From ea87084d6b649e6d90fdaa4aa4d51f08758e042b Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 27 May 2019 11:38:22 +0200 Subject: [PATCH 001/457] Add validation on bulk_update --- substrabac/substrapp/views/datasample.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 4b8cab446..6033e845a 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -305,11 +305,24 @@ def create(self, request, *args, **kwargs): def bulk_update(self, request): data = request.data - data_manager_keys = data.getlist('data_manager_keys') - data_keys = data.getlist('data_sample_keys') + + # validation + # TODO place in another method + try: + data_manager_keys = data.getlist('data_manager_keys', []) + except: + return Response({'message': 'Please pass a valid data_manager_keys key param'}, status=status.HTTP_400_BAD_REQUEST) + + try: + data_sample_keys = data.getlist('data_sample_keys', []) + except: + return Response({'message': 'Please pass a valid data_sample_keys key param'}, status=status.HTTP_400_BAD_REQUEST) + + if not len(data_sample_keys) or not len(','.join(data_sample_keys)): + return Response({'message': 'Please pass a non empty data_sample_keys key param'}, status=status.HTTP_400_BAD_REQUEST) args = '"%(hashes)s", "%(dataManagerKeys)s"' % { - 'hashes': ','.join(data_keys), + 'hashes': ','.join(data_sample_keys), 'dataManagerKeys': ','.join(data_manager_keys), } From e9650c98f142ea1e27c26346d4a061193ef67577 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 27 May 2019 12:04:23 +0200 Subject: [PATCH 002/457] Add data_manager_keys non empty validation --- substrabac/substrapp/views/datasample.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 6033e845a..a98efe0df 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -321,6 +321,9 @@ def bulk_update(self, request): if not len(data_sample_keys) or not len(','.join(data_sample_keys)): return Response({'message': 'Please pass a non empty data_sample_keys key param'}, status=status.HTTP_400_BAD_REQUEST) + if not len(data_manager_keys) or not len(','.join(data_manager_keys)): + return Response({'message': 'Please pass a non empty data_manager_keys key param'}, status=status.HTTP_400_BAD_REQUEST) + args = '"%(hashes)s", "%(dataManagerKeys)s"' % { 'hashes': ','.join(data_sample_keys), 'dataManagerKeys': ','.join(data_manager_keys), From b0aeae4ac05cbc46de3aeb695282d66a6146ffcf Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 27 May 2019 12:14:01 +0200 Subject: [PATCH 003/457] refacto --- substrabac/substrapp/views/datasample.py | 64 ++++++++++++------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index a98efe0df..ac693edc8 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -301,46 +301,48 @@ def create(self, request, *args, **kwargs): headers = self.get_success_headers(data) return Response(data, status=st, headers=headers) - @action(methods=['post'], detail=False) - def bulk_update(self, request): - - data = request.data - + def validate_bulk_update(self, data): # validation - # TODO place in another method try: data_manager_keys = data.getlist('data_manager_keys', []) except: - return Response({'message': 'Please pass a valid data_manager_keys key param'}, status=status.HTTP_400_BAD_REQUEST) + raise Exception('Please pass a valid data_manager_keys key param') + else: + data_manager_keys = ','.join(data_manager_keys) + if data_manager_keys: + raise Exception('Please pass a non empty data_manager_keys key param') try: data_sample_keys = data.getlist('data_sample_keys', []) except: - return Response({'message': 'Please pass a valid data_sample_keys key param'}, status=status.HTTP_400_BAD_REQUEST) - - if not len(data_sample_keys) or not len(','.join(data_sample_keys)): - return Response({'message': 'Please pass a non empty data_sample_keys key param'}, status=status.HTTP_400_BAD_REQUEST) + raise Exception('Please pass a valid data_sample_keys key param') + else: + data_sample_keys = ','.join(data_sample_keys) + if data_sample_keys: + raise Exception('Please pass a non empty data_sample_keys key param') - if not len(data_manager_keys) or not len(','.join(data_manager_keys)): - return Response({'message': 'Please pass a non empty data_manager_keys key param'}, status=status.HTTP_400_BAD_REQUEST) + @action(methods=['post'], detail=False) + def bulk_update(self, request): - args = '"%(hashes)s", "%(dataManagerKeys)s"' % { - 'hashes': ','.join(data_sample_keys), - 'dataManagerKeys': ','.join(data_manager_keys), - } + try: + data_manager_keys, data_sample_keys = self.validate_bulk_update(request.data) + except Exception as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + else: + args = f'"{data_sample_keys}", "{data_manager_keys}"' - if getattr(settings, 'LEDGER_SYNC_ENABLED'): - data, st = updateLedgerDataSample(args, sync=True) + if getattr(settings, 'LEDGER_SYNC_ENABLED'): + data, st = updateLedgerDataSample(args, sync=True) - # patch status for update - if st == status.HTTP_201_CREATED: - st = status.HTTP_200_OK - return Response(data, status=st) - else: - # use a celery task, as we are in an http request transaction - updateLedgerDataSampleAsync.delay(args) - data = { - 'message': 'The substra network has been notified for updating these Data' - } - st = status.HTTP_202_ACCEPTED - return Response(data, status=st) + # patch status for update + if st == status.HTTP_201_CREATED: + st = status.HTTP_200_OK + return Response(data, status=st) + else: + # use a celery task, as we are in an http request transaction + updateLedgerDataSampleAsync.delay(args) + data = { + 'message': 'The substra network has been notified for updating these Data' + } + st = status.HTTP_202_ACCEPTED + return Response(data, status=st) From 35a4e0e40f6a75775c4d5116ce602c2a4f6479e8 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 27 May 2019 14:29:44 +0200 Subject: [PATCH 004/457] fix --- substrabac/substrapp/views/datasample.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index ac693edc8..7fb900c0e 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -309,7 +309,7 @@ def validate_bulk_update(self, data): raise Exception('Please pass a valid data_manager_keys key param') else: data_manager_keys = ','.join(data_manager_keys) - if data_manager_keys: + if not data_manager_keys: raise Exception('Please pass a non empty data_manager_keys key param') try: @@ -318,9 +318,11 @@ def validate_bulk_update(self, data): raise Exception('Please pass a valid data_sample_keys key param') else: data_sample_keys = ','.join(data_sample_keys) - if data_sample_keys: + if not data_sample_keys: raise Exception('Please pass a non empty data_sample_keys key param') + return data_manager_keys, data_sample_keys + @action(methods=['post'], detail=False) def bulk_update(self, request): From 13ff6d4fc96b51c27278741dda0807c30d3ad772 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 20 Mar 2019 16:24:27 +0100 Subject: [PATCH 005/457] Query ledger with fabric-py-sdk --- substrabac/requirements.txt | 1 + substrabac/substrapp/tasks.py | 7 ++- substrabac/substrapp/utils.py | 72 +++++++++++++++-------- substrabac/substrapp/views/algo.py | 9 +-- substrabac/substrapp/views/datamanager.py | 17 ++---- substrabac/substrapp/views/model.py | 20 ++----- substrabac/substrapp/views/objective.py | 13 +--- substrabac/substrapp/views/testtuple.py | 4 +- substrabac/substrapp/views/traintuple.py | 8 +-- substrabac/substrapp/views/utils.py | 4 +- 10 files changed, 70 insertions(+), 85 deletions(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index 53fd65156..98e6ebb4e 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,3 +26,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 +git+https://github.com/hyperledger/fabric-sdk-py.git@865252e51079a4579fd2ea18b822c9796f480399 diff --git a/substrabac/substrapp/tasks.py b/substrabac/substrapp/tasks.py index da89344b3..fe46583cf 100644 --- a/substrabac/substrapp/tasks.py +++ b/substrabac/substrapp/tasks.py @@ -225,9 +225,10 @@ def prepareTask(tuple_type, model_type): except Exception as e: logging.error(e, exc_info=True) else: - subtuples, st = queryLedger({ - 'args': f'{{"Args":["queryFilter","{tuple_type}~worker~status","{data_owner},todo"]}}' - }) + + subtuples, st = queryLedger(fcn="queryFilter", + args=[f'{tuple_type}~worker~status', + f'{data_owner},todo']) if st == status.HTTP_200_OK and subtuples is not None: for subtuple in subtuples: diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 5f48345bd..73782a1e8 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -1,6 +1,7 @@ import io import hashlib import json +import glob import logging import os import tempfile @@ -19,6 +20,11 @@ LEDGER = getattr(settings, 'LEDGER', None) +from hfc.fabric import Client +from hfc.fabric.peer import create_peer +from hfc.fabric.user import create_user +from hfc.util.keyvaluestore import FileKeyValueStore + def clean_env_variables(): os.environ.pop('FABRIC_CFG_PATH', None) @@ -32,49 +38,67 @@ def clean_env_variables(): # careful, passing invoke parameters to queryLedger will NOT fail -def queryLedger(options): - args = options['args'] +def queryLedger(fcn, args=None): + + if args is None: + args = [] channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] - core_peer_mspconfigpath = LEDGER['core_peer_mspconfigpath'] + chaincode_version = LEDGER['chaincode_version'] peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + requestor_config = LEDGER['client'] + + client = Client() + client.new_channel(channel_name) + + requestor = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + target_peer = create_peer(endpoint=f'{peer["host"]}:{peer_port}', + tls_cacerts=peer['tlsCACerts'], + client_key=peer['clientKey'], + client_cert=peer['clientCert'], + opts=[(k, v) for k, v in peer['grpcOptions'].items()]) + + client._peers[peer['name']] = target_peer + + response = client.chaincode_query( + requestor=requestor, + channel_name=channel_name, + peer_names=[peer['name']], + args=args, + cc_name=chaincode_name, + cc_version=chaincode_version, + fcn=fcn) - # update config path for using right core.yaml and override msp config path - os.environ['FABRIC_CFG_PATH'] = os.environ.get('FABRIC_CFG_PATH_ENV', peer['docker_core_dir']) - os.environ['CORE_PEER_MSPCONFIGPATH'] = os.environ.get('CORE_PEER_MSPCONFIGPATH_ENV', core_peer_mspconfigpath) - os.environ['CORE_PEER_ADDRESS'] = os.environ.get('CORE_PEER_ADDRESS_ENV', f'{peer["host"]}:{peer_port}') + st = status.HTTP_200_OK - print(f'Querying chaincode in the channel \'{channel_name}\' on the peer \'{peer["host"]}\' ...', flush=True) + data = response - output = subprocess.run([os.path.join(PROJECT_ROOT, '../bin/peer'), - 'chaincode', 'query', - '-x', - '-C', channel_name, - '-n', chaincode_name, - '-c', args], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py - st = status.HTTP_200_OK - data = output.stdout.decode('utf-8') if data: # json transformation if needed try: - data = json.loads(bytes.fromhex(data.rstrip()).decode('utf-8')) + data = json.loads(response) except: - logging.error('Failed to json parse hexadecimal response in query') + logging.error('Failed to json parse response in query') msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' print(msg, flush=True) else: try: - msg = output.stderr.decode('utf-8').split('Error')[-1].split('\n')[0] + msg = response.split('Error')[-1].split('\n')[0] data = {'message': msg} except: - msg = output.stderr.decode('utf-8') + msg = response data = {'message': msg} finally: st = status.HTTP_400_BAD_REQUEST @@ -83,8 +107,6 @@ def queryLedger(options): elif 'no element with key' in msg: st = status.HTTP_404_NOT_FOUND - clean_env_variables() - return data, st diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index bad64fffe..2e94f794d 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -161,10 +161,7 @@ def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): # can modify result by interrogating `request.version` - data, st = queryLedger({ - 'args': '{"Args":["queryAlgos"]}' - }) - + data, st = queryLedger(fcn='queryAlgos', args=[]) modelData = None # init list to return @@ -197,9 +194,7 @@ def list(self, request, *args, **kwargs): elif k == 'model': # select objectives used by outModel hash if not modelData: # TODO find a way to put this call in cache - modelData, st = queryLedger({ - 'args': '{"Args":["queryTraintuples"]}' - }) + modelData, st = queryLedger(fcn='queryTraintuples', args=[]) if st != status.HTTP_200_OK: return Response(modelData, status=st) if modelData is None: diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 783697216..af83d79f8 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -173,9 +173,7 @@ def create_or_update_datamanager(self, instance, datamanager, pk): def getObjectFromLedger(self, pk): # get instance from remote node - data, st = queryLedger({ - 'args': f'{{"Args":["queryDataset", "{pk}"]}}' - }) + data, st = queryLedger(fcn='queryDataset', args=[f'{pk}']) if st == status.HTTP_404_NOT_FOUND: raise Http404('Not found') @@ -241,11 +239,8 @@ def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): # can modify result by interrogating `request.version` - data, st = queryLedger({ - 'args': '{"Args":["queryDataManagers"]}' - }) + data, st = queryLedger(fcn='queryDataManagers', args=[]) objectiveData = None - algoData = None modelData = None # init list to return @@ -278,9 +273,7 @@ def list(self, request, *args, **kwargs): elif k == 'objective': # select objective used by these datamanagers if not objectiveData: # TODO find a way to put this call in cache - objectiveData, st = queryLedger({ - 'args': '{"Args":["queryObjectives"]}' - }) + objectiveData, st = queryLedger(fcn='queryObjectives', args=[]) if st != status.HTTP_200_OK: return Response(objectiveData, status=st) if objectiveData is None: @@ -296,9 +289,7 @@ def list(self, request, *args, **kwargs): elif k == 'model': # select objectives used by outModel hash if not modelData: # TODO find a way to put this call in cache - modelData, st = queryLedger({ - 'args': '{"Args":["queryTraintuples"]}' - }) + modelData, st = queryLedger(fcn='queryTraintuples', args=[]) if st != status.HTTP_200_OK: return Response(modelData, status=st) if modelData is None: diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 34a541eb3..c567acade 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -116,9 +116,7 @@ def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): # can modify result by interrogating `request.version` - data, st = queryLedger({ - 'args': '{"Args":["queryModels"]}' - }) + data, st = queryLedger(fcn='queryModels', args=[]) algoData = None objectiveData = None dataManagerData = None @@ -154,9 +152,7 @@ def list(self, request, *args, **kwargs): elif k == 'algo': # select model used by these algo if not algoData: # TODO find a way to put this call in cache - algoData, st = queryLedger({ - 'args': '{"Args":["queryAlgos"]}' - }) + algoData, st = queryLedger(fcn='queryAlgos', args=[]) if st != status.HTTP_200_OK: return Response(algoData, status=st) @@ -169,9 +165,7 @@ def list(self, request, *args, **kwargs): elif k == 'dataset': # select model which trainData.openerHash is if not dataManagerData: # TODO find a way to put this call in cache - dataManagerData, st = queryLedger({ - 'args': '{"Args":["queryDataManagers"]}' - }) + dataManagerData, st = queryLedger(fcn='queryDataManagers', args=[]) if st != status.HTTP_200_OK: return Response(dataManagerData, status=st) @@ -184,9 +178,7 @@ def list(self, request, *args, **kwargs): elif k == 'objective': # select objective used by these datamanagers if not objectiveData: # TODO find a way to put this call in cache - objectiveData, st = queryLedger({ - 'args': '{"Args":["queryObjectives"]}' - }) + objectiveData, st = queryLedger(fcn='queryObjectives', args=[]) if st != status.HTTP_200_OK: return Response(objectiveData, status=st) @@ -216,8 +208,6 @@ def details(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - data, st = queryLedger({ - 'args': f'{{"Args":["queryModelDetails", "{pk}"]}}' - }) + data, st = queryLedger(fcn='queryModelDetails', args=[f'{pk}']) return Response(data, st) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 345267fc9..0a963ce1d 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -287,9 +287,7 @@ def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): # can modify result by interrogating `request.version` - data, st = queryLedger({ - 'args': '{"Args":["queryObjectives"]}' - }) + data, st = queryLedger(fcn='queryObjectives', args=[]) data = [] if data is None else data objectives = [data] @@ -298,7 +296,6 @@ def list(self, request, *args, **kwargs): return Response(objectives, status=st) dataManagerData = None - algoData = None modelData = None # parse filters @@ -330,9 +327,7 @@ def list(self, request, *args, **kwargs): elif k == 'dataset': # select objective used by these datamanagers if not dataManagerData: # TODO find a way to put this call in cache - dataManagerData, st = queryLedger({ - 'args': '{"Args":["queryDataManagers"]}' - }) + dataManagerData, st = queryLedger(fcn='queryDataManagers', args=[]) if st != status.HTTP_200_OK: return Response(dataManagerData, status=st) if dataManagerData is None: @@ -348,9 +343,7 @@ def list(self, request, *args, **kwargs): elif k == 'model': # select objectives used by outModel hash if not modelData: # TODO find a way to put this call in cache - modelData, st = queryLedger({ - 'args': '{"Args":["queryTraintuples"]}' - }) + modelData, st = queryLedger(fcn='queryTraintuples', args=[]) if st != status.HTTP_200_OK: return Response(modelData, status=st) if modelData is None: diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index ae25f0f0f..69acd6a17 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -112,9 +112,7 @@ def create(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): # can modify result by interrogating `request.version` - data, st = queryLedger({ - 'args': '{"Args":["queryTesttuples"]}' - }) + data, st = queryLedger(fcn='queryTesttuples', args=[]) data = data if data else [] diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 2ad5d213d..69ed77efb 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -122,9 +122,7 @@ def create(self, request, *args, **kwargs): return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): - data, st = queryLedger({ - 'args': '{"Args":["queryTraintuples"]}' - }) + data, st = queryLedger(fcn='queryTraintuples', args=[]) data = data if data else [] @@ -132,9 +130,7 @@ def list(self, request, *args, **kwargs): def getObjectFromLedger(self, pk): # get instance from remote node - data, st = queryLedger({ - 'args': f'{{"Args":["queryTraintuple","{pk}"]}}' - }) + data, st = queryLedger(fcn='queryTraintuple', args=[f'{pk}']) if st == status.HTTP_404_NOT_FOUND: raise Http404('Not found') diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 182058283..62ff2876d 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -56,9 +56,7 @@ def get_filters(query_params): def getObjectFromLedger(pk, query): # get instance from remote node - data, st = queryLedger({ - 'args': f'{{"Args":["{query}","{pk}"]}}' - }) + data, st = queryLedger(fcn='query', args=[f'{pk}']) if st == status.HTTP_404_NOT_FOUND: raise Http404('Not found') From 70ffb3e24a6a4c58a94a7d9038bb67c122c596db Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 20 Mar 2019 18:38:20 +0100 Subject: [PATCH 006/457] Invoke ledger with fabric-py-sdk --- .../serializers/ledger/algo/serializer.py | 23 ++- .../substrapp/serializers/ledger/algo/util.py | 5 +- .../ledger/datamanager/serializer.py | 31 ++-- .../serializers/ledger/datamanager/util.py | 12 +- .../ledger/datasample/serializer.py | 16 +- .../serializers/ledger/datasample/util.py | 11 +- .../ledger/objective/serializer.py | 31 ++-- .../serializers/ledger/objective/util.py | 5 +- .../ledger/testtuple/serializer.py | 20 ++- .../serializers/ledger/testtuple/util.py | 5 +- .../ledger/traintuple/serializer.py | 31 ++-- .../serializers/ledger/traintuple/util.py | 5 +- substrabac/substrapp/tasks.py | 28 ++-- substrabac/substrapp/utils.py | 152 +++++++++--------- substrabac/substrapp/views/datamanager.py | 10 +- substrabac/substrapp/views/datasample.py | 11 +- 16 files changed, 225 insertions(+), 171 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/algo/serializer.py b/substrabac/substrapp/serializers/ledger/algo/serializer.py index e6d53ed1c..1d3ad8962 100644 --- a/substrabac/substrapp/serializers/ledger/algo/serializer.py +++ b/substrabac/substrapp/serializers/ledger/algo/serializer.py @@ -23,14 +23,21 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = '' if request is None else request.get_host() - args = '"%(name)s", "%(algoHash)s", "%(storageAddress)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(permissions)s"' % { - 'name': name, - 'algoHash': get_hash(instance.file), - 'storageAddress': protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), - 'descriptionHash': get_hash(instance.description), - 'descriptionStorageAddress': protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), - 'permissions': permissions - } + # args = '"%(name)s", "%(algoHash)s", "%(storageAddress)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(permissions)s"' % { + # 'name': name, + # 'algoHash': get_hash(instance.file), + # 'storageAddress': protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), + # 'descriptionHash': get_hash(instance.description), + # 'descriptionStorageAddress': protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), + # 'permissions': permissions + # } + + args = [name, + get_hash(instance.file), + protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), + get_hash(instance.description), + protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), + permissions] if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerAlgo(args, instance.pkhash, sync=True) diff --git a/substrabac/substrapp/serializers/ledger/algo/util.py b/substrabac/substrapp/serializers/ledger/algo/util.py index 3dbd13981..486f86343 100644 --- a/substrabac/substrapp/serializers/ledger/algo/util.py +++ b/substrabac/substrapp/serializers/ledger/algo/util.py @@ -7,10 +7,7 @@ def createLedgerAlgo(args, pkhash, sync=False): - options = { - 'args': '{"Args":["registerAlgo", ' + args + ']}' - } - data, st = invokeLedger(options, sync) + data, st = invokeLedger(fcn='registerAlgo', args=args, sync=sync) # if not created on ledger, delete from local db, else pass to validated true try: diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py index 334365bf5..9d7417f87 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py @@ -27,16 +27,27 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = '' if request is None else request.get_host() - args = '"%(name)s", "%(openerHash)s", "%(openerStorageAddress)s", "%(type)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(objectiveKey)s", "%(permissions)s"' % { - 'name': name, - 'openerHash': get_hash(instance.data_opener), - 'openerStorageAddress': protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), - 'type': type, - 'descriptionHash': get_hash(instance.description), - 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), - 'objectiveKey': objective_key, - 'permissions': permissions - } + # args = '"%(name)s", "%(openerHash)s", "%(openerStorageAddress)s", "%(type)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(objectiveKey)s", "%(permissions)s"' % { + # 'name': name, + # 'openerHash': get_hash(instance.data_opener), + # 'openerStorageAddress': protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), + # 'type': type, + # 'descriptionHash': get_hash(instance.description), + # 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), + # 'objectiveKey': objective_key, + # 'permissions': permissions + # } + + args = [ + name, + get_hash(instance.data_opener), + protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), + type, + get_hash(instance.description), + protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), + objective_key, + permissions + ] if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerDataManager(args, instance.pkhash, sync=True) diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substrabac/substrapp/serializers/ledger/datamanager/util.py index 8469fe460..a607cbaed 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/util.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/util.py @@ -6,10 +6,8 @@ def createLedgerDataManager(args, pkhash, sync=False): - options = { - 'args': '{"Args":["registerDataManager", ' + args + ']}' - } - data, st = invokeLedger(options, sync) + + data, st = invokeLedger(fcn='registerDataManager', args=args, sync=sync) # if not created on ledger, delete from local db, else pass to validated true try: @@ -30,9 +28,7 @@ def createLedgerDataManager(args, pkhash, sync=False): def updateLedgerDataManager(args, sync=False): - options = { - 'args': '{"Args":["updateDataManager", ' + args + ']}' - } - data, st = invokeLedger(options, sync) + + data, st = invokeLedger(fcn='updateDataManager', args=args, sync=sync) return data, st diff --git a/substrabac/substrapp/serializers/ledger/datasample/serializer.py b/substrabac/substrapp/serializers/ledger/datasample/serializer.py index 8171ead95..23fb6c56b 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datasample/serializer.py @@ -18,11 +18,17 @@ def create(self, validated_data): data_manager_keys = validated_data.get('data_manager_keys') test_only = validated_data.get('test_only') - args = '"%(hashes)s", "%(dataManagerKeys)s", "%(testOnly)s"' % { - 'hashes': ','.join([x.pk for x in instances]), - 'dataManagerKeys': ','.join([x for x in data_manager_keys]), - 'testOnly': json.dumps(test_only), - } + # args = '"%(hashes)s", "%(dataManagerKeys)s", "%(testOnly)s"' % { + # 'hashes': ','.join([x.pk for x in instances]), + # 'dataManagerKeys': ','.join([x for x in data_manager_keys]), + # 'testOnly': json.dumps(test_only), + # } + + args = [ + ','.join([x.pk for x in instances]), + ','.join([x for x in data_manager_keys]), + json.dumps(test_only), + ] if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerDataSample(args, [x.pk for x in instances], sync=True) diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substrabac/substrapp/serializers/ledger/datasample/util.py index 15eacd800..1d6a776f4 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/util.py +++ b/substrabac/substrapp/serializers/ledger/datasample/util.py @@ -6,10 +6,7 @@ def createLedgerDataSample(args, pkhashes, sync=False): - options = { - 'args': '{"Args":["registerDataSample", ' + args + ']}' - } - data, st = invokeLedger(options, sync) + data, st = invokeLedger(fcn='registerDataSample', args=args, sync=sync) # if not created on ledger, delete from local db, else pass to validated true try: @@ -32,9 +29,5 @@ def createLedgerDataSample(args, pkhashes, sync=False): def updateLedgerDataSample(args, sync=False): - options = { - 'args': '{"Args":["updateDataSample", ' + args + ']}' - } - data, st = invokeLedger(options, sync) - + data, st = invokeLedger(fcn='updateDataSample', args=args, sync=sync) return data, st diff --git a/substrabac/substrapp/serializers/ledger/objective/serializer.py b/substrabac/substrapp/serializers/ledger/objective/serializer.py index 372c336c1..02cbd6eba 100644 --- a/substrabac/substrapp/serializers/ledger/objective/serializer.py +++ b/substrabac/substrapp/serializers/ledger/objective/serializer.py @@ -31,16 +31,27 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = '' if request is None else request.get_host() - args = '"%(name)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(metricsName)s", "%(metricsHash)s", "%(metricsStorageAddress)s", "%(testDataSample)s", "%(permissions)s"' % { - 'name': name, - 'descriptionHash': get_hash(instance.description), - 'descriptionStorageAddress': protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), - 'metricsName': metrics_name, - 'metricsHash': get_hash(instance.metrics), - 'metricsStorageAddress': protocol + host + reverse('substrapp:objective-metrics', args=[instance.pk]), - 'testDataSample': f'{test_data_manager_key}:{",".join([x for x in test_data_sample_keys])}', - 'permissions': permissions - } + # args = '"%(name)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(metricsName)s", "%(metricsHash)s", "%(metricsStorageAddress)s", "%(testDataSample)s", "%(permissions)s"' % { + # 'name': name, + # 'descriptionHash': get_hash(instance.description), + # 'descriptionStorageAddress': protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), + # 'metricsName': metrics_name, + # 'metricsHash': get_hash(instance.metrics), + # 'metricsStorageAddress': protocol + host + reverse('substrapp:objective-metrics', args=[instance.pk]), + # 'testDataSample': f'{test_data_manager_key}:{",".join([x for x in test_data_sample_keys])}', + # 'permissions': permissions + # } + + args = [ + name, + get_hash(instance.description), + protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), + metrics_name, + get_hash(instance.metrics), + protocol + host + reverse('substrapp:objective-metrics', args=[instance.pk]), + f'{test_data_manager_key}:{",".join([x for x in test_data_sample_keys])}', + permissions + ] if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerObjective(args, instance.pkhash, sync=True) diff --git a/substrabac/substrapp/serializers/ledger/objective/util.py b/substrabac/substrapp/serializers/ledger/objective/util.py index 8b9693bb4..e7a1111e4 100644 --- a/substrabac/substrapp/serializers/ledger/objective/util.py +++ b/substrabac/substrapp/serializers/ledger/objective/util.py @@ -7,10 +7,7 @@ def createLedgerObjective(args, pkhash, sync=False): - options = { - 'args': '{"Args":["registerObjective", ' + args + ']}' - } - data, st = invokeLedger(options, sync) + data, st = invokeLedger(fcn='registerObjective', args=args, sync=sync) # if not created on ledger, delete from local db, else pass to validated true try: diff --git a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py index c9f5ccbad..56e94e7d3 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py @@ -20,12 +20,20 @@ def get_args(self, validated_data): test_data_sample_keys = validated_data.get('test_data_sample_keys', []) tag = validated_data.get('tag', '') - args = '"%(traintupleKey)s", "%(dataManagerKey)s", "%(dataSampleKeys)s", "%(tag)s"' % { - 'traintupleKey': traintuple_key, - 'dataManagerKey': data_manager_key, - 'dataSampleKeys': ','.join(test_data_sample_keys), - 'tag': tag - } + # args = '"%(traintupleKey)s", "%(dataManagerKey)s", "%(dataSampleKeys)s", "%(tag)s"' % { + # 'traintupleKey': traintuple_key, + # 'dataManagerKey': data_manager_key, + # 'dataSampleKeys': ','.join(test_data_sample_keys), + # 'tag': tag + # } + + args = [ + traintuple_key, + data_manager_key, + ','.join([x for x in test_data_sample_keys]), + tag + ] + return args def create(self, validated_data): diff --git a/substrabac/substrapp/serializers/ledger/testtuple/util.py b/substrabac/substrapp/serializers/ledger/testtuple/util.py index b02ccfb0e..d94056c33 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/util.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/util.py @@ -5,7 +5,4 @@ def createLedgerTesttuple(args, sync=False): - options = { - 'args': '{"Args":["createTesttuple", ' + args + ']}' - } - return invokeLedger(options, sync) + return invokeLedger(fcn='createTesttuple', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index 970a67ba8..10322c737 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -30,16 +30,27 @@ def get_args(self, validated_data): in_models_keys = validated_data.get('in_models_keys') tag = validated_data.get('tag', '') - args = '"%(algoKey)s", "%(associatedObjective)s", "%(inModels)s", "%(dataManagerKey)s", "%(dataSampleKeys)s", "%(FLtask)s", "%(rank)s", "%(tag)s"' % { - 'algoKey': algo_key, - 'associatedObjective': objective_key, - 'inModels': ','.join(in_models_keys), - 'dataManagerKey': data_manager_key, - 'dataSampleKeys': ','.join(train_data_sample_keys), - 'FLtask': FLtask_key, - 'rank': rank, - 'tag': tag - } + # args = '"%(algoKey)s", "%(associatedObjective)s", "%(inModels)s", "%(dataManagerKey)s", "%(dataSampleKeys)s", "%(FLtask)s", "%(rank)s", "%(tag)s"' % { + # 'algoKey': algo_key, + # 'associatedObjective': objective_key, + # 'inModels': ','.join(in_models_keys), + # 'dataManagerKey': data_manager_key, + # 'dataSampleKeys': ','.join(train_data_sample_keys), + # 'FLtask': FLtask_key, + # 'rank': rank, + # 'tag': tag + # } + + args = [ + algo_key, + objective_key, + ','.join([x for x in in_models_keys]), + data_manager_key, + ','.join([x for x in train_data_sample_keys]), + FLtask_key, + rank, + tag, + ] return args diff --git a/substrabac/substrapp/serializers/ledger/traintuple/util.py b/substrabac/substrapp/serializers/ledger/traintuple/util.py index 8ca26f4b8..be771ee07 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/util.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/util.py @@ -5,7 +5,4 @@ def createLedgerTraintuple(args, sync=False): - options = { - 'args': '{"Args":["createTraintuple", ' + args + ']}' - } - return invokeLedger(options, sync) + return invokeLedger(fcn='createTraintuple', args=args, sync=sync) diff --git a/substrabac/substrapp/tasks.py b/substrabac/substrapp/tasks.py index fe46583cf..7b2eca1b1 100644 --- a/substrabac/substrapp/tasks.py +++ b/substrabac/substrapp/tasks.py @@ -199,9 +199,9 @@ def fail(key, err_msg, tuple_type): # Log Fail TrainTest err_msg = str(err_msg).replace('"', "'").replace('\\', "").replace('\\n', "")[:200] fail_type = 'logFailTrain' if tuple_type == 'traintuple' else 'logFailTest' - data, st = invokeLedger({ - 'args': f'{{"Args":["{fail_type}","{key}","{err_msg}"]}}' - }, sync=True) + data, st = invokeLedger(fcn=fail_type, + args=[f'{key}', f'{err_msg}'], + sync=True) if st is not status.HTTP_201_CREATED: logging.error(data, exc_info=True) @@ -248,9 +248,9 @@ def prepareTask(tuple_type, model_type): try: # Log Start of the Subtuple start_type = 'logStartTrain' if tuple_type == 'traintuple' else 'logStartTest' if tuple_type == 'testtuple' else None - data, st = invokeLedger({ - 'args': f'{{"Args":["{start_type}","{subtuple["key"]}"]}}' - }, sync=True) + data, st = invokeLedger(fcn=start_type, + args=[f'{subtuple["key"]}'], + sync=True) if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): logging.error( @@ -309,13 +309,19 @@ def computeTask(self, tuple_type, subtuple, model_type, fltask): else: # Invoke ledger to log success if tuple_type == 'traintuple': - invoke_args = f'{{"Args":["logSuccessTrain","{subtuple["key"]}", "{res["end_model_file_hash"]}, {res["end_model_file"]}","{res["global_perf"]}","Train - {res["job_task_log"]}; "]}}' + invoke_fcn = 'logSuccessTrain' + invoke_args = [f'{subtuple["key"]}', + f'{res["end_model_file_hash"]}, {res["end_model_file"]}', + f'{res["global_perf"]}', + f'Train - {res["job_task_log"]};'] + elif tuple_type == 'testtuple': - invoke_args = f'{{"Args":["logSuccessTest","{subtuple["key"]}","{res["global_perf"]}","Test - {res["job_task_log"]}; "]}}' + invoke_fcn = 'logSuccessTest' + invoke_args = [f'{subtuple["key"]}', + f'{res["global_perf"]}', + f'Test - {res["job_task_log"]};'] - data, st = invokeLedger({ - 'args': invoke_args - }, sync=True) + data, st = invokeLedger(fcn=invoke_fcn, args=invoke_args, sync=True) if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): logging.error('Failed to invoke ledger on logSuccess') diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 73782a1e8..577d0c47f 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -8,21 +8,20 @@ from os.path import isfile, isdir import requests -import subprocess import tarfile import zipfile from checksumdir import dirhash from rest_framework import status -from substrabac.settings.common import PROJECT_ROOT from django.conf import settings LEDGER = getattr(settings, 'LEDGER', None) from hfc.fabric import Client -from hfc.fabric.peer import create_peer +from hfc.fabric.peer import Peer from hfc.fabric.user import create_user +from hfc.fabric.orderer import Orderer from hfc.util.keyvaluestore import FileKeyValueStore @@ -60,12 +59,13 @@ def queryLedger(fcn, args=None): key_path=glob.glob(requestor_config['key_path'])[0], cert_path=requestor_config['cert_path']) - target_peer = create_peer(endpoint=f'{peer["host"]}:{peer_port}', - tls_cacerts=peer['tlsCACerts'], - client_key=peer['clientKey'], - client_cert=peer['clientCert'], - opts=[(k, v) for k, v in peer['grpcOptions'].items()]) - + target_peer = Peer(name=peer['name']) + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) client._peers[peer['name']] = target_peer response = client.chaincode_query( @@ -84,16 +84,15 @@ def queryLedger(fcn, args=None): # TO DO : review parsing error in case of failure # May have changed by using fabric-sdk-py - if data: + try: # json transformation if needed - try: - data = json.loads(response) - except: - logging.error('Failed to json parse response in query') + data = json.loads(response) + except: + logging.error('Failed to json parse response in query') msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' print(msg, flush=True) - else: + try: msg = response.split('Error')[-1].split('\n')[0] data = {'message': msg} @@ -110,74 +109,83 @@ def queryLedger(fcn, args=None): return data, st -def invokeLedger(options, sync=False): - args = options['args'] +def invokeLedger(fcn, args=None, sync=False): + + if args is None: + args = [] channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] - core_peer_mspconfigpath = LEDGER['core_peer_mspconfigpath'] + chaincode_version = LEDGER['chaincode_version'] peer = LEDGER['peer'] peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] orderer = LEDGER['orderer'] - orderer_ca_file = orderer['ca'] - peer_key_file = peer['clientKey'] - peer_cert_file = peer['clientCert'] - - # update config path for using right core.yaml and override msp config path - os.environ['FABRIC_CFG_PATH'] = os.environ.get('FABRIC_CFG_PATH_ENV', peer['docker_core_dir']) - os.environ['CORE_PEER_MSPCONFIGPATH'] = os.environ.get('CORE_PEER_MSPCONFIGPATH_ENV', core_peer_mspconfigpath) - os.environ['CORE_PEER_ADDRESS'] = os.environ.get('CORE_PEER_ADDRESS_ENV', f'{peer["host"]}:{peer_port}') - - print(f'Sending invoke transaction to {peer["host"]} ...', flush=True) - - cmd = [os.path.join(PROJECT_ROOT, '../bin/peer'), - 'chaincode', 'invoke', - '-C', channel_name, - '-n', chaincode_name, - '-c', args, - '-o', f'{orderer["host"]}:{orderer["port"]}', - '--cafile', orderer_ca_file, - '--tls', - '--clientauth', - '--keyfile', peer_key_file, - '--certfile', peer_cert_file] - - if sync: - cmd += ['--waitForEvent', '--waitForEventTimeout', '45s'] - - output = subprocess.run(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - st = status.HTTP_201_CREATED - data = output.stdout.decode('utf-8') + requestor_config = LEDGER['client'] - if not data: - msg = output.stderr.decode('utf-8') - data = {'message': msg} + client = Client() + client.new_channel(channel_name) - if 'Error' in msg or 'ERRO' in msg: - # https://github.com/hyperledger/fabric/blob/eca1b14b7e3453a5d32296af79cc7bad10c7673b/peer/chaincode/common.go - if "timed out waiting for txid on all peers" in msg or "failed to receive txid on all peers" in msg: - st = status.HTTP_408_REQUEST_TIMEOUT - else: - st = status.HTTP_400_BAD_REQUEST - elif 'access denied' in msg or 'authentication handshake failed' in msg: - st = status.HTTP_403_FORBIDDEN - elif 'Chaincode invoke successful' in msg: - st = status.HTTP_201_CREATED - try: - msg = msg.split('result: status:')[1].split('\n')[0].split('payload:')[1].strip().strip('"') - except: - pass - else: - msg = json.loads(msg.encode('utf-8').decode('unicode_escape')) - msg = msg.get('key', msg.get('keys')) # get pkhash - finally: - data = {'pkhash': msg} + requestor = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + target_peer = Peer(name=peer['name']) + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + client._peers[peer['name']] = target_peer + + target_orderer = Orderer(name=orderer['name']) + target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', + 'grpcOptions': orderer['grpcOptions'], + 'tlsCACerts': {'path': orderer['ca']}, + 'clientKey': {'path': orderer['clientKey']}, + 'clientCert': {'path': orderer['clientCert']}, + }) + client._orderers[orderer['name']] = target_orderer + + response = client.chaincode_invoke( + requestor=requestor, + channel_name=channel_name, + peer_names=[peer['name']], + args=args, + cc_name=chaincode_name, + cc_version=chaincode_version, + fcn=fcn, + wait_for_event=sync, + wait_for_event_timeout=45) - clean_env_variables() + st = status.HTTP_201_CREATED + + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py + msg = response + data = {'message': msg} + + if 'Error' in msg or 'ERRO' in msg: + # https://github.com/hyperledger/fabric/blob/eca1b14b7e3453a5d32296af79cc7bad10c7673b/peer/chaincode/common.go + if "timed out waiting for txid on all peers" in msg or "failed to receive txid on all peers" in msg: + st = status.HTTP_408_REQUEST_TIMEOUT + else: + st = status.HTTP_400_BAD_REQUEST + elif 'access denied' in msg or 'authentication handshake failed' in msg: + st = status.HTTP_403_FORBIDDEN + elif 'Chaincode invoke successful' in msg: + st = status.HTTP_201_CREATED + try: + msg = msg.split('result: status:')[1].split('\n')[0].split('payload:')[1].strip().strip('"') + except: + pass + finally: + data = {'pkhash': msg} return data, st diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index af83d79f8..04e6fc18a 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -332,10 +332,12 @@ def update_ledger(self, request, *args, **kwargs): return Response({'message': f'Objective Key is wrong: {pk}'}, status.HTTP_400_BAD_REQUEST) else: - args = '"%(dataManagerKey)s", "%(objectiveKey)s"' % { - 'dataManagerKey': pk, - 'objectiveKey': objective_key, - } + # args = '"%(dataManagerKey)s", "%(objectiveKey)s"' % { + # 'dataManagerKey': pk, + # 'objectiveKey': objective_key, + # } + + args = [pk, objective_key] if getattr(settings, 'LEDGER_SYNC_ENABLED'): data, st = updateLedgerDataManager(args, sync=True) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 7fb900c0e..288f5baea 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -331,8 +331,15 @@ def bulk_update(self, request): except Exception as e: return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: - args = f'"{data_sample_keys}", "{data_manager_keys}"' - + # args = '"%(hashes)s", "%(dataManagerKeys)s"' % { + # 'hashes': ','.join(data_sample_keys), + # 'dataManagerKeys': ','.join(data_manager_keys), + # } + + args = [ + ','.join(data_sample_keys), + ','.join(data_manager_keys) + ] if getattr(settings, 'LEDGER_SYNC_ENABLED'): data, st = updateLedgerDataSample(args, sync=True) From 2604c02881effd7a6416ba9e24be1f31242e632a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 21 Mar 2019 10:20:54 +0100 Subject: [PATCH 007/457] Fix issues and improve code for query/invoke ledger. --- .../chunantes/datasamples/train/0024306.zip | Bin 0 -> 279457 bytes .../chunantes/datasamples/train/0024307.zip | Bin 0 -> 274698 bytes .../ledger/traintuple/serializer.py | 3 +- substrabac/substrapp/utils.py | 113 ++++++++---------- 4 files changed, 49 insertions(+), 67 deletions(-) create mode 100644 substrabac/fixtures/chunantes/datasamples/train/0024306.zip create mode 100644 substrabac/fixtures/chunantes/datasamples/train/0024307.zip diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024306.zip b/substrabac/fixtures/chunantes/datasamples/train/0024306.zip new file mode 100644 index 0000000000000000000000000000000000000000..9e579cd4e560d2abe38e0fb455453d0a026257b3 GIT binary patch literal 279457 zcmV(xKCYH`|__x@7N-B>NwUcYmWlw!_&?2 z+_aK&|5T$-sR3;Z>9!9(?f3j^1aBnrT^BDRr468k{kW>TdK?Ir!l71j@Cb+Bpoj|( zDPjXHl?-coU<>N2`97X!o^AZEHH@|& zh?$6ATA+dE>&Ii(BL~_x_VCzJNqT+5u46|2_K#0gZb%2wb{8tvO#QXna3-?TlI`Bc z_brC}ndFHJ9PJXds3KVDyAiduHEI)w${1btWga^UG?f@i$u_Y=OBgRp4ihS0_N9%6 zf{K;5-?1e~tIF};fJgo7l6VxKKDxt+#nCNvGdK(?s{>?JGd&MocPOQ=eUI2gX+e+E zI$Yas_m&V0nDhDJMe%Fqcsd5H$8AXs)`(awrD#8!VaMGlFl20H#TXjOO2j>he_EEO7~HY;02`(QsK+X%tTx^J zI0)-6MD60ZG|{$k$lRqk#S`$=Ij_d`Sq?K-w1#N^&R1QIWr&asP!1MrCPELH(A_R4 zF2?ro*5lFJjAWxg^fYKX^uqeFBynm>n}=eHK^)h z0Bm5Zi0=b9-GpQHn-_mx*KoLDh-Y7Z2rTxd}O#IS4Oq!co!-Rj~L-lR0TCZlgBAVyd&2zSpuA)^S5$-Sq%T~P08OabvTzC(_9)}vW^=^r)!6cT}rwB(xWs5tiTqzoQ zTzzE~oWZgL?Qi~6Tew4W>}K%PVScR15q+OjkvbAqGbST=IAv+^aICQ~F_?XW zAiSiSsIIP*-$Ie!hK`RZ=_bL#2Hnmq{&9k;uBv=WKgi61*F9zw=fmt9u!2~3lo|h* zUO~wGojwbyQ>i3v-^z~5hU#eH7<8nTx7g=s!3{pWoyxj*&~XwT1R|Yjo35GQgcdKs z)#lbC+N?tT)M@O>*9zP#^3x1|7X}|!8A%Ug!B1M~|1ze&ep=EQrxv;E1I3jDP0SlI zBt3|gP!|oXy8g~o zJtA-vPqJRB*{Bi3C!@YnB?^DU*XEZGo&TlCYy$t2GeHwUHvC0bHo1rvos(#9Cc!G& zv#vh!T7tfnk9V>4r)l%`XW(Gn(mFM6LIZ-mt6kD~9jt!RZZJr9k*&puH%|GcSDr}` zf5|)_dn{Gq!(F+H(;@7+qTXU=+Y=sRpc+QsgXf)KI?z$4KIY@0A&Aoi%#*VtHGiJf zIq^bI{)4CxOP9;83czQu_A97pG4|Nc;~1o#F9poI-8*t|+`jYN#^0Z-Bjc zR1>zc4hUz+P(HS-Zc^c@St@<&b7sihwjkxv4XcU*)#P)uv)KdizrTMycTNx$J-G@}3n? zkza{I3MKJZmFvjIUaZm*zgr(Qp6^;NXHO^=Gq6xG{TsDSat9V3Ly?dYjZtq zQlNrsA`^z4UEEb){|~b zigJ(zyRaCk;TAyxlHI|bwUQB2TE9h}P_m;PdeuY|rP+Lh6#sFll>&*F*_5zBT`@Fm zSb#c?E8_P&E3Ezi;~=W4n2zS!*gpf&;K-8yMDS}C0V}Gm-gpH(G(bZ*xXBsOAHJ^R zR+2JhU97|JNhpHZmtVySq=lPwaY1XzBYRf9vx`Hw^I!v^L zc>WEj`7d-COg<>kC-*OY17xJ>w|7Y~4Hw}KTvNIx_S(W$C=%Mm{wj}Ir-?%7i=X>h z)B_)#RlO>-C{a{C|Car1zsJ(PU2XL<`xFQyp_v)N2%WV|a?$3xT3sW1*zV)AGZU9m z=3^PIDz37wajIY!$53O3hX>n_yihb;wLYKR24n=6B?#JLy`^sGKlmpoD*SE}c&2YO z+BS~7H+H+7PFJPFUzYlBOLp9Dr0pARw3_PG{extIaCPO&scx>%63lRxyb=wDBaY}N z*D08@(jur))Ft@W`#(B}+ykt#c<3;VKDl}6fu<^DdLv`{YIv9&%Hw^okb&|K#VRJK z^X>&z_)2$;Rg(pdL|99|=2I>6xX^cb68kniq)KjQd<;chc$Ykb+(`)Ki^ZD;Mn-L6 zZYL6j`D{T*cRV}AI!@a(ksE%+ROI&WqTRUtGlmrm zV#+3ca1tzdUKGP#AFh@pOK8A)5-o`K0op0-=nuM|1_NkF(Nx(1Yp=uf-t*#)WWQ8ibHAB@Q6gAw2 z(R$=l=8Y;S_*~vH>FECUh~O(UNc+@qMpKGxLqHZ?;MOD?I@sJ)XEw?r@5lxNkQQex zv1(Y|(bUlTAnY3eQ~4=Z1_w3O)!Qgg5PVFzcz-x5=X#VrV zQr*Zu7243#AvtC^s8KofUq9LNKdrs#R-)SFQah4wu2|$iEZjO?$M+vwU;k0y;0I_H zl&|ZD_sJIX>u1|3cd%Xurs1Q(b#vD+r01XdpEwZ|>UH8v6I-auJcP*xO}eeEj9jqq z@EjSPkaoE9@B z#-YT;Y}mz=@>^gb>*Dkz&B_7@XwO7-bz$P6cYv3uJ&cj8<4 z`CR`Ax;oO=I>t@PceZrX^{(xmkX*`iSiFFr1oX=Ur3S+3ev zPWw=%W2k%a9Lz33y4zqS#d>PmE^uUA-8NCyE7l30nM!6bm2CR=bH`(zXRJB%% z40D*D3BpbT(M*}+#>^tT+lxXy*L4GN&ehtt%l9L}F+!-3(6}YiUwRQQ$jzj%{88+6 zZEYP#{t`sA^WioL*Og_|W-M=F{~?>~(oLj2Gl5C0$=E(;dBm-bYs8qb-(zAkaNZkU z4VX!!ukMzp1s1Mwki?LAFT{hLRPS2_dKViMyD~2>)^?^3ZTqdLWF35VPTVh3me+(c zhnA~56vg#4Vr>0j+;3AtP`&i#V3G1wbr@LZoUEV%oO*X zNla%Ncu?oKNy!15rc=SpF-a+>4z!zo6;E+xCjFYLC-&H;{VWS#`5Io(*n4u!>?tp?Q!Na~h#t3=>L<=_t~{JW3`H8e(eyH{w1Gk#P{EADiJQ(z zKz(k78c8U-G&Lqv7qA2im@$ft}G#~7MO4g!~Q;PdnMTsmcmj=Q@LbgQ?Q=Tc)TN4L0B zd>sC@!v&VjLJZTao5Sm4E|d~yu?rNXvZET*NI|6Bwt_8XZaoa4gj$A`RIxkTaiEpo~ z?5ulxDYL5mW~9x(;iM+zz&%d7j&y{U`6csTTJs3cA%euIJOlYOzL8XY@KSnO{rWR< zZ&)3gHJ8hsL=9m*^7S~=`o=E$#UXzN_c#9rXdNHlvQf9-L?f_0_$b#LM^8#|+5mZV z;E;=Ddsc#s-oAgt1kfUN6nd%(_Jt&bMPEAkEXM?l7`hOy&$g;%TF|w{je@7&u7Y`g zN-~jqdu@1CHnuNY<3;B9I!F0eIC1NHzSFGC_6d!7ESnFTG+{Tf0TiKtsFI;+Ymh`- z%8F%mzc1%l%C&Inj@^-ae^MV^eAXi_oC0ZgFbj_6k8XPF@*d93B7`Uo=C$Be+_8}{ zF!1b?@z=wY28)*^XkQ6wdX-|y2%Mj_p0iX7Zj9A#S{bpc@k9=W z*=LjrLZjf!GiFc;B)$|v>@xIkodAFp!haO^cFGRHl-UMd!x#BYHEGdEp0?|F3v)|2 zZjtN8RJIN`xgX*TpTzU%Nyu zCfdT4yFa{YvTsLna2nSPw^%)^iWPCH24`dPF@|Qo0h39`T4kscb*AtpD#$gG&Gdz8 z>4i6*WGM;!5~^g_H45_~oret&_oH-c=PCresbrX!98CbOBC9%WhSlgvXxXR6NM8ng z#`#e7Q7Bw0_{zeCO5z}qUO#suu%n9FQc*K$>v8|x3fTTEHe#d8lh|Qpau3PcP-`}@=B|*%;EfW3kZdhXuG?CB5q{bu-^c3fK>VCpxZF2+w#u` zyN5`}u!yY;_F>(xwV@k}AIjKE<=5sY&!J);QP;(nK8N}BV&rjTk#lIQ?2RVME2+V1 z(1>p6<(YWU<8>)u4|k?G`dpP))4x%5r%`)bE>5m~wvoVBVl0#IkEFL}9SHS!O}Vajp#1t*$PT~1!jrlG-A zmpDT$2VMWm#V-AoAI}y~!IE4Fe;FIf(tGy$_|gh%=fAnb>h zpeDTrGz&=GVBLwh0d9@kdeOb0E<| zVOMv1r$C7*wbK-MN^ohj;%Qn?l+(g#sjTw^#oIp5u%i@t+iCnEQyY{RUJl<`8T+WvnGf za+EkH61kY5=}_Y{3HO;X@-#8Fi^t+}^_i2P1KfwZ6I`<^B3sPiniwZmd)OyVoNud*qQQUV4zoFmrJ9H;?W+^z52` zOyNRZ;+UCisuganF5GJ*TAkN=od&uuNX zi-L$KP&oF>&HwVfG{)S)p77_Qg~L&4<2xikuB&dPfJIjlw!kW| z(mjm-z{)RhBA<@OPDe005v>WtT(;E&Pfe$c5?KLjyzuBRlNd zl&S)eX*A?j6Iw}Q^wL*hglRA+Ss>%Y@+Gm~9Y$l02M+mJ$S;FDIIaxYL{MNK$ddg7 zi1qE=X{QOaAmd~bx8Y27n1NTg6;#8IY*`dC%zP}Nrs#F=iv%@Cq=sUR$J!WnZNuay z=y}3AHpDdLj)8W{itqfatXamTGduh8{8b_W)20OE>7{lYbMI&@yeev%R|ed7caIiG zu#UFsHb`Rs8nBMKs*Y%|z5!&W^=M@7GGw|nW`s=ECmr70w$fa1=uN4`+VK>gqamDH zM{P+}Rmq1&m#{VrW01(OO?LP09C*K(fRC;RJ7+wNr|_fSfWLX2beV^x7u`b}V@CON z4p;X5lQI6jX#=zA%um`iZz-k2D3I zp=DZ4o3aIa_g5S;CiGSOUUa>Lw1x?-M8JA0q*599WqVUnKq~v~+C_Ku`Guu}GnS_Q z^_O1HY28ASf1V}+GiG!2Hz2zobkBVI_KrcBK8SUxxHYD$`Ij+du#i?x#_F1zRk7b z=4CoVIeT7kE?GMe+1c0oy30@=%;0~lCSO!P~lC(-xhE)GXkfu&jV$&E=5)(loaB&xsj6a>@by z%_n%Ykj9cM4tES`0e*hoL-MmWOisiKGvz`oG20o$8rw>n#pU!?enH#Wk8>|7l( z%XQorqTw9W#_Bh(zVw7sgQV9pO4p4MQQbL<2992hYV<>e9l`c)NkFJf5G#P-*OHAI zmVzqtC@{ z4lAGg@Rbt*`q8sqG@FZ=(?L!Ck5T5`#=50f)7SNEGoM2c>B2O zQ$_Oi1r)y!@lgWhB5ZFz$b{B(TNRxoylTHiu}w>8R!`?gH+DCE;fF^8DdEkxGKQo9 z6(_nfFMn!*$m>6FnWNo+7O}v zV8*b6x0j8m#4$nqr5L80{Vt93u<297%NnM?WrKG1|4jTfx zuXaU{nwg|rqcjSqi^94wZQJ~D^nICkQv6#w;#G9HvnkhXtfrl7z+*tgNQ#El5<7H* zIJCLN9C#r?93CV94!RPA`}S*rf^Dzg^}tAmR+Nl7$dM@3!ICBQr_J3igO0f8J@M%k zHwth45_6xd#4A(@d?UDOI0t%y=KCPugc`&PIj$hxMX%6|mu6`j~?DFPX#iP$D` z^C5eQCjMwIr;%SP{xYlvdzdpJO1tx8avs8(oPg7&5-+_XZu+oKwFp$R?PeF ztQoI#AAT#MsyK;)8HJd5&h~i;Ho8~6+cmU_nY}Gpi)D^+H$9dA6 z=`k84?nVI$QcFSh(@_m8Z$A#e73S*isSgDfiN>~=g9i51iEqHtH{e6skNcA==!Q98 z5!hFjSH|ov*aESnD{tL2tJWktnqN}y@`?D3ng-lx4dt}p+}`l|m19Qc6HXaBt>AAWKs@MKJk zd#Sd#pZ!yg+hkr|c6P=94~!(Nw+u*H*)9DB{8*Ti_OA7u(Kx_@WBdK9BIoJ4IsEN) zSNZFg?0GM}$g@2)_dwY=ZqGMB_u@_TljSSSkL;6wU?`z=56-8jk<{XOYB*l+d|hu$ zg{s!2!J|#!G9ND^a^>1AEkjHbhEvSfktsVhR`#&#N7=A-Um8{eBEC@F5P$=JnFqK^A+g9PC=eBaI{?i%df zlyyaBW4KjVd&N|cYGBjlD%IZj@zZWL0B%x!<0AW$QO&$FQO`H~ci$eS8&5W6B^`>N zKkWHP&-3zlia7G0bJ0uksEk9jYVRXgGyCnXGFlp$_S9$WKY3p~Rh>BymtL&4?pCN{ zN^0r-1>M<1_-@TZ6`N2K{#8JVBqmp z%7ZEdxw!k8-~ljW!nAfSJZ= zOL#G(ZG?_l1FG?2YK3CtCJKd0ZEDsg544$c@ddks(b}m{(NW=;4z+ofCm+suJ?@+w zbtHJp(Ue|v_|Zz!M3V8bF#CbwXkd9F`DOr9Lw8@LK=@Wu6p{wQRcPzfzroZL{`53EV_1ZGw2h1u@Sd{k8car3A z5p;H%#x5zi$h)!5@-}q{iQ2$-G41j+-+^b#Y4&*p6rY zeIFxz+;a~qNM$S>m$2Z`sM8(x$qW z4e2nb34+%yeu)dFDs=es+^D66*ZkcpyxbSDUh!gb<2FlxZK)^dFR)t8_x^()Sbjc> zGks67?F^;4s~3qc4l%<{i|lX`Wz_U&H%$pt=i}X6hPhb!QvEHo>d4w!Sj1s;8m%A6 zf76kQ*ktaP-%BN?7e;=||B86=+B^E{m8TI-W}K@c!`X~CPw$-NzV(xOF0#t!0ppJ@ z*g}_rL=a4bh4lG(!$rr=za2v!cbofesWRadFTlK_LV|`uG2034SJ%!WT>oL1A11dj z*v&*A3ms*n6$WVN^KuM3G~Zh#t4MjcBk5@9TRQ4cLgZ&Jp9DRz9;Vr9eoBMdNk6CSEs>{pTkM z>tAxwAM@9(H|qN8288Q8pKN35(tx-uKp8C7TFC9CI=cx{vNSQ#aDmPlFd5k#$j~1f zHkrHkk!NK+Vy=vZnW$Dlp!@8+U-8W$<*+gG&BuwdEE61O3lX#r(_jd=*DjCRU9CvO)#&OMjs#q z+k1rk3a{@hSc-$!zk9B&;F=DZLCpUM--|@L4!oON^>|~VxGnCA#}^@-Z+%PdxWga`fF z3QCQr)Uh-JLE!n!2RMy>aM*jTJj$Q997Cnp1L5@RCnU~ro)FE5t7h&vw{4c(ssZ~( zg4K=as;lg2^+#k(3$a^R;e`1CWIUyZ7^5`}NN^#MibSyT*Am$!X@Ojlsu>9!`eF}V z$}1wAI$k3)@NOIPv5t9d%=v(J@AGWzIyx|E)D9)wNpN;`!!Q0_11Vw%)9NC)mT|cZ z=QMmD59P2{%LQU;VPM2~91qe~T~W>wdcxxu=2D)F-R>u5_GIhi)SpiN9=6Fi=y( zv*f`6AK9d>4oJuiy<+-isbq>?yk_xS9U^tj9fVtV?eg(jv)F1_!w2tA*B+;(x6f@H zm$%Jaq3Jp@LI;u`)JSfhQ()wmUS9nQtg)POCpVV~=#9_n_tQ94JR1v-g7T^Ea-yu; zly_sioZ0OB>{{XXmKF7;ceEh zX?^_rJ*VaC5{KvTt7ze+nQg97m0QDld$B4n!?ni6_$<|A87gaG zQ^&}8L$>;RL**x5>6?%?$7;JphxsZDG*%1*YVw9hdfKQhgVt$*Z0Cpj=YeUxQygik zuDTLmqT>y0rVj6@89V>{wc(~n5Js*FO$HMC+l#m9aIVEPuF!phBp!YIU$JDYEofSB z&;aJ^x^2vbimDq!r%5CrJx<-ItC_z8k-*d&Xe%L-%F2~Tg*h=?&A3tCckOMi4Txu! zX|75`{ELv(L7qk{yq=;#XPM|lR&QN%X-a*{ST?2HZ)Wg$ya~e(or54yia}0Bm&iIo zhW#|2QUI6CMUSh96DRv4FB6Do4?M~-1p>B}h#2k_GHy0vpAGM}jMX=Oa2Qwp%->e! z`lIwDAt9)M76RrZcY8RbkvNmA#hy!SGzE?V!BeEfW;9v(4M?b`cc_cdTq#mnj0GO2 zmsFs29J1DD*Y6f4EF|SE75z4Yp0$4SsZ_!&-nCYpP2?-rkVaz_34^zm1|K+lcZCQ? z3K(Tt2!F_(9&r#tYq@GYSZ3jCvwE73NN@Xn}2s2Hbj+<{6!G9NPzG=B*=v+ei9}Scx1uG$;$|DjWxB4Z5h!(OTIgWJ;Z*>7cIlW;cZ*W=4>~|94XG2CU;=+s8W%}P1TSn1bFxj|GcP0 zFx)ljlN4AdBS{ABmBh)?3Ut`Xe}fmVn^-qq0l3p- ziyFTm0Seh2TuJnJEhrQ)0I3-S~ROo< zWVlomSN29j>bJh8xw)D9bR-m7oJne7O#g;PyWz=ysa z*Qp#QpNaA_svsnm;VFpJz(I@lx3#P061b;`ZF18ahQ&qcIF746qtzQRZPA$%#n*6J zLl$9A&^x0rk|ZC;ASk!(Y}1;VqdlUrM2EUi);+_fWmo-KjgOMdZiG_V02Pwpqo3L| ziL63b4FQ-^=0$b9lWm+9d9QIC`dJq#+NV3XSW{8v!_S)Xk9+$@?s%L3Jju6v9K5wg zFuO4LA9Oc@4HARNVXzBKsK@=h(~1G}Ec8oNt1hUZsc>Ls=|>ng<%cdmla6B8!u;!w zsbpVy7}e^lWDfdBrq)nX!UHf|;GC%JMuA%>T zHZ4|x`zx<(^?M-vsPeC{SQ*2UAXBYR4PT6ceDAiJi9Ho+&9ysOr+^J4f4WzIKP*)> zskKZXio?Ni1+TNN-f8YLkBx{jMUzUh%TF@B6-1MXugB#mjANK*gD*dc2>`nK$Z(%b zVnFcpsJh);tOG3}Q78U#Tho_mJX2Bp8n-E|yjsu)x<>Phnw8ZbXDV)sD#6nMOXX7`Om57aUX~gL ztX8z8jUx_pmNaBi)z8|PLScMxo{2|PWjIM{H1q4Qbr(sP^ktZ6?Hfi@C9J$VU3 zIW#-HX9ldQ)A7B>s(tb*@&X;ok3I?NB3hDS_U z@ScQewT-^wvM!x2x1We?d%Hoo_9hxmyX|VYE)d($(>)`svqbK;xt!Kx{Jv11hW}K) z0U80-c_DA+o2&>=3d6~|{gZeR!F-WN@pk71hK-v)QDVu(UNgvRZ)fy8yz{&ica_=> zyV!D7Rh6zz<0~F(dO2c4Wbn%Q%1_y^Bs#tvz5$J^>vS;@K|u+~Jf+wjYX`7}qljqK zjSJ+#6tGsX^B5XIFBXCW|A3EZxg{8BKU!Tp`(2c6zX2OKhnto%56tmvO(f;hol=6b z`}}7mxXG_Hvr>7peI<&Af#>X42y|MmVX0*Cno)-8`{LpA^b$)~ ziq4cNmx0xH434z~_DTyHJS`(pBVs0dEuoP?xyxE!C;AN3lC*xi=2xG$DEPY!JNOaW z90n5ivgEW?rmEOcZSIVh+ES39VUZ0c_5fnSK3&bF5uIrei4{{TJj>IzljD{AV{NgW zU^vd;hqMOoa)8|PX~~PW*6jfnxmPe?KG5S1gM*%E@|T^kz=Ric?fhy`#r1NmnZ*ZaXKh!5{D1xY|;k8xi&J;cMsw(87&aG;HQ*HCLQ3b60>0mdvzdEk^ z72TuW`@LpI2mk(&ziW1usbMH2O|^qd)-XMc5@rxdC2V7_umRa5|Mrpkvu;8$=*U0t z4fv(LqSmslueh&PW?0+{e2Zd>)8Er!eg1L@&=9<3e`H$e9i=)iIL~L)5Wp0TCEI2p zN%sG@ZSf?b$CZltH>@;8OFzJ^6)HMJnB^OQu>9z_yiLF*(RVe;mF2%6stogaQSV)^ zU-3my-d)6Cv?1eRN|Y18Ipk;k4Vat#ppxFA9DU1pt1+`KGoLc7$Tp?Fm%1b;x>%Q) zS#T6;!!}i~so{puz!fN%H&uE|w#JQuUG-f4ZOG}X$?t3VUoM9J*ngmt9Q%x`nI~~x zqxPfyiMoEX{@l^x&7(? ziRSVYDJbwSq>79|N`Vz;hD|-j(E+BH!ubhQ>KwU*gQudG9IHIU!b8J8#?#n1*!1JH z?o<0Gv`VsZ{B#J#p>G`nH#bjX!czREDQz3InB;LEg46rsn{{eBb9x%qkr%tNR5!{% zu(~vZ9vBFwl3(|+f|f#gGGzS9_@3)yHF#iC~W2G;8gcVD2ntSfvo zL;9vkziVzSiqbcL#BNSiQbEk1LJdA_Qmtmx9UnD?Yll%!}bkxwUpt|3;`9u0$WbCsthJJbC z*^RA&--Ze^W`G5;HB^&|;~OxmeiDWg1Fe<_55W9vApu6Q<$&XaCA9;5l#n+GGZ*#rIXz1k{V-8gc^2nO^DDpxRa#rypvp!I>~)Px$8G-+{MR*8hkSY% zGc~}cRwp`sn5bW=4%y0DV8hu^cJQw_zNhiSzG?d^bgggBZaiTl7iZWNrXubtmYsrL zl9Ku}jJhd`FmY*4=m~Z80A8pJCJm^}%RYigTRo4xzwc$}6k<;AIpFkvS)kqP%y6O;g z2(0K>Y`gV#PV^A??jzsL2FRjy3fpi}A-XL=Wpw;30oiUW5~V zlu(?+q!)sUSf5zKw2dahH-uB*lBz@cnm-<;8`AE>cMV4_Ev-g}AH?sxKDaHw$5^HP z2E4j4V~|%vubOEX`^T71ETiGJzH-tmxQR}Z*)<7G%656Veo7eQFPI(I&NIi-(IDjxQHRLGZ}v-&C&bdlOn>Nahj)Y z0+yx;Q5uFaio}Qt%hcWgWE`M~a$w4N6#f}wOR(Da3f~&q`0ohT>t}|z2s5#dzgeN3 zPq*I=!-b9}ZLLVRX&p<7iC`p7O&|~o30@;XEGwNR3WY}T8@sPxJsT_zX67Emu1arX zi`UwVJF9{H3I^ro4tusAM{|*(er+(;h;kN}6q&%45CMNn6Qj_psv~eP=U&B-@Y-#; z!$)S!M%>OxsOsdlVxC!yl44K#-H#^L)eey>S3@-+oQ(;HBv@ej+1@BVrT59YDR!|$ z;sg{ZNRaY|n%o~ch0^^H<(izpTy%0eMEJD-2E+$?$i1S8DWdYu#f49ll|so#w{Lh_ ztAEi(zVM6I*i2Pk5>(o!4`?RC$yF6oxVP|dNhrloUnlJ{*>P_59mAXwNXKxI5Q-?F z!6GAVR1jAp0#;+dU#VU%NS&AF=@;S;hP5qEh7GrVpzWP|cO`TtJ-lmhj+2w3JlJu)9R+J!9n6)Rv3>*byhh19MB9XwS z=Ma89BfnBN;b|We;g>$)BbSeLL5hr z<}*J~`XF%=!v3tWTLj1>bImWVEJTh}cT*P;to<9`WpkNa%1&Hd?v%yA-ca~mx3%qv zQJlZJyi#KqmM@HdnC7?$j%5ZmvKb<|nk+>GiKbboPqKB9oRks+`u8#_`_6w^Y+wnORSK?S;gb+!q7)yQvDK!yGbEgd-BY6g+J{&5lNUzK~yT zNs7kH`&6_6A{n|Z7;uv)C`-|GZKwK$`{Vp}+Hm5*k&M4-?r$)gHoWJNh5keX1@*{I zn=}W^Fg#IA@r5{2)1BJE00aVs*Dy{yc3;T3tc<*bBk~+RET+N^b<~*FDS`IL<+U!{4^)fs)%hp5oTzV+IYXt^?~;%Lgv5R;C=}L=YOMAA>M%5|E%w zcQ=-hjzm$M*WI-o4mArkh8dAQI6Uh|?LwT+TF|}3H-Oz5d0d7y6i3%3g#v=VQ4!K! zrfyUf6huA35-DvdX3jt6K5+X6^<{3AppMs9CCe&{PiaY;)LeAxBzx0(oRlOC7PkFc zQDsy`q9t54<2-W2DablI`$uMkgXg4ad5yy_ICd(tydpwQq0Jd6{^|9J)IZlaVY2ej zxg*D|_WYUFwRUPscn~+j-POF=-gd6zHlix51}6V4tt*pdbHrQku-pc<#QG^aIc1Z( ztoz;fbkpk5_&rs(QMEBw3?2GzBs~C=C=N9TvqFY1?jQbtFfJ{&K`J+!}wX>2DPzg zdQF*vXE)g^-qmi|<>C@~iV6~VH@*QY(ks~v;~VyP3|&i1${`aj2`h1uNQ^nHFd!eg zrXONy_jKXSC99&R=iT)X=f?;tU7LWnSTDLI*-Haop)Td_at5|dlkTlGuU#khLXBMA zM&oBw#`VQHp~uJ?{q}h$KT(kiNs(i)mkT? zrre4{GU(|vVi?_nGJHjn$hHQgg72Dyhk2Ju+T7#)p;Q=iaFMiPP+z#LE6>SMbC}oJ z)pU_9;9a`1y5yny6H7JQgOviOwLQFq?8w%E6FIz+txK_(F! zAfGVYF1etnz?xp3LB$DhAB>7|Cswl5zf zGmeYf2{4Vk6WcoBQyxx}_Jgz1ur5Wc+2JPVkXoQX@X)(7G@;Lz9INxrP*hRTrZ>66 zGncRn2PI0mG-BaDgL>~aBlS16GagOnS*M$4m{q-ht^nIxtnau=>v`wOkcx4J$a0x?pf z2;E4R30C+UCxUhxmvC0DY@5pz`H$KDfFM&v7@h zRetv?YR9Fmk!+WY=jyv{>E9WVnEp(5Z{V_kWUo}=Qc5Oo+V zs-utbU3N)4k0_6RceR&Evy~_@#0@mSV{v55lcn;^*K;8=<$(}}PcVsr}19iNLS)I}qE z_3fGI@0|u2l|GSwlkP@z9rK4JiO#uS+O&D2Ie4YbF2}^Yb1+C?CD}C6G9iZP)RD88 z)M-5?7;f8iCC->!`4=J=J85?e%2P?@D7aa2Be&ofvT#kc?%j6&)ug=TJzi7I_e($5 zy|VRDT&>NpASCF;u5-j-Qn2Clq$F0qu3GFdxG~nXSev4!w(G^|ycZmSllZZGZ@8iSj+EXp|VcW*7Mq6 z1X(uZ!yNII6T*(Wc={z3w)Gd5G?W)|#fBk#nosdJH-T>QOv)gsCN~n;Q`>S0*1Esx zn@*`%|;7^P>JED7Mm+!`F4ho)L+-$8Z|`}>A4Hy>(nF8KR+f7I|w?@ z8y~DIS@JWHLa>+l-fNIQ{D)VyiQJ|vCmiumhG$~4xixTuYy4zrvnixrY`g0k-ADw1 zG&PpGWvz{UX90KlED>k?oE58!juzR_X0tXXT%^N^i|(xo%#Q+;?h1TtOXm8z#!Xcv z429+lb`Z`|4MqM!r**PRHr6BTw9#{D@gUxGRwwBIn^TPWE}v7fuiSjvbuo?u(B`&% z!4EmqQ>mNK)G=woiD>o)@GzrMqfy5skbr!4cgy290Oa~lJvVyhs@>A|XTL8@jAP|- zNxMoOLz3>$b@aV5(U;*tlKG8%4hek4mB(#(BAu9!I*|=oKdFc`?xleIV+s&sNuQdk zmmXSs>db=i#B{*+5$?wuV*trN*P$ zmH@ggJT@Sv-rH^PL#jz>k4&rkn&3wD9?SCT8?gNEL)K%;<9aN`Vh3q7))npiOapuPnQ4uMtE2*jBOl=95%=lU8<0P8#?shLw{h`Kb^~OWG zWp-)Ko&ZXn5Yc`rw;d)35c>v{1p%HSQ4`oWUYsYP^dII{ybq8mVAOHPddhj@!*JgF#i z5sG-Ph8k+lS(oybd?{rmkYW{h*?bUqR**nzC1i+3MM6Gz3EZb#m*rjZRKkFGWv%JG zA*&ypq_Vu!QI!Js0Ah8srry_AZlQ@~a$Eh-s|?6b+EfGfXdxOC3|&#ZOV&GsKr|e3 zp*oZ!D*Xa~+FM;ZXdp&iLE ztaz8)jklV5DvDyZi^nN7BH}v#w;_@T*LgE0aWW#ymVWhcL5%FI7y^Mvz9;%bVJmmx zl3>9%Ks12(@to!7i_3Hk$2IFWAb=$S!gfI$mE7b7AUVwt<|PO`$ZZ@=IEIalKFua# zd_04-Mp^XhzGE4|4Q=LrMGd=}N3(M}GT438|xmp?qGJh5|^<1eQUXv%;UgUrW5F_UHY0*4c zQ&B(HcrX@kgdw8IfSkX`N6a*1;P?XQUj+F<%V%Xoim(IUfX)b(OioD_(+-N)_SmQL zZ-A0~9EY9$BqfGbJg{^sEDZupOaXfA?{dQ{VetUSLsM18&_8=yZB8SC4eX$X@$&5O zOnV?bQd$)^nVR>Q8h_sN$N2K_HS_V{&tb%HuapUVkXj?%<&;&mR1YzJl9_T{$6K5> zu@J+CS_$Vqw7Bnt#$mf2zd#N7NU_A%+VnBQfW*b8<|dPx^PK^QaI*e^F&VuPS_~;c z_{l6-uiEZF103h7whXV58~J{$bsB!_=nU??=lNU=T1g3|76tWe+vUzVT(tk8JL5&w zy7tRizLZ|+0tq|0T=pD=2#pSOCpl4`{KrGDzO^VTHY+t{CKo|fMDA)q(1t;dfvvaY zVhI^M1O`JpMc+U_=d|6|XY$K#h1>yRH6F~3PxI&LHh{#PTpN5X;QFxtais)DyUQ%=&U3(&XVmT%(O2`V^bq1)aWh2S;aW z*!ADdtnC-Cf27qZP}Q~GU@-qjwe7J!t?sl$STAYbYPznIfIe*e)5eUsovM6|bw|=Z z0gYA}e&5eah(WUQq`Kf}{m@ZSm)^vl#azZN0AA@saJP~_)xKE#E4w`h7jr6M_JNpU zu8Iqc+?8Z`T|cuLyw>6y@RSVr+B{0s*)Val2bXfXYFkqKoi5<>$d=PecGZ=t!RU)2 zt#y+(36kb>{yRQstvUjpGW1KQ?ZS+DBN9Iu_Vt{%1SM=D?ZkK0n|pE(-)XmLX;_p^ ztz9b4DX%JH?PT+9)x;e#MJQz$b=CY_I|OHhee`GlmH{2O z8aeQ=)Q`nMCl>mGx6c#2A#Q(fnqO(k2muFGUv~+^0_u<5RyaJptr`@jk#se`;BLiF zc@O#GHI_i`4bIP9PSeGfW3G9e^ZuR^s#Z<5OqbI_hFlY#L@AXb>IlRZdoZk8ydqt2 zq>q~@EAFK?7a|r@vJq`6K4?AjDp2!B}i#}3DS33x7t|(T? zUL3mj)xHwKxYui6-0dp9)Lm4?4Ai!#cYEbzxY9g0KP1yHc1VFNK^I=4XDUb~;GNVw z#rgxs&qCK66NI0-wH*knvQ?GXIy!hU_i(?6-CaWC6kyXktSkU$IA&P~^0xnTnHZT9 zjWFs(RH}4*G^&w79d<`-dYF_=siYB+yxwNyf2fiQ-cKCEiN0>lUYWBAh(8b|p1S!8~A{lP|c(3a<{v{+~w^DbeI-E`f!c13sP!GV4|Ms9(gFKzati(RBbFA0rsk>lM%O7hhHX?W+yvY&S1;aGNK zq%O>gMvDZ*diLzrd=A|(gpd*elcABg8=BC{nzDmEB?CnEes_77G(*;s5EE~G|7%?} zHdDj48%a1A>h?z<#T)n-x<0hI5!T5P0$)9NuU(V2>wVe@bC3 zzq>m1Q+1(wA?+?*^xsb8lsl(8aMln~Y1ck(_`cF#$+JS8g=K?aZYF}{Xi<&L5-i_< z_r#@CEDU-5u$FlT2A;LW{H&{8UnHGXBt4Zr8h?i_1mg78T-qLUNS6_Gw!(T!HKp|3 z&S$NcKF=;GCt$w)a(1k_c&J62W;^>Kr=NC71?DymL=J_p<~6Iy`=a}e_G%Vb{W<@%D4vLW|5Jt0 z%#-h^xvE#-JT^}RXeWPVT&%)v^*idY&~MMIrlXH*`5?tzwMA}j5)t;yD(30=*xp`f zbotQ-i5)ljGUPPO+-)cO%4tE+_>O`rTjz7Vn zniz}po&)28%DP^b?4U=>Fv3fk%f=jLYvt5%@9g;oukxS+&xJR&p#xk)K)5`EFiPHXra3dwluLvST^3Aohz=b6A+wD4_;4W zdffQ>(p)MDc1t&IeKckc79||(bzw-Rn!Jwx4ozCEl)ukyDj_r?H9|PIX@spF{F?KV z?kWeC)?P(9MJgwa(M(^>;W- zM@FxkFNO(3egZFa#o}Xy*D2ZF>&hJH{iXd)WDV(7a!g>>`u9@rrOO{k_;#88DoYcg5UC; z;~(8fyaF_IzAS=ouVj0cA9mO0lI4uZFw~v*s&dv^ELNQh1JQ$}4nx|-OD^+Ql$I#0 zK4l`M)I&wB>d8Bp^5-sQD3+Y@DeHN_BLj;~U`Zr! zqs50}X=RalY;+W3K`P?YA|R8Ma9Vo)qoyu%T)E2RAt0mEYFpJ;V_H7w8pUu;!R7<+ zz-`M==dvGyHA~Km7H)_!*0xFDC$SMYMUP94)F=76+95%MBZ2MHmaf(|(UWc%zr3V- zU=w8*me53AA0wfOVS8;cDOkDZtJUc+c0zj~B&7jqZR!5lMqmD?z(lHy?@?Ga5b`Kf z^J-jP9n5z=pLR-<->Vgk@nh%Ap2FjrR;D5#r?jNrIe83{8@>o9xKV|p)shX~-d5lb$svP4YC@R0=5YI2eIk)o876_^-65rpg*o=$C9IfA z5qR&!vrP*uLZxo6zwZ68%enQ?Zu_}ztVBOU#$a?6!|}O6$r-AiggDm_Rs51mLhRQ} zW;mi&a0UXIQn@Ahc%iARD~=GdC=Gac$x(p<%96mVM8vjuUV%G^;XRoxZKo@oN1;|O zw>L{#W*pxlt7G&BL63g47#Ma-q^>k_nKm3XO1cdZ*%56F%*hzPg)IQDm2Jm;dT}e) z($|WLXclSArY*VTBW&d*=@Q7mhZ*g%kwa#I!D?3`*wJFLc z8a~xIK~@_f372QACVU`T7G^9pyLA^)Gv&&t9qR=&u&_y~Td9FF>7y2p=&UAE&zbW8 zaz;~2>)dssi8IYGW^;Wdz-YHQWM;sU?xY>NGyk8SsHFCw`{K827?a8A<#QRcGQ zjBqoUqWxLGLMC5d&N$KmAt^&9j6#%kbtO|TzKOZt!%nD*7Ayd@t4Y%E8c0vnVYAHJ zNZ9)X!=W#a>+oItl+)>>%pxeclo#M|jlt$x!hpFbljie%J67=mUgvTYI2N+f!OqjG zkVm6}0xX9mmcVvq!+R{q9t*lRFZ0_GZ}uog=A~ROWvzlM4U44k=Sl!b2=ME-G-=>_ z>%*f4*28hT0~vosM?DMlz1o*|gjV!>NvGWj%_}s8(RC;KDa8uxF(Zk`TqDwFYK4k0 zW(&O*0D=6z6*;P)Jnv^L96o*7&UIv~Bm0VPN!dqa+j?fWO|V8uK3(=@<8qCRrZyaHIvYU5(rbiFP~1#!c|u%RRlK(o6(7_F=eei^>L$*Tbl)B>J>g zo?l<)2M~Mk8$df7o7B`eyY0)c=7wNNX9^fJwi>As$F(VpIF9jEHV01_uLkw%M(X0P zh4Fg$ibcLkNI2fk%PNSCP^S#iBvD}Y3rQrMZfzgLJ}Mnc?Y7*)L2MKTm^q2$XM6x~ z{K1a!h}}q3lG@eNmjA}u-8(bPco-u82r>m$P^4TPnKaV%s36I9OM7hB-17m*#^6OT zIo90-U9w-mmk&1xw@yZ% z4{NDCSzC7|hu6`jjs#DtXx?}9uq7uv#Dv>Zj@9UNv{eT%EQS+hd>??ByUsCKy_~qU z9jD{sak^@5+p&IwT{#`?k{sr?d-V6>k2n7w+d=g8Ak9aZ^ZIi`+ewQ*!#PB}eYswY zcPA?MIN9v3WbJz}iEAu1oq+5lHP<|7vuRNol?^t~SSY+#iCxUz#QogGq^7Khi)qC* zZWC&{B41Bj%xO}66>~#_j{`I&CB0zz$kol^q47xdVWrce))3T-jXbbAS*MMCes)<_ zMHYxn5_uVF6dYoYqv6CJscep;YfI z%`Gdz_Pmg@v4_CawMLzw6KNnU;y|1fmS~iDH8mE_;MOLzo!P;=y;-Ypawk)5y?pu9 zc0~n{j#+xby{NqI-_WRO;mwi4^*;_%MbdCqlp_>bP$5+;lw@2hg+hsT)WU!>XC&wQ#+t%mSS&V>gH-U0H!6hMC>36DU4#>+gD=^B0dUymH zVw92L_|9*D${*_S*k`R0$G-)?R}1V{T?#WQCB}7O z|F`XY;}hU$s29a*CN6F@b5Rp^wY}a;20t97;_t0m&B1GmsgtnTz57$pNmzY7-4Kd^ zmd9zyYB7E-r`>_0HJldnNo9t6)DYXx;~NkqSou{w`wb9!gTZ4&l@WGkGo{V*+Gx0oyb^jfo??FsTTR4+NdCLf== zguwfk1pRgK(y4B#^_3N{-_F$G>GKU(%|gTP#HIP!GRTxd`}-U44N#x<%Y=c-YAhxX z0h#sZQQMxKeFG3AV8is_P3fJaDX$V*P+UUl3m(xP1)5bB|?xuc~AY$Bo=R zq25H#rwk^85`s2=7Y_UlX2Jh`Fw!6ajwGv6sNt8evvWCP-_LJ-Hsb?lgPUAupQ1kO zlg{Z|qTM*S;!^?ZupuKGF0o@$Vis!nJWaC_lMp*qWyMLcbnp6C1zclcI?+m#<4=N) zj?iB{Y+GM5sHdpX$^5a^S*1x;4F~B~S~!+p(SLL(?fOT&xdRJ5mp}II+R76Fr7j{> zulQ&jkXls+ZTZRn(qq-r9N~T!c!^0U+8i}PzvZY!`5fMeMM}2r3GQ-!W>Tt^@k+Uq z+xjrJL2U=(1}O(5Q!8K0eFMrDTbL+4?Y8=^(bVwVu0wF2W8!(T?*S$cYm(|iw>Yq)7FVA1}-8fu? zpV|GJWfRirX4$s(x%?O42Dt59qw-oW3z?W+Xl+Wk++e1auYEdNF8i@vbygCjU)dXM$fWCT?-@ozr$;F^01l=P z*F3{2ZH6D!+o@t+h*w8+9J$b*=Z)rZ8$tHJ=gm0`9Pb^U&NP5OqBSfCHF%+WQ$r*k z4wo3xh;KFIQx=f4rN04ffX~WSP2C*bVJpzW}*h_gPdl|Nm#PM@5 z+unft^=eP-A5y3lN3X^oZB3JjJuGyL)j;iDy8wRtR+B#txx}2;wWdmp)vluU9V0IK z-i9ii%yk(1x;jq#&(Hc`;ohQ=WamBLSUY25Mm{;z29!u?dPm>go96y0xYe!gp((vDY%& zS_XYgr&wdb^4#}!EjSaTxV+J?0P|1TD9Fe!9A}dKV)M96RZM6J6`D_AB|r&RdAZBK zPbn!Y2?&Ob8l(Pp+>W^zaFriTm~An?v{OcC;=HI0@1pVQb!K6>R8X0i7E4FVW_?5- zNJq!wUUn+>C#CS>fV;z=ak(Rz50=Z$WupOQ~Mq{=~@ZUAgM{l z6dr5iY<~(AYV`AybF`OGP8Eq;=zA$|ymj;+;Tc-WLZ?*_*#9`1RK)V!{^OpN6$0>t z-)f|5s&4+}SCXz;!tn8-Mc~toiFuOh;V`Tg7QdLDL5LW`Ki8X`IXR_U<1@Chy`%FZ zyTd$5CQNNTouiziPL%ofLI|nqGSI3O%m@=MIqKiavALP%Xl0r~zJg>sr1SFNB&;^n zd2XvGYl#32B~s_2jWe)WX?}t6pWE0I+_1)7A{Qh(&5ow=m23y?G}0yo=1~02ZW{Uq zk_qj_dHslr=qgwUa@SP{@!dh=YXs8kB6H~ebn(6X<{?;e$@;Q=zSSamJbe4G`kojzH6?BwZ6K9|LtwAmzAys~UN*-VY2h-B zBlob20Z)PoO6*r@%eXo~+)2}}?^7i zr>^x4fM!WA&rdBK1ERj!ru;2a<3y{prsLNGC2g=o>_;;_^uf!}OqlXBn(vR2LsrYE zBkz*v!N3;DG8e16ktvU@t@VXy_!KnBl|2<`Q*8ZCYZ)~Y37pefAUR535{rNt9!@8zNbg=!V5m}#2e)EYKV_X+L=R3SmDJ9LfpJ| z6RDR}p{0^e+RJcK6{Jf&i$!Tq`pL3OH_sGwU z!|Jw~i`TjMrPLjj>wr@ivM$SHwnb+w8+qHK4d^g-{c10kF?MIm9R*^@=O7wIT- zW>ySc85jyYcNLf{H*_S4awXBMD3fBBaQTGz`Y-7y`_CplPd$?@O^q|qHvq9o#kUb- znvqp9cbAgS4d%Q83R+fKTZ*ere65VrsGW4WF$9UsKa1OpycWwZtbgrb zCg!({UTLNQaX43ldd1RUfYfF*m&h(n8I~P6NuTfz% z-Ow~yJM)%5^Vg@uYKjm`8`&F5eoc$Iv)lN~?4mzgD}L9p4#os)P;ap?k$ADE<+w4n zR0`AQhu&2jDhZA+EIe$m!(Ao?p8EBS9WeAJYUK?PSX|gRE;-tTM^knitOk88M}s_X zMJMWMfu`2abm7XrDz^lA31o4Vzr8yuhfR1L@#2JU$4cHgGG+<94pfbQmYw zBBDR;b3%x4m20f#CxM7vVHQgMhYk2n=3wL+6K!7FIJOGA6@Zqfkk|L(ujz_^e)wh7 ze~B-P&+_MLWH)&jSWh!f3C#w}XoJr_q%;$00LVb!wm&c3&4vUVDoZi2HnalEv5~Uu za#Gjvawj5RpO{G;nly^;n<(U@9=Y16eb4zX1F<=3aq|apsO#+(>!Qqk$RQy%b=V8x z7)Hp|p?Te=6iUgw6^yoMj@Og#B>A;bbk9;M5x$In`@7iEv^+h9N7Zi4ne)VuNYfmj zwhPSR@gj(casbKHKXkj#4w|AB1U9dz^`B1KE$%R)Ki*Y%Je*_Ab~o@GyLIcnM4#_; zM>Qpq?u1>4HN?`HN7&43J#goZI6T^H;X{HYr5@2@O&Vio5hK+{p`TRuu9R(J^UB>g zYK#fwYnv+E>4yU)+dI=VujYH0EzH7U4^w$*%K`_r_iyE3^&L~diS`Kt=@=)37{CweWXB|kaX9Hj=8WkgC-%VCi(89GTth8*ov zgDl3*C@SD=zjyITm>00wM>YS zWSE`EBUbvb*XoB0=g>R9$Qc9McHl@#ag<69G`j^6+vkh0(& z?B}F~oLkA`vq);N3X3IQ&u3}C)19UyOSiXh{0>opXE~)xlVy6hDVR zfvAv6Z<4}sn$ot>efG=NAu8yC^?KH7w2=~&n0Jb0N&{u6?tH@$iozFN8{lh$;`pbL zDoo;oApO$G2>BbZFc^N;eJjQgx60QYcD-)Nx#0TPO3XOn`M2c@zVKyF;TsSiQ8Pks z?9|Lm*Bz?Ca`^@^%JL0J(aC$kS|lFp=#mJPNF{4iq+Hz|g+@Hh@3HZT;<+^2MMdLO zccviC9o-zJ@~_+fw)?7sv3H~{!?8dT6RzFs!<`b)m?!>_lVdwigE zmHn6o`Y3C|Il7M5OsOj-uYDdW%Q)zmR>;wfS}SY~6TW1RncX7LF)r+uu)HqU@g+cm zVdX4t1rrok(Xkcn@o&lPk=%MIual0#@*6P8xR}u4jq+-~Ao3?S-0UFw(*N)SN!Wh&eBwT<2B$+!X=|{rli9mH zGPdz=VL@d@Hdo!1zkqkme*=D`_neICu&{+SiFWXs5L0_ewyLkXIv z^0-m>HI?{yQ?9T()vn9U@wvTlXY_j)*RR2 zE#OlKPhOs)_^N#OIJCBt(q8kS*iemC--snMpBYe$DMPpqAk*15R3~07OZ)*-X$o>Z zHuGD+(>iZ*%y}B*x>WDo30=;wZzCaEzBGU8t@#ExIDhcNPF>GW;#-r5w~?!2vLZ>r zW8YVdD+N#{;JXRbw3cvg_GEc5yy;4Qxnbez%fMu#n&`M_-^8$d#0JXXnVIJx&OPlpRskVMBF!^7Xr{`|M zr!5D29JcmW3oi0o7AzUoEH-=+?eIRF-3~^CFUl=U!biguduE1Hja^g~9@hZ4>zZ24 zX4-J0mwGpfaO<8T3Xo2#T1+N29nK}RM{-Rov@5o{OQUp)L%az4)V={j1r}qo1t21j zrZcqM&TCFuLFXoaUhKfm=CvAQg`^r=p|5I^ zVS>Ak7MU@FYcS^+^atZ-mgF~JU8Xza_NC{3x9t3@;&1dp3Pn$}>h5x&1)>yrv_5Jj zLT_*74bOE&^&%;BskX3MP&wT`wuS3^9(CgO|tgLy@A2@V$tgIgFrebh{8MM zzZgj8fn7YwJsy2HL$lUb@KyQ^FyxKrbo!^wt<@U@dyCW4=w9Q9kZAnpuL_#A?R+U@ z`bR&$!;tL48=0$d@zkfywCbw_s9WNuv&StA6!4b{WLR-tcxK%}Mj)-vs2+8dkzLhg zTi+>IzPmtF<{xv@!{uaQDb?S-)s$pNWl^?3{2>PTY^szlG4H29drV&Hc3|{tp3YjI z@aP)MEz?wzTxjS7)s=R(?ksG{Dv5>+S`I$`FbNbvR1!a67nf%2&S+}*s8kR<9(?&& zWMiu^JD8|P|0_rebI7@WuG3YNw@3;uP9{mv&S{KR*;P^-(ng0NP9feE3=7-#L4Xbv zbVevquP1g|UG}!`hQ`fKTH4r9;PgDa?)&G6ky69pXD==5L=N4yzL6Q%v9*gbaBC^A z7(NN>S+X9MQrlvqy^*QB2FhKf6|NryonED%H>Ifr%3JLP;W&M)e4N(2+Kgw=cfdhv zP)fvg7htO9y7sK&$l|p)9;z`Mk|cAw;4x06dQnDIVTm5OtY`use=TxkZ*5s`0pg-n zGftk_H7898qzrH22o8a8dTOc#bbi;sQ;f#$6}d?o?w=^N*YROFSL%p(L6>$Z?og|v z%HEEu^h1guvDT-WePZ3VbHpde5tq5f@IqP3?VO(l5A|feYrm=Y7W(v}PRt=$flwT} z=rDjpFl8&-Yc@r`$M&*^6TMdW;!*kN%y*8zbx#>|J!Gj<3$fK(b6`zabf4^q`M>Km zOr#T)-Fp4tk=2s%yVnqFCL2nc5Xg~vyh=(^7dKk3pXpA3y3YEVcDf74r2K6-LuiO{ zH%%GO)G#q;eb{No^v7TrMx6LJ%W4om^5k9aU@12Nvx{$`sRWx(75*Ohex2h5w7thZ zA_@U|{+{r|-vBuR-l0S^Hq9NOA|-}&nfg5zWz)lW0e>NW4vR5;)CxxKE<)8V&S?FypJaoo_&*0hj5}(-Gx#qw z5pZl|#%Y9zB^wSAGucSIG5KMt?sfl#+O&1Z z=#{Q!z+PY*H=V^8#*$-sRwJ7!!!p)y26ieam)l{d&DvmP2-hNCgHl%Yjwap!m;24) z2IJD(LRTnLu)(y-GG%!+qH*Ziqve|wyM<7xjZZd=pAL@bvrNcbEPjZ+awhXFET~a! z%|rN1&M$%$%Ccccj%Z?iwXSd+RrL+DLQl#<%EfS$)k)Ca5v@m4$;+hsbsKt&4=LVL^O?(BNDhy+0h0YB z0XL9l)cquoA1L^MAFud7YAJx2Y$BR?mVI2qaU=yC5iV&g?9<%rKPrC4HKv*awY1*@ zoeg{*PZW$I=}2_%d>V~O@U=8xi>pBOdp35OYSy1RPt&^mt%ST%&n0(|GJS;QDD@p% zN;bsr0Si4ul=zyCs_Z?MF4**e|2aVZKUPc^L9fky_-Y!IYvq=pA5Ql$F!(ze@}oNO zx|mPM7L17hv-e*ES&oIFqpy+XX?-Nmz^P3BNfuCOQ@mkH@EiYm-h$e_wwddYD99Wn6}*b+Q;-))02_ThfAx@}>db`&Qj1k!=lm^KB;`kmDxi_UnyQ!*gz%6$j_big`YWw-6Zm2Dy^a#O3nbp5HpXGx$ z*Q=zBz=`U2t0_VeA(LuRQ;GE10nAYCE&>Z#t?fR8KX(nWq??;~o!5JPUOZFF!ctwv zyLM$1Oc1otnz^RCcn)I%Z*8>^$H(XFK?k!o_a>uk2}}tK}L!)>@Zp8C3O}1R<40mGU^$SIV)&f+T_T&=tkT zRNGy-^m9haVv9S?kfe*0Wo(KBjAx2hAg_;xD&0giudt-GU<(}~bW!?%4iPcaSdrl< zM3s9ptxvnef^Y?RaK{h^|ol-!chgNrFTPN?fw`fN(CS%1Xyuq-XFnR52vbw4-!Sz93u znMN-vW}q9AX-1QF6opkX=HL@qNv%8%q!A54nz$tmBV8^OQ??6bTdj_dO=_w(QvVTM zcHQrUPmayA)n^0`#ii0QnNG^Q;@V4NJ?RrqdhEZOrb>mY;jIZ$8HasicNZWwL`0itzr6J#?VOi9zBn)aDT*iF!kX7?D9jGb6VQfq-Xqd{@h2+&9@ z{n#yf?T?3%T3QP4SxahSed-k3*wgdqXTmwBtZBq#S$87Sz52KHE1K2f)>7?wc9jw_ zfTA{qHWJk1oene7%`qV#-e9M6wD{m=ju5)fRF40bLwV%F2V=%IxvO7-b#Wo}XaY6W zLN7DY@ErS!^nQBXw_ej_p`4Jp2A(cZJxLowJ#}Rx8BPR%P?cRMe4Z4_UWQ{mh8P8l z_LF~|+}B5zDL(^gw=l)%_8E)n7dtFh#irtiM^qZ=zgTU2XhVYTmo%AZKIKOmu@DvWq7SO(0M-2FXI^B^6LOCdf?=UnN#<@3!AdEr+4qTcp&7BTa2hfad8Fu*SbV zs}*X{CZ-8Dg8V=1%y>||3X9YX*+J6Kmu@F~S1B#;#S?0VSg?`HhXg%&&WwyGTS4)+ zk$3w=_p|=Jai!Wxu!W`R_U_U!gUyY!8>@WK4*vA6N((sEWfja-Q^jB65!`nsUp(c^ z5@p!392?UIcQen>v@FzmkAItO%*>NC--V$U!bfkv07}*}`B?E;)o6j?Yq!dQsN88X zC7QZo>hXH5i~Bf99p~ahMD}=MpB!E%w*l=!O*>x7&v@&ESd7@s?8ztqQB;$qdMq~& zOC)}-r4l6Za@uYQz1=3yntU!EI8hax{9Mr#yRU$3RoFw;D6c`2UZKudvN-a{cQ)(Z zuBt^ybJ`l@{}ppD2fw^u%I->|asg6znAj((-y3U=&-(Q7WGK%Q*MuS8{p25>wT0by zzM9vJ*dT4@Wl5IT5b6rIH4K_5b#9YKrp7%JNTQC<%@@pY(@n8cVRV`a=+}F=C-;ef zu_zA9Yd|>3MQ}6fY*t(+u+qigd;5OEMH3*KUc`@6*!mGQQ6V$2u%2+ z+fr0JB6A3*z?_>RL#OPaHa)!T;GQJ=s^`@g`}Z~q?Qt(UEz731u9KLVQxDaMD9{>= zK;uUnLo0)9>ezyDY;k7=jw3}ckB*BN2aD|{11Lc3^P;zPm3v`S7==7mA$iQYS0_Uk z%joA*l2KZdKTqqzVg~DW8)>YW@WHAJQT}%RR=upuWd2z2yb1=o&6i`o0&Z13B66%u z8vU8WubWa_q^lb@3V9TNo!;tlmbXNt`7nzjoa=gywY{ISa?42&m?LA0I3j<&;8=X| zv0gwAHfr>aK->n}S)*Y1HHfPtWIOe506(LS6UvXu?Rgq8oskcO`)!17RUnQ6b%Rcc z{Yde;ve*o-na^atyau=Se#>{9meK^b5;}y4$(Z04X?6!GMk>i_iT1R z-b{f;yu7vD6a0SX1hoM&p##%n7oUG7j6{v zy8^o)3BLXN6{6qqG||6`nGG$CaA=4750k-bQ8i!cc={LLBIG)*%WBK$Ze+x9`c4V5 z;fWOC&}Bms%H!CBO!W8c4JPO1fSRO~0%{Z;CRM{7?@Hc@8RN~ZG*!?MI%umaD+?(d zv9O1(5KO44jc75PCVg^`^sa3);YXC4#)MZX&Mo(*7Rc1oJ`c%Kxair`YnMf>NX1R* z95Hnh@)Fu{l}dIlOTSlQ@lq5HcwLYF(ta))JDJb^fM0W~INzsk+)2Lt`}2r#t3!sA zQ&V`M&00@SkS5LW;U@VK0)q|Cq@Qgk%r>|tpdi(I+C-RvU-_4)3z@k3gvW?puQGww ztWr$HLj)89_lN}WKKB4<{j>jh%PG9+n9VNX&{0`VVkS#yWC354)QWO!Lp^GC?sjYrjI7thZ{ zY|aN0LoQhlk-f%)I|n0b1J3IXBOWTOhTi<~C433jHxHyrmB!TTGmqe*n)|Pt0h_<{ ziSmmdaqm4)PGU#!0{Qk^XQME*6}r#90YeXKld5$>>LLDqQ?MOgb9|nTyc=_a6T# z=51X6t7&JdZvgkXv%p0Ln|Nw-x_)W4#&7r49a-mLDIOcC`hp}OQk}V_ECO!Xtt3(j z(rbG9N#mU!oU^Zt((P_v58cS-#Q<+R{N8_U-r{cwZzbyjaigX?KItiTWY|hgvU$nm z+Yt$PMpk&LWKhD*XrBC5XJ@vccMW%w4SW1&0JE5ZO)z7{-Xwnq}85Vm53-hp13Gm>NvEuX0{MP<6 zKaNl&MHRhbv~3zVg4!rCjjI}emKDzbRpDC7JbSa2Ii8y4n$XqL+PL?D1FBUDMsw=i~izya)fV*bob+YS09in$zbc=&w3*LMspbVPhoA z-sR2a@M#!um3^hDmuK{rIU?i7ViV5XAg8gii*&zR%h`4unoKZg@w%TQUK@xtwgm2P zg=#ozC|<@v@>9`BtxEiUMCo)}tHvd{;gJ+R0P**>Ui}2GiRLN3W%pn0N>WRWj?LxX z5Dd0~!dODo)PyAWDyWo|{{t_8(0_~>N*4`1LG279jl9N?Ee6J?BkkC_4%W# z_~tYcTJc(;qPOHDkOzas-S8a9?UV zIK`z7U-Mgxdr$BE`t`Bm1zb9SJ(WnM3ZEvAA0%?al1I&O8u~DdU6G7Zu2GXKx6ji~ z*g4Nkj_ds+i+6r+viI&c{d!dTh6Z?cjTdfAdVRy;TCIitb=I{6P(5aAY3gf#+Ki;d z-6@L^kAk!L#U28>yVJH8V^0%l;)-^S~Fw*3@-fNZF)wbZQ>zD3nFG*xgB5;EmTnp@9`;RX}N3 z)u<0Cu-dDgTpJ~QhXB|H=rPa;J0kaZT3WifO0JJ5!PM`l(~hiTCT2d#K#pY7aDCV36#Habqt`O0(?c)llAnj?@d;KjN#ZPerE);!$Qc zKqsjz(AikQd2ryn>TOS2!d1PMNj=5aXWr)=Qe?irWcHc6d`ur5*T^F%(nYH=DqBF! zXxl`rbsSh5jz>t>^v;%>FpO>X&5aTce)XG`>~+X`<5GWle2}J;;_@gt`2PTL-M_a_ z2KwHQV_bYsE}9TGcy?vqXPR^ATXBkICnjF}XngzT2qK|g%<>KLHOmnqmw`!T3VW1U!*Z9o?M z5}*=VxF=9}tG`ZKQPP&!>8F@Wbyq(Z^ItrTTNXPu$8fd=8RsR?UHKm2@zLMVhKUSb zG6^Mk+?CwWE$T=jsjTonfB}=#YoSb~wLQCqjoFBi!^z^0Jx0n=mCAb7UNtn>#4*~; zAGz4*9BR?zD4sOgoq!6gR4_kaV@1}%W6j$SQU^Ku+O{D*HZrzp9ayzb+j3&(&f4R) zX^SbrFG|zfEunm^Zk4C}f!U^9424u_7&)lKfRV^r8*Hs=&1y>0kM03S9cD>{8zL6h zn`)bs8JB;a**P=kaY*iqio2ksWdMY(0+KAXY6%?t z^tMDTY6Ty8CK=085{^zD$4i_T;o9ANhyF$~dB5+`ylJ9k3hNq_6(fyxYBj3{73=b$ z2?|K(r|Dd-VWvjoOgGe<@Si`2y>rx4XZL>u9@Bh&pR@NY!hGLUdyZmbk_bgrV_{WO z?d5;;3!7xI2sbb7k53Z9cT(+=n-f91_yE1Y;o=)kLtVzSG(jGgw8419d_CM@V= zkIAF%iWzOS=1aQ&0I(RSI+6`@&p{JTZW!s5;vg<7n8@RUm$KhY*|H*O{n2Vx(B2Nz zS^oe$bs+94y8}f+qY~??>`ukp4N2e~NWYDVJoLS0T1dxAdXNPYTco3d-7TxnXKyvs znvtDTzA8}1+)Mnu^0`@2dyBpla&nHSS0YqmC5%O&RxE({R9GUJO6|a6%pcl~qAO7zz87d1@f>>!&?ax%aF027}L zy*e`^RjGx#+S>8OxbkO@JO;?cB5a(9rW%zWw1`KfY8O&zZi|w5vPofL`i5E#iyfO` zF3>kEgPpmJ%N*kS)pcBTB}7?4seY!0%PbstE%Tn;RA@5U9np&e9|TGQ+Mk-%m!IR7 z^&cdIp`oWIPBYZ@ryr$ozic_Tzc&1Iah{}P$7YMmN`Ze3nH&3-yj^uiDtO*kXrho~ zB#+`HJcPs;*3tpV_!L1D5BchCUsE0REeU&5GTj>=k7yj*PvYt7nEIJ%!8Ib}h#(|w zxWvU$VV8o6>R2!YkuyOgs2}#wtc??sud|Y+uIP&ubb4$d==FZx2}gyL#x-S_Bui|A z47?aA=pnD8JpCIp?w;dyQG0h*9|cxQzN2o!JlesRkTQ{wjDY(y*$+|~7g+cP$77&i5{BDuBzW)F|I!t2?&fQ5syqkCu{{V)~+{gUL zk8Y_%RC!Fy%ODFGMp4X+%tI$29fqO8(D<-N%cG+ip|Vkmebba$vCTBcp4of%>EBL5 z)a9viEOr6MDh+4tu-rV>So?Yh1dW7div%>Zr^kNQrHTIHLB1>wdVHfDE@iE@i{BDa zKhqob1Rj|A+T{+s@-Q6T`Oy9bX)Xsw53+HaJJj|91sNtvsU1cuSG{c zHZCP*%Wbt*7e!&Fqh0Fx?R@n%q>>35c(Qfv<8#P7wwtBp?Kr)Rf z(7Oj#KtS?S(rQQ^^al%H+z2PAwWY5o5{&t?a~37lm|I&=F;7~0TH7K&Q<9jmpD(*O z%i+Jxb=-ZvEO>;hBxr{;WcVn|Ood3G&FC$7=Bl{s#-_Yr6&Qvee58JEV%Hazi+o=- zXCmboK_j1WK_pnV%2&f&1gqie!HbUaNTxLLIfaQMbL6HV?O|5KY#3MIRs8xothEAK zY@%hf+S8nJ7sYaZ-9fFbyBd&-QZ0xh8pqrTjAqN`mOXONV}jx}YSc)?I{=>ksK63K zn;xJMLYtbmpH5PXvtnlBImGe6*PrY7I-gVM>OwJ$cJ{xuFS1GPe4V)E>Yi){Y>|~3 znAp^A7RIQeFaSSr_YLjGB%jH$o{pPj_v(+C##JxV9kRR4UygkBUV$Ab=Xbu3ZmTU! zWMoDv@X&P(bFh%(wnUyKb5_6$W^db5Ox8JG7#1Lpl6nYf!*q|P!o8xAE6>`8gTLS| zsv{{z;7Ezz1c&EzV&8&QS8W;Shn*u`T410^gTz2m!pjP4*{u4NswC}oz-FWw(Q(a# zDMZ^?#(pwWpUtd}F%4--RdU=!r}wWEss%ZEk`C&Ie-gg#tabvnMqO;5Vx`|ij-R_yB&=#&(x-I#^!H&|a7Ao2+u|@<2^-6LrD28Gxhya@x z)S8~7TS=qBszFGXR@9=(`B_PghX5g1EwSiK`MB-3kSlpV zaE}tIfIYP?ND)^gl20C>6UR|{pII6sEgXL~uEpcBRauk0bv$;>+pDA^#?6|0tIAN` zZ?=4uYI0=2rbUqCD(+4{Ea+u!I4S+U!&V@TPN4H$XWoRUhM2r8R7%5_HQyGl6*|)) zqZ(a3qG62WY=|Fm8rt!k-xXaQ(+ov()2jtwERWROATxhawM`^dPIV*GrhUy%=rYpV40XRiR=7#;UQd)sqr z#LirnmX+H*?)k!DK03OgYuH7y8gNxfQotTh1P(Um=d6!cDdXu%O*shTC0kY)a@wyK zp0qUd;{y|%irS&J5vT4GJF2M1#r2B+08)FtA7||OnVD0jE?`m(&)1A+0uqHh%gb>k9SqDwU$*=cG!=)+*!i@v^@&h8Rp<4ZIGE+Q({+Y;rgbpqGbKj*Qv zHC*+Vt*Z^PoMjl2#FC{cNvy^nYx^GCEX}(5UYBH}7_fzfZruj^*WG_5e&u!Z-+b?V zqq1YV@oyRU@kH#$Q5E2U-;$GZ;Kguljj{XVDovvSm)oIgmqgm6{Vmdn9gbILt^D~aT9@8IRl^3}Qkmz1~ePV|1|S=GLyM@~`QJxOk4ewawAy|{`00IoCE+t@pTq)Fzx zeOXQF&0|FyFtyl#8owXNzL@ExsND;_ve~C7-Cj$Osn`_kb&;yE4YH!zyN#T7X}`ul z88wd2nAm~CBQeS=OKjI{R45?Us>kGCu)ReJx6`a*BxfdFiS}*5>lLG$~G%c)Eb(Soa$k#n)b1T^GUpP;&F4VE+J{&2?fd zm|$4$Ws}IHZR0L&kE*gBLnj0kKNc#99eY#Mno$_eNLF@}qYZAAj!t9en>y(gtXL|K&)cI^waEy^x$kJ#$a%htkdPRB(l#UpA}l(^WPYnJ&ud~$k1YBP?kqFoU* z_NiEukc?%0wyxJMPM@)mF&66OD2S+(Fh}RN?k84TEnXnsVWN+|s&K~#=+x3~uYUN>K5VPACU4<9+`{lvIt^L9c#!a0T4YbO7NXZ&fNS&D z4PQ;YA-_sV{{ZOxmu)m2TAXtcq-Echy~yTu&%>9@AwE>w~+X+%yV5;Hr| z(4QPgy6Q}ycRZrECi<+&W~|)*0QB9h_^dgqx_nnr>*|^XM3kh_ag3B6A|cuPn!eq~ zuisI_D&q{Ci4Lk-I4DxIl1Q<{zT8?9sOMmzxfRr!@HFr1$<@H=lWy}{Y!>n^aQW&@ zImesT-MK5;E6Q!6Ri13K=FWo0kD-V%q9VYMGepfiZdq8IgYRNV8Ppv{y8wR`)Pyws zLdlIrHGqUT#Z_GMn`-MT-%mpkXZ09&+U;drzj7S-y62-zk+vH{ZqFMDOOv#*f)Qj` z*25UcBCU@+QTP|>>FPour!9xLq!wO1z?A2|$3r-plio=m5lU>s_Zje3BmH`Gfr_R)=t|d#5#LINDu~L=KafRHY;u<2GH@ zIkEUYJM}JWW3xx$ViiSEqii@uV54;)(Pj7yt3+{jgmk2C-#J-G%Ne?&MN@wc3oD|I z=z>pbe=)YI`z>e9`NHr6FuZat4S-+3BFF>v|P7>4^e+oAz?<7mj z{AcGk)1uCMsgK>cl@Dyun!Bs2yqsig>SZbx7g&UTP9F;QuDd1<1wmN$Y02SG(?Y=<8s z@dqWGubw>4MPlJ#(qMsbTpyWtcZ)q8$6RQd zjR}m?$seNmi-Gq9F02ZHOGOCctn*z{)>!!-?p9yA)D>eV(81=3CcLg zGYUB^1Ut28`@Ykw%LHnp$uy*EusbS+KDK~rEk!eMR4L_$2c;6z3cXn${{U}NN&O}5 zc;h$Uw_f`2-4N7LoNi>>ecSx;hU$l*Sy4ceB<$ul4^g9yt@a_#v}`am8pgD5?yj?^ zsBVzzYE~VrPhi**ltT-Sa8c2opsr9vb=Z~*doxi4>POGX+}f=Idgx5w z@A{Tr&6{uMb}d?rtr~IXrohyUfKP@XVH{w|-uX}H4qQMdAwg7;!*FcS=VwwsI*>RA z=CuToW`U~dZjPRmRjAoU* z_Il27fR`xDCzfVKLa?zb0;`ax*z9Z`NNKcc=j0XMDoO4*i1nzcm#~A4!N>OvCOM#TdQ;6PMd-neTH$6-KqTVAZ-Iy<^j3E^n z3-WB0C5iUtje;wr64QY#Jt@rt`KF=%y}j#}%Ee)`iEbE{9@1rVXAxh|YCH#C6BPVc ziqt#*0C43F;fAcstq-_>4gN^!k%sKc& zf5%;KtURFyHS zsL?3J@59~a4JcJ#RgOFgJZ=j{jLu58Bm}Z6S^<^0ue!gIZF8@>Q719JKGL~vP2VM! zmu2(st+qb))pq-567LwRtIcqB>Jg5Zq(u;ri4mD1)j8ghNKCsUMIHf$FYb zP9JofgBj3e`=Uj$@Da{$qSMwTEz^@13KR>I?UZqO??>%jPZ^PB-dGhB4U^RHv;ZtY zQDg!)0G0T&@+gj&B#s=(krsLWQw}>=UyACltD=NRipaJsYp^aN*nH*SrRr?A8|=~g zdlhKN^k|48l#k03vaxF*fJNU#X{Mnq`gFM%$~9N}e%~DR*h(2nsWy=@7ZEr|1!MJ4 zg;~`ZJ6>jXuJB6&2?H55a#Vr^h1BW@t^qfDD777F(;COrh<2CTeB<%|0L$p(>H(s5 z+9N4Nmzz=J7)yNR>7NrH!2-lkkU&zh0-mvO!L!l>J4% zURpzn3tF!ICQ^=}zfCtrE!tx=fC61P=Qa)izAiEfmDLfJKY_BS9Q~?((6qpV#{u{U zpo0WWOT0^9HHFYs3%cU_f%Nr)R}EL@_aswdvX!*TL` zKmeORAOctQ;dT)(zMPM#xAh+P{j;CwtC_dmdrYag3bN%ZS}w8N=c=Eut^U`E!QzlF zu>@K60O|*+2VlhTM?or*M^AX$a+4L4i^N5Kc`?)dJoP6pa@C&brrRj-+@myO?&yvr zW=LF>EgFw@Dpo2jZL{8mMco1e8aG3$K7zoEw>fuiBS`r;X$r%4OhD?5X~rNYHG0jzQk+j|P2thPGzG<4!IB^kv&*xY$4tn7bg z&J4oq3PuQ0)TI{U<1w@P8Ix~&=y6~zV-BGJCyj#=14v6C3|Mk+pX2d;G8#HjsY()o zd^wHR<34hojGZ@5F?rP_cZ8)E^S9cOr}?e(^1S(S#>NtcNghy-Eou=NSjWQyvj79Q z6b0-_vuxCaXA(q5y^Jq7<+|~a_-?w>j)sW_Usf>MM#dtiij0-AvAWaq)VT05lUUS9 zv6gm_kV>;XDuME8L6NO_H%Ivh!YpOFqMgwH0CFwk9NCv{dSs=gD08|SWoapb9gy>W zPSNvr=fd4%X1#*5t=`T>3OrW8uE3Bh)DK(f9>_=|2+CZp^o3VphClho9Z4N|LWmU~ znNK2ETUW`KpR~_GPiz?S?18iOFQ%Pxc2rQ9fC zYC};38vg*hJx!^%>Z={pPzhYv6&zm_$ZHv{lQ~G1$Y6mhkJKeD59jBfw{Tq)XRluZ zXiNBZ@s=Tx^(s}#0EHwF7ML+pumlimppyZ2#nJ$5S%BrvK>T(N{Tww0qRPFcjSBt; zwsHPn-=Y1?2;xL=;e^Yw`1XviJFJC`0P5p)1&eV)#r2!&<>{wvB`H{@q#-E5Yx(On z+ZfL!^joCn6S&D_ZX{x>622_)S8f{VdT{}Q9CGes+(#){I0I5(906gZT~5}z06u1)D2_cpHu6u0+XMo+bDnt=AjbxG42SfC7ya$=dN z761|eHl=HCN+C|9Q+$3BkPm%sE8Ds>DaPqBr-ulBc1u!n%kc-hMqAprP6Ldf`|Mrsg#iCiRZdCn<(XBfv#BOYoSmc|g3 z-dt`##$RuqyKG3Qn`VqDa)iyOY6H-#YCa7fO#{H=rX-7C=rXV6lP*^d!9QcR2Q*Ta zq-@iaCOO?HH*`MTw=9N#%)}}<=_kDBF3%GJ=gAzNU6oWHW)Xl*lAy3!{^9uRH(OI$ zGWS9xp5r$a$r3#H+z0mR{{T&+uI=1L3S^d}xx8d{@l=>I6Nfo>)LqXFp_X4Oqbiby zCIqPl)pn{;c14>cRsK4MTU&bOQ$a51A29^u0;TiCb*-bJI8HS@9_A8#yjO3B8>;c~ zf6t%%Mtxb_`?g1A`XU1(=Xd<M4eUz z2JP1zO76C$b{lO+ih9$V9T)^BHJ&m64+TX0RsR4fo_f>1jEA-TJ@mXCj}O5Z?U=eu zWORjPRoF|A+qm^|{!-2OWuxoVo~zY;Mr4gffC2=`UTLOMOZOO#(8#sbUX#&FO=b*b zB$n;)vd-M+92NPc>l*%~f8r;yeKQtkY5IJBuJ?3b(@Efa?YJ{+tcCJavt+Oq3~&)+ z(6|GnXnG%0>f3aUJv19YlU8w!xG#hHomH>ubbSnWYObuK_P|DVc9;MvmHl}yubAQN zU(}E4w{acQze@4;$J%(#NI1B-@sJb@95n>FWInGYk|>w{?zAL&AMof^%Ti!9dx>Sc zjB4WdFAt8`y56(=NBl}*2>mS#$A;7LNPOW!zIys2=%4BT0Mj2yM7arv9!GHzm0aAz z<(*x?+FX7DLqHUz1weZ@ch+?O0K|2@M(Tw0q7S+nX4e)AH-XQ0ABCq!{1-=bH8mlt zDf!bjg}OKZphZ7`UOf-^)V%O z60Nt+D+ON{US7uTj*N6lBB6D0i&f-{k31Y;zPiB4%gM=&yo3F}Wc5% z(<6{nhCgzCN5CVhA-V-=vY5TMF%hmdUJn@_^mX5(8AO`}g4t41%v~t>O9Ri#pKb5( zL-tI@kMm)wmtV3~Y0jlPt%{UKL2Bjnohu z;fRynLHJh$8UpUokJOQ~aD+M8E5~ipL!XB(4tmA)K8ei!p|SS_VWt_uoFRSj-A>(X zy_3B|Bw##@WCc8>q-e(t=hpO&KrkgU))%m!q6vDMk`Ec#LyR8LRR6{{1?3kEjt4211%B4Wk-x z>+7g+LAM~DK~gsUD?%QwV3MAk_?FoPNOB7Wi;ftsYVbX0YU!fxi&xqRiQG8+nS1o# zjon0m0z*=7LsQ5ngG?yv$s`ajgLTxpn(&h*I$ue*^~EKO_B&kz*}kPT%OM!d8*h1& zJl(B!!C5*W(;$et3K9T70j<;vzw@uj!d!SI)E-%;GAL=e8d-=H+KI3VUf^8 zWiK?y6QAn%zG(OkhsiLI%d}>N9!XX$&9XQLdte9vYtO%4Cpg84x;Y)pO}KCQs8GUl zj$WEZF*u6%`!cwAwEqBqjPw#L`6sx{azv5pH3ePVfW%0Iaqy~6!GAVI_3z?p545O? zy1JM}7YTRZ1Bag8BN{hs3u-b__%U2QZ@PBqgLi3TSe7SX4+J%Uq()e?mDv8<(JC*G zRV0fK(>BeON&^`O(gc)@h1`Fy>B89c-=;E%Y%@u_bgK)1Qvxg^om)P3g3 z3K_mu!)$$TfM}8l09U80sU^(hU>Cw7rF~cm@4tlb1oH0X^t}LrJ%qaZVcAotXl{R`P(Sat+9Z7Fy z@)Z|kFZ?z93$wu%1^|S6)u$Ao&?oPduT5&D5NIe=m+tW|g72z*`SRN{69mZSOhS@m4>8bYWB~CdfSA$o zpk~>LJhiaobctw_j@_`qd#hV^JD@)UW_&u- zO#I@T#rZr}YxAf`<(9b=hh4Z(d7uxlRwad-c$Fa>4fb$K@+MCNkC9 zM{b_o?a7-N9G>9?!&D-3T?|nygb3O}5nWlmIC2@qsoK12T>eSB0G^rY^w~pm7-`YC z%+1?#n9iJG!iA??lPKPu#8(L8{huv1K343lDoE8C+>f|O%npZvbQoA>1l^J-d~3H< z$89p-JUOU=e9+3u{`c26MnXzVvsj#Vo_)@H-hO-YBIDSQki?Bpu>=r7;D!5!#B1_w zh9{Z<@YS2cHXJQnww_K7^+-S2>}JR8B`~UFn|?t7;~BTX$5tYaF!$q(x%MdHiHz|> zgQvG9#=uY>q>;_~fXj^K4Xus){Nk`+%hEM9Qc{$ejXOw2aksy_iY(kGemWu}#zNZ0 zJc}AB-PEXNK0#4~uG|v9EmEIr={mlkN9qHcWI|D19$%a4cUCf4N;b;{7h_}1J*nVn z%?DCP7-HKn9PF*520q8`TL5yP*rggZnr@OX<~o!&?VU4wRWy&09CMuY?a-GK9?V^` zZo6%1OV6JkI?PhBNMlt6oS-0)%d&YHX|9EzVki(V`755OryF8p+q%rX_*6KyRsGJr zrs=LdfILROIBUl@UNO*8$u`bkhf=g%gYEzVnu4hOYCp8?@J(lHdWmgirxF<3xLwuF zBZR!<`Hxgy)Y`kS;r7-nroGA9(>I=^$9SSA&?CgnB&Dt6Wpbi|?L-qm+X83;Dy}$d zZxd9Mp4T;$So38UYhm|CG^RqGu_VFv{{S}XH(|Ev&81h1+thJ7j^blhkgADSc;tQw zA=L;CrpH?rcpju09ULR|FK(Ri+jTACfw#+M3in;~Fofz|>vkgLJ|kuP^T2b}+}z}W z+Zst^SCSxLUqCE+g*H8PU=6VfO{d7|6HPr*CYc=C>RsalNW`(nXP%adCjnRX?#DJa z`vd(Rslc+3T1I`<8J0l$+L5d5EXHV-BFOC$;^fXnC_-?RQgb4(WH|6AK*~g` zu~+sqV%}B7;~lyqjWi^x0_;^3HztIdg-Ug%I~yFZ16C)CJyRcXA|$l?+~c_TC}TLu zt0inw@D21j+HF|MBS|CkRf%zq8@%2rEVpouIi!NL9xd68(xtksH5y}PfNBJ655Vdl zQ7=&me-l-VE-{P|N#1R_8-M#AFSYcQsL4pE=L|#`iq)L1f8;tvfn$mgn}%nlvaW&k z0DZ+*)Qbwue$*&%dfd?0*>RZ`S@#5`ruqA}s~%zun!_%&WuqoIBS6z4kUv#!{`+hz zIXaX&MhZJIELZ~@DFTS49ED=6%n3FDC-d#sWvoemiq+$Yk2oVG3jY8pb$7>IH(3I4 zJ=;C{@w>=u|vTjT)iQ{!u{lZH8@EC3DM${Xkz;HTbHEurr zHRCaii9NBjr?=d3!1OTFhUaW!F64_(EtQY_pPM?espDBBQhk(eSv#e6G`%o})PCQmz%5i)!JUfEb^+ zsoU%!OKiY{e?0Uti+iK$FohdLq0Zg5OK?_9H=5~~-;}g>QX-&YII7Pb^7VW|V1h(g z_CUJs8-QHU3JCTZin|~c`5zrpLvZ^BHHAKDzT?`Hj>kxKBW(bURBWkLj?1Rsma-jw zTz6#hNYu0uZPn%|5c*S_G+6mQ(`VMWsibU>n_^jqy1jzy@Rj>?o$`5#)VDGwM9J>< z)qhO+yDQ1zGN1%#L}-Yp95E^xM#450wA}irTOYx?%am_sBv$CcIILFbHx>BLbEkTJ zO)WCrIXv#cD(B!_V~kZ_p8o(w;wZLub~UdjR#UAj7UyAP6IR8qkU3;n>6zohzZ_+a zTjTe<*G+`ImSTr<9b5{{TUfUNP}TE2-T*4O@{Td(PSN zc6b=`#BbvIJ11~o2@+y<*_<*+{{Z=RMsY^ejCr60H#-4F!JsRa&sfXORg3B@-TWRjN~Zyf}axZ{VKRqXgoz@q`??p`IMQXoN- z>aC#Uu^@a^gVb)dyWKBO{!&uq_yXf&oV3x3I)D8ns@6=Kqoo6L{M){qg-+lf z<*p=N@Qo-D;P$*(*|_mRB+@D|vRn02&g?~#e<6j?6b*Vhv(!mOI$BN8MjCEk2I;lV zd-w1jpZI>5Ca0>_mD)4ZgksbDx_WwMD!sO1ta!HVCQ8U=own54kmA&A(d!g{w4und zs-OZ!_s3QH=X>dtTM&k$kBy|FpOJX@>&}dH&AM88XaSi4Yxgo)ZX^j2Oxw>@q@5H6 zWA4r&O+!-^QCqgW5CV!~pzs&*O}W<4+_YN+iHf>1{O}c?a+zuB%JzLQtn88n8@q{~ z?*>15>5nw*>cSL^?Wv6IDGh3d{Zv=whspkW^~@7dWOoDE;3aiY?I9$+ucgxsvxB86 z3jYAO3prK}O}DUP%2)t;t#QQ~qDI51wKhlH zR}tghM&Gr4*@&6iUMM<7rlg|Ci>X+}q5U=$kC*y&K4vf_3aBTA0LXnyJpe~7sJk>& zd<*F_k+~taOXP&4Nxn$aS-1I)0-TQVkGpjqZa)t_ufNVXuB(2PRgo17xzTHrz*1R_ z^2%6)#~gh8beZm|-zT}Z+BtDdVmK?w&!Z2tf&Wi8Y+zvtSu&MvW>=e_ml%;pSaj|G(xD7AOFUJ!WYUI0i~ z7Ij8qr4>{!+Q*W%J&&mb{tqC6EmD+;Nnxoa5lJo^yhg7!Cq6nOPEr;{KN1Yr?eW{O z*HSt!yo55J!BEZZW{)jT%L@Kjac87Dk(OgQMs0*7H@p2Q6M+0EHPD)I+*DlmqEYdC zqxT)T=ZoW|&fo`%cU!V{VhaikJxL%nx7+v?M#W!1$J9K}Ool%AK)1VcmP5YY?FG_Q zNP|&MYwiK!%B#oxmEWa>1T1?h7Iz{>6u%8>$P}O~fk((t4#W<6UZl-Ad$lXucN=2J z;Rv9dIpd1!x|)jwjEKl2?IcR~EjD7fx=YULB3wD9OovnYVxl#D=8cnkbYvq%`x{oW zK)N7&n;Ck)Q(sXbrfSB_k<(*;KT~V-d=<_srRf@xj^;9Cwf_KfPi_2-HU9n_bTOt7 z$8de|#=d1>c5uF>RN8=9K_i7EkO}6<&@33lM>}JW{^;CH_z-qSb<+5D2h3Z1oSO?~I4^?w+J>ztbA| z`>OBp(HcZijCBbaHp+EY-s%^R)0o$e47<2z$11qUV3#jGG6+R`FtsqYR9OW8Nwpwd z*IzlW>WGYIIh7|6)Z0y1=OtDp@*#^hbhP9IjnRFr$gyPkWqdbvjyoNE^YzAK_S`JI z#L9*a+Y-&?EkFjxjz^M0&UIB0qch*+Em%E8Em<^a>Jw$mR^_@@(jS$9@GqTAX5Tq&x zu>?spg+XeojRnz&>9J)RXLFMk$tg8gPIBKrgg&d%>T4Qqr_+oToNn(Q5tsM*PnyTP z{{T||0Id0wVRo!_?461^ia3D&lN4gVq-~Ru`pKIi*O=6W_!`$z$I*HZL;QVTQ>Upm zS4`PRYcv#bZymeUb!5N9XRTTui$YMcKg4RRvM8J#!T&dw|ET| z&p3^t1Ty&>9tJ+l2=-;`*Kxff202Z2H&am zeM+-iV<#KGmFL@K-*!!O%LYSW2Z~jtb&@b0SQz64#9p+)M~ICVpWpx}^^?1G{au=x zi2J0den^eAU9;Bwv>_5OgfxaBL}I*Q%~l@@*H-&ZO7|6>QZ`6Dkbdoe8Aq^C^t2Y( zkN_840($12q@yjSz%T_>@so?}WiGEhc3)pgL_&6nYXm5t9{++M=TSxbk-3Z&YAH#Q$FYuyxWxOm$ZK`xhk-3lNB8jc*I~#$6q_I=vnF%?TE<4KT+ORv^}#}^VGeI>XF@hi>k~20NWVW6!Kk@{@{~Ey0R20 z3|XwO?R}Yv%5HBB#wAr`bDhVOH|RT{hY3|> zDCRVOSpljVol%C$7nWrPj~7+f&>FfLI%e4D%4}Tik+!q?V#jy#`0?ENKT)A5>OIWg z@anr~xlL2FZl66L?ETtIi4|0Cs1&oiDQACHzny86xS~%WH_7RGey>we+apacvPSu< z+(y?Q>{cotQKZGVg3x=4v%LXt=2d5I<8pV!TZlZ0Rbx}Eg>Jd3y5t}}qWSoudL~G% zL4vkW`)%T1Z#Y}rBSsF7Pe9wgT6>7&m`IGP#_O+?ul8-j-G)qt7|U%MnIzw4(He@g znpU#(oDv4WSIIt(xJsq;;+O8Zu`4~-?F-|Zd{DZ23>Hz_?ta_TbH*#1WBIh@{tHV|`h}T}h-lS)uV-(a&#t1BZm;yltz$2b6KmFCy^o?0vOJrq_ zwI!ZOX303VHX~h{r|3j#Qfm2>ifQnI`KF`CCq^Oe>WDV+HpbP{QUgCBMFpTu^Fo(v z>b)_Hh{c(3`-sS$-(qr=mw4OC1!J!|dMtgZIE1X-6U9__B4=~Els}X@6_b`Gc4BL0 zAq_6Pd#!!8stHxHzTBH`MITgf>N=Rrh8NGa-@K}R(ysgCqSJ{J+R82>l^T{g@1L8j zapsATI|_u^wN?xQDKeJboA_W9dXhd(^jdM1#zwO!$KFFzOuD9qQchk>VQ=O2I#N<= zH7Mu$SoZB+e=w_tnCiErfC5WXC?o)lN<(^-wiXtMv(u%iJ=7=D?=7Sw6P>2#E%@zO z=BCw*nEPMEa~XDQQx=|Y@zvPpjY%?Usut)xav?NI>?ygjMScYyh1Aj&bmgmo_Iu<4 z-Gq)xrt9(4zfM9dWoB)gLC4&dx1GLt=&mMCEOH6lsE-OGG=z#t88y;22FNcnAPhJl zwI9z+lczZDAvi$dH!Z;PnbvED{AA0~>cXKEgKAy_8(%nYzkb+U4TmCGa;BRojiqPKjmFxv7)cUPQ|0Oh*DUCx~F(LzV%DDrIK^#xgv+^1S1$Zk2H zgMnQ-%iQw+0QyHb#fgOSQN!`pVl0_LG(^K1NQHkYfb&P3_~>N#Mp?;4v%7QK;6ww~+bIX-@0yrRon%|jM)Uq9yaDn;nD zSmj~?%wyM6s|^JKho^*rS~#!`_KN@_Xm zdq(Kv#|K=LEh1VdZZ<1h7rqppJ#N(deBJTXTAK1^lG?xkltG&Eh-J<=agL*vG)gNk zBO!s?wc|e?I=uuI=~0R!g3w^A#DLWyymz5BG6lFLV-6JVJ3CP@fc80)ZMzVs9TFHrpZ zassWE3Qt29VlmXx*w+$bypi^*r+ca;Z;pu8+ScjC%$27#l8`v&>e_mVWIw6Jp8T&2 za*2F&f>m^M21~I+l9d3XKwQ6Jo7GJ#bPl`?+Z2!<-O`6S{z)zpjCZwbrpM_^JKWv- z4s7p#8Nu6wuhkY)861x+q-^p&-XM(`2&%!EM&E)sZ~p){UelB$`}Zz3=0t8-m%37g z&>2%XagK&jgi0cV6lz}Nc-o|lHuL@OqiT`No)I8)0LAb-&&eX zVFpsvVPg~cg1m7eRko`PyWeN2H6tjZZ%2;G7n6@3IM3p&IE^2d#)^eh$XGQf+<=N> z=aFUUo7YgpYCt~vi3jQH@5}Agj9xrTe5`R_zg*uQ?%oTPQh5IWbDs1a3+@t1$vR43 zc;YMu>ePy-hFiO59;BT>Dga(bS=!Rn)c*kLig_b2Jnk`1_Hn`2WeBxIr<#gKzJG5y z_h-HEE(~boP;J3*%*+s-fj*@TsH?7c0D*O2b@W7`DA^eSY-}PvToriANh{~A87&c$ z7Vg$8yJbRFBSu=PqRQ%qd3<1~4$ZYFR3lJ>kuhV(UMmlbbITT7Tg}&kprDiyPs9k<9rChG9BjEKkJyAJ7Q&FC1vQey;afG88ImN2i^uOsx>BW@gDDiSCOp;UG&b5aBp_?o7W5G@3>q-I-8@E^pOHASwH3GM`R9ELqE0(TRTi zn^$aOC0uPHAPw%6b9@(lFox#@Bwy%De|K%y7fAA9zMx$Arinn2l&NDNRvykmwt|T) zHeFZ$0Fo}xU1cpnSwwOF0B&H961M{v`DihNgccIqGi1Sy=0c6pl0%+zjw`D%2X7gP zruJqdd(?()pW2CDIs7YDymi7_5|l?(H4LK4H@5r6K>q;8ZjmjTa(1MnhN@FbE}LFz zth|}5bpz)#b1KI`Fd>wc*fz>`48T>ey0r{`4IXIzBJL#(oRa#}WOHSEqc4NG+S}>6 zaFmCL-xRSvGRN-lf6q*K>keFO82hz8gre9ZPzV+HTi})t{Em8W{m5=u$%_4^^W-oA zO%?KV3q3Hn>RpAwf_yEOce=VfewML1@RZTVcrC z@vp%w2;}wY#&Dqeds}Ud*TIx-xg6seuALa|Dwz%_(rCrq#?L0x@;AQCKt?83m^>Po%E{o8lKHInHThwZN6E}gqlBf2=gSdlLhasI`4Ip*qvuGVG{9jxPip80AlOU3Ak@NfJgH zNh?+684U1ZN?nIT@tN9o3L_*l8Co?q5QQ>O=x3gLK_YRV?mo?qX=V= zs2uU-M$726H6t96faTl**JO)SRuk@^X}+2gJ=Gg$G^uPaQl`B~R;^e96oKeDCy)l_ zl;b1c7?J{jiCN{MpV%`^;>jIIOEHXRC8nHZb5>sq!<9<6uQQBd88Ra@(J?HcOB)|> zswU0TF!=?4@22kLmQeQ7x8pAF72mdebeL*Ga|u~*H&Hf}G<%Ef=O$~b_$bd5Y#pRo zBaOjIT2c#9EQE(sVbuJA$N5&ISev0a&Fvh@rSY2W!)JG%r;tK;ZK?)Rxn~u2OAXst z?T)Roe$s}r0KHa&Yz3{@ARc)n1INwr(S(THq1zm`{C@4&ag&~xs>)49Q6BW)9jdta zR-EFFtl_7QBW=q9%6&qyZZv*C7PbM@092O$05WQ7q@u{2_P51V_xa+#Po8@4>JQr| zzq+rn$yN>Gy5>xDE>RO!Mn0q8ZZ@z$Ekts7pw-Y+wH?uxrZN>LYx_yOV!yWsO*N-Y z(pCvL8%qXMzmzYLdWqnDfL+%3Qe$v!NC)l-Lct^xM}vQkj}2~Ry8i%FXQv~zmnjd) zT)zR(k{e~WX-gQHdogiQX>)g;9#|)d)T=l^LNRIrhZJ_Z<$|`Xr2NtRbuO-txY{wJ znGAXEFvYGLi%)#tP14%N;|RGzt)AY)5bb7ZQ>Fabcajic6C{!oBkit%6clfRWVI*? zNw#a^x?B%riA}h_{ZdjKadcxpcN}M)sE(Z7uNNv|lA5}-Ip@d2*9n+eNLbliOXHJz zWma_rC?}Wv?m=1t&$V@psOoQ&bpDea(f3;#FE)cC!WX%F9dV4KDK!B7F49tbgF#)w zBKEN2hGHy_suo2j*!-yu#3(9i>XJwd6e%T$EEtV15)3aln# za0|oS&N@k{30t;M!R>Nga(91uQ1*>_ZK9S|v*bW9!9lRDZ?OlS(09 zPD)xul%6?Q%LDgGPHTgp_U_#cUuugPG85pe7{7HMdtoapC&M8UF?D6TRET;Dwb@8F z@vj$LizkWMK#h^y(~aAPs`5nf#kG%)wKO#+7_|wiWF7l}t>)p0+U{9y>m4HfLEV)I zA|?Q6tQIi#v_RWav1Y%?Gyoqo23M-o)T)eiBJ;VH=!N49v!3l8u}jvcr<15ui8FB> z#AG*~Ml4$WE^D5?Z~m-*R=$<`9}$~BzsDY6hDU?8;KbRP^T}I8jT)VxUJC6YK%ln` zL#&-m(!^u+mx%_PcAVhc-Z^dVm3?h`Z5>#Q^@u}GF~#Y-mdcH8YZh_%GuQK5`nCOZ z`qTP@hQCYwFN=}e@xGzTkF?`rA(Cv|)0H=go_V=~6>lOWnlh@d-be)XXQT8njEzlg zXp{L8ojK+%MCD~Fk@6 zoaTT<$wwu3m-nlyGINacKOD&I$D zM5mq_`0C9@5!#VlJDV}?=9K*4ANT2Q9EhTjcDR|-$s12Rip&9*ZB6LPHCV}5z_Q#D z4;@#h7|J=7z9ks4X|_>YyyYu_$ZBykn_?@M|A0B_%_9mfG56v2+yDi@ij zk?hIGDirXP7MofpgSF7=ucB$OoylCAVG^6~BJS+uJ63VmhGp>A6(vUO!ZqUq^U{BB z?lR(LIy9wX)QVz0@5-fC%rzl_XH4>nKQ#8C=KBjavGd+8}_tEpU9{k`5` zcso}WgzKpyNeNT>nXsPb@k?)fCfARXqTfw-Y;VzIxx;-=tqofeB+`~laoh!qZ}hHc?a}Of{Ft&~bjT$l zWo9CZdYXF-2yu2RU%gl$Nvrhs?&(+Y| zFR@!~BoX;+Y3+)5`01iQtfI#3xL^k@1WO)4oT06KSZtt3)K_&pmH=4buTI#`GTjY| zI5&Mx*9w~s)bU?^#UFvXvmLt0_4^|UxL`&_ENU%ZX5SsN@I8Hz z`p+y__>wsiH+U-NeJEgf=&+X@$|mYgCG||| z(1*4$DmS0hBXnJNyxY>ghOV3>Zk91A5i)1C?3}0C)eZDl8Dmi<&aAe?NwKmG9%)-v z+N)lF@8sxc?9-4>>S_aLuuMJdFD?qsDd`_c)P1(S-O`RYyKy7p@3F>xl`JxbjG};4 z7XihU3P!4H+?%c#U5hknH?rNQw5#_U;*oPzYL$FOx#JH;`g$V7+SBh!x4t-)_RXAE zcZOyu`;w?-P_02gy++_EAkYTu;GeR&w;QffKAg7&vxZcz@__#U&2V-KAx`KOLB2-` z%S>K(7mzP49S)l_##t^+Kzd-n2HurH)E#R;Kp&g_IP|5cNC;`|l%leY(y_Xb?IO4K z%Z_gPd?6HFjbYuU#w`bnH)Z>?;=7-*G7*J?6OtN5aXaq7ux4$I4apn=I2%=8RcXwh zvU{UMzQB;JVx-HG?+6!`#Gh6=Qk_e5E+CqcL=1wM7K#fb=J~6iszInK$W=oVxU}D9 z0d@qt{j2#r*B>G9G-s)@8)C%48Z-WB0GHUdgzwP4or4{SfeB(r-x%)uQuJfNb(u9c$i~LsCJj zIYUmtsj(#GQXrRiRPhryI=|598d`3qq(bv+A9v>G#doKg@zE??In@-)JdZIBL0wod z3S9c4xkbApnk+#6deM%qoDw0VGCjo9%_xa5=OzqwR;Ic3>FLIg)gNq(2+M0OPRv2& zyRMG*wUJrYbuG5Vm^C7WI)vm9--ZFNpPp<6YYy9u>L2CPWfIE)r8w^@`17CYCt})5 zu{g>7Hnm-)jNyKIdxH))iP%UH*y^fTos_ci$0pQ*Koki8Spam4-KKMh)`YLei-lsM;J_SAIH(ecxE&|ywVyY?P@yS z!HpXr2H;uttwt9VgiN0J*Mz8noV16=FQAmu+qFSa7~V16E4R-*sOU(Ue1)0m2rf7S z$3cKM__i9FV%vTO$E^3&>C1CElN^5)O|&i0S8EKbol45&~)oinp9l{Q2p8nW0jeH;o=< zW|A|lg>tM(RXUPNh}N57U>hK=a@2sz3&PYkkmrk(Ni7|>d?mE)r`aMxTA)+dE_kt<`iE&|abIfgcX@q(65h&xzewLK8sjzTtW4hOlLB43@?cgz; z4{ca~Q7mPo$d7OegDJXVgq^o44VANXV~`I__A%Wt5&NS(u?ye~Vzd2D!8Kv6_+8M zNJU1akC`M;{>pZ+%R_)qCen(mwQq*|Xaa*G4vX32zy}2kE0+bI) z+%S=t<2l3qB+zhCkLa&S=$aVBrY-!B!s^~Ti|taw(NuzXB-+;t)|4es2*y%nN|0mu z`HN!Nl23!XAugg9`AM6`bMgTy0DyKr*YeIS8PbmLN#eC_R-Hh3jI2!V#_4|0Hb$5 zvaE-~+6EQ?AAJHz4M9P!P4vlWnw08Nr5{c@cU-%-Q*WMsJxS`fF&#Y;c+a*+CTJ*+ zyUNvc+knu?8>?lRKeaU^5#vv416H=7S6q^#=cU8wX-SO9-b4Q7^MRt4@!E%%sN<@H zNyO80_A4*NjRtd%%fr=NgosKPf~%_Ut%3m9lj=4c06DMZSsgb^)Ly9=l7tKQJBZ5p z%uX@q3E4WYNhx=Y_{DtH^7CeItN4xMn6`}33-pYyt1A!)4ja_pKOf*8uKLdAFw&f& z{;0m(nehJrdhKC-6A0#Kx~i9PNR?`|1voQ#>fTBR+E5$Tt7SG3f!u{4f&-c=+?zM> zI`nk5E~f3IvPN)%31#rz{IpgsvduR3$6+LSj^>_Ta28?B(plV5$U(4a6dPvos;dA6 z*RcSEU_MXB1M+%*{YIEpwEfkBF?PI^6fQZSuIEJ(JKK!OF;(AY-W}Bxj&l@wtLk3f zE=FHHEwqR=wr~|>Ct@|CKol$$t0M2B(b+YV5)tgR$%xVa0Lojgn8Go-${1UXXBD58 z?0e&bt9diy7x4#?=3vE9ffpGT*Xu-&hStfWOYzk%jPWRj)Z!l5QF-ROv{hmZ{!=1>ZrGdn&9y;iR_E>_7T^a#BysA-na!VM8s8r^bzG6vUfG#|J^0jq zDT;pnIOKZo(YVtYGP=PX^-5dVwaJ&Ukm}TVDuukt$g=DcKuUtVzpD>#B9$bM_|Utq zktb!bHl@{|cI;fQ9xKnz9=s)|EJTW0+AOo0pvh$w_~^bKR1hmhj1y@2JaOdOgDDkE zYoD6f3L~V$URm7NH?mxfwPKXnj!)%!RA(915HJf*oFeXe=&nkzjwOGoNEY>IKdGuz(# zCxFgB99oMyV3s5(#aUiOeLZT<�!deLx@@A&=pISR0WepKwS}af@!=Esi&IU-ap5 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%0DIDYFQ#9nT38T0{_Fak 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 z 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%0D-Av*U?MnPqm=7ht30`v$sUsJ4!P`S=XVK)NJ3 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 z ztE(LG(Q4_sMaojvf70dCHqq0n?s2jGb$g0vUvabgIern%M4b`_xYqTz+DMi^EBStZQ-n#kkS*xbp zcSPGo$99{|)vJB$+}9ZF!aJ_O zcj>Dk9b$1VIgZh_(Pdqg!li=BSB4&~Rxk7Tr&CdkdCw;5Fk`j=F^0bl)_bQpY7f+9 zKlADLc-lpyH^EOm`drCIpJI;3TQP;TS_s?``*sR~Z`cE5e?4UDn);GuA`$=*lw)9f zO{re!-fZ)psnQ5hC}sUoWM#$H>h0V!dGj_GYr{L`WQUQP9UbFlDnW@$EU1yaH?so7 z8*f#kN3LlaMr6pSzR_nv^6bWbZ7}rhO<2Yt*@nH=<2bjTR;&4G4wv#3W;rtU>7pNVGGUi?hi1#Ib-l@0Y@gukebU19M8-dc4f4#WTna!r#!gFpd5i@Q(L z>1s{(YeLQPXBiRj-47l=xlPBZFQupEfhB>;TgK55TKk}Oj!a>kJ#5daSuiDa+? zZVL*f*KS&hi{|Qy!%GnQa8n-0$-kOnedTvdTgh;)rP(4otZqA!p3V&7w@R0ea4}L5 zm{utSGQ`iiwv8J`^05R88n70lP#J*)vH9wQL5yw&lzt@}Y`2J8XOs8u(<3?T_YjrV zYh@s33(gDg*si2(2qefSMj^K>V(~hL+)QEA1I~E~UwEqB!Ut&11T`x*I0&dANjqN2k&hv{_J;*t0hDRu&>4?wfAb!3KbN3Hus01n6j~`Jz2R2CRhQRq4Y;Oy(@E z&(h7^cUQ!D?({m-ifmzxPr2MmrQ3(YSAlR}SD;x7B+xM}s{<1z%SHAiH#}IdS%Ise zu_U$;hU$PogB^A=To=^lBlr&5gLa3v7F7>(nDakRtS{XTlFn~#?(#?+o5#bi|7 z9dvds_EeCh*CdKA;DLNKb&aH3h!+%*lK%kJ2|t34&TJ^p)4)m1+?Ld8m*BDO&n0um zL*zwwEL4;tJyEJkDP^2$6ICk2ZUqhj;Pl8Q2}zB&wxt-Ym%C{zesgd1=!Z@rGgfU- zEF~Oqnj`EeZI&+~cpsCGAw?l0WZ86d^#V0^X#xr)FeInIZYqU!*-i|8o}6Nmb1gW_ zark8Spno-+>#x$1G9$eQ+oqRG$@Lq*IX*hIi339uvWr<6k$`G-CyoBwZC#Yu6+{#H zr|HFnDUFgF-BAn1UkFFNjn-bF)Yj83@v#8gSmN(be{I-ezGH@w=TvfMa6| zgbh!r8wFY>__8`&w0WqSk)nt@gN3Juvf=JLbeCICP`KENZZ$VVykJ2uxXJK*4WAnn z>cmvP*pNmqRCSeOXHqv+pwEBLsIIiyWIAjHDP&QTwZCpY?l8nM=dZ2P)YOS6#f-OF zjz2h&dGTEH=cr|P*n~c(>i9K z+o@xRZl0no<8TT4-EmznQ$*HA8e~}KJ7h6)ZWzT@{yFEU;P0`WPKD%kjr1fq+g3-= z14I%)UPbe*0YbA%a*I5Xj!R=_z)7s7I0SQVMY2sspin<{V)nd`=WWvE>S32Cmq0&o zs<~A{gsBCLV^iwtMG`HxyA%gagrf)kZD=Lh4i{)U*RK{+c;KlX? zWr|rGgl3>nDk$SJ@jzYlJuu7Uvxf{F*hdFG-Mz$18B za+KpDS1sM~mb!7N4L1_E9BnE*U2J)~L-TzR{{T&q(XoKPCdsf+jUZ&OrFa9MO|~D} zegNsZx;iqB%^h7yN%rh*jydmfJ7lioho=2`LY+CpZ`@09cHxVS+3xo3(BauKF%@I* z_?jPWmDq_QVZn6nl^!noGMzp7MspUOc{g=CRZN0O~chQ|)(H+nNIs zl%*p3-bePuiI_=@1i0%wQOCBVpCrK)F8ar!6%qhK{%eZ5>K{=F+D00CW%n|iqc@Bs zV&}*G4;;JapS9Z}P<<$90BD z0x4ot$@wi9s#H~se{bOOdA_KQgiMT~Dt56WXx|_Q&unvP)Uwx)wRG78owURT-*yfg zaN~^ERB^tZo?Mq{BqJU;;s!Jdl7=i*xNmd8RsbGJr8Un)dR2FA4=F0|^SiaL`*-Q5 zs)VA&WF`A$6Z3b+IL&-sUYR4nSg}NLM_QH$?7+!ki%=kwZ|n`5S_6;8p{b`4%p-?t z2*&Wf((g1ms&YA+dW$b<5X6Ps=7`aL8kb`2^KoDa8qXm8r2&`;R0b@zp@I7u*+AW! z`!0dA;=tFGu@84{QC#`e?3RB&OX@X>uq6DA`V@!>9|#iN>3F_Y-BJ)Qw7SXCW~T|)JxA5RTT zo}kmNJ<-~xM`cr*@8Uzvf;0C%qOynD(Z&u3;Ni$P>8lSc$x6|}u8#HNa@yMzAdP{c zL;^2?@y{$^h(lXPQyejOsFzAnyYWkR)S8fE_D&P#+lcdlt-FqS=etV^XH{L z>5B{FWNVP=JFbap>J==O3TOdpYw#P9(0XkhyJf$>9Llkg%6Ewn4<=5l^z)o1EM+3| z?&R-rrT&z0UHStN@he7)B(9(!X3z~s+5n+IUcdCfma*s!kH;jAJ?o=5{{Rrw)~w(f z?VFTyf0ytDb)h-R*>2lmQHyf_0LJ~${kd}C>g&w2AQD7@S7_2jZA+*pYBsn#Eb^LtE4@3U|P`Qm=+c~M^Vp=Y7c<-LOA5|DeTie{%wg%Fi11x8i z12oxH)cBpAIpC30JS+>m9wh-?Rxp6G>Mw&GMfC&Va zv2yQ8`$;*)j^jM;WD>`V$7iF`)YJa}^mB}FF73ER@euh6aAT#u>xUvp3&fGgn=J=N z2L9}Ru}*Zfv~hZR zpk<6@IMX8rc7}6cH0JYNIChhc_zNmU95CcYvpO!JRUB*p`K`X-So3G(>N=tt>|;^e zKhz08A>fcd<27NM;jeay)tSc)~vgKS$a^YMLnV2Vv?11fG;%)2lIlC7~n@gAq( zl>puJLk&nsmWyq-3QUu`(;Si4nn){AV}TBlTx!%8R;1 z4m%?5CC&0WJ2b&cu!S0k1R-L5tyh{O<0oH0`jsE4To8pxE0H51tYv#w6;AGkvpo}Z zY-7gbC;lT#%I<8<9XED7C&kXv3-CNJ12$qK6uw)N}Y)! zzZ!)W3A?_NHV~HGyJXq9iT3ukvD{MfmU4Axrea3r1-9c(B32s$Cp>1Cn(M4i%iAMX z$d9){4AQBQfB{u@*}rgu!y=VdAh(f&5O0oxUY-!GNWXK8#AR1yZKmE#M66}Ur|R`? ziArUhu@3;!-?sai=BZUbslJ`Y$;!f*N8pwgLlX%MWT_*9!E0VeB;Oy&BdGmE2~Oh) zOH%Gzm^J33fa1HU`z^X2rbHzZPSuai0mMR4q#WCjV@XFuCdE|8RYQ72s8Eq*k!?v@ zCG3H*+UVHSo|_#FLK0&eZ;4O0lCg2%+%d`R#wUlW-6;tujog^Z=x;cb9|uC>?a*XB zP8pc$8&*(IZ{;AG+;9ZN?Y%1ZM;2mTU$+xm`wn@?Tw+u znB(I$mo|}1EPpdXk;l2FQ{!}2=R)mv8HgOQCu6q+Q5`)u)0Q;|?m0B~LUJzCX}-U= zC8to&S5}4^+s@>+q5{;ao+}Z`S1&=&({QxXGshVwW|)92&azn8sjCa{I9+(IPhF0L z*$>sbaK;oN`e~#)RKMRH3F|fG7ZH&g9gN`@IKwVL;jAC9$(P#|vDIZuT~I4FhSaMP zepx5;Cg++v6y1@x)ujQpr z%&-{vexLY^!9JXB^NX_=&T`N%&q=-O>6~fIaXf}JStQqZ({=XW@T>?`0Me3JS{}1C zy)!UC0}r!KV$*@LT=!q!HP*MK^%Kmc7=;X4DRX7gl&JB}IzsN4W*p?gSp%Gi+B8Lo z0xWFu6?Ph!^--d5KrBGIGV1ORr~d#=37LwCregC_x}&{kk?+=oH8(rSmiCCX-fE9Z1eGN-iVr z@LHkYp0p#X>uH(PB@_ZTkjEmN{oXtDiJ94dT`b+hDP}Mvkm8ATjkH}##VoCR5fy-{ zwgZvy038;j@=7w2N|0wDC)^Y)WX)a&{8cP|_iRL1ua zPZv?ehk>LXI&O=xzC4FFB%G)n@!C(^-WNI*Nf+a0q6ly81()XfOvg+A0IjDfNe@azd;SSt9c{DL#w$B!Nk zW->`Ml1P!vWqAB>x!sxA0eYB$Rs;FE1FF8C(@8^4Zd=_5*To}CiW)YURjQVHs!L6d z*ccfu?kg1`jEvPe!e=D@^ftyI4H(UUG#z)-Lq~qrTHfJz3H3i{wmGY6 z%g!F8oXN#>wY|cWILqU1IPco~^xfUOs~HivViAy)EUju0LheqNL=~`Z&&_mRr$$VF zhw1{jB`qdB+M<#n$%gLwMw~TS7q6!6tPvR{-elM8Rxy4$LCS`Fc-thx(t4D8kS!wu zp}`h4`7|g3#Bun;^%HcB#+$4gnIkC2IRtsGBkg(kzO*#;CdiCn88VSFau{!nuk1ML zHJ>GA)&-P8uq*;bk6^s)(8xaKMsgKgQYr!ozO&~!<5m!*%EVN_(;KX{%U>N?dU1$q zZC%F?HE(Wfl*Ve_dK27o8YhPm3_x;c4v~s5MqAcJVIyl5vXTbGvmZ~u>ODs6X(U8X+aUhg zAz4^gH@*8`R(fwsIWN>I=^+tIt=6G!XTCp3anmKMvNUOnR(pf+0%x`i9ka%X+wfPm zVPn9WAwX4`KWqW9*X<>i*V?S?tH8P)Yw2lEMmv6!INO$-%jKu%?XE!2S$f)=n~=x4 zXPY~Q*Y>mby0|b_Rc1$hfkLJkOEb`9ETmB*+!hQ$Z=Oi&zfVqR%Q+elkype>Q&hbe->uzw&Oj#^gkmRV8~ERn;+T~lta;DCe3Wu?EIZn(F6~b>f!d2 zj-CS(-GotNgT6bKQ_;gx;$G-WH5oxaJB2%OTy@?wf3%H$8O?4Bv&Q}>Bx^)gs#%ej zo@kmKBU*YW7pE?Hg-Ce|nAdti$x0l99XZR(kuznO+s<*`v1PY?cPHwkF&O3w#Imxu zt>OR+4P*&E(RafC02h5u%NGf1WVr2nUzVJFU&Z0*Bc~{08kZhjDRJ^zGXCc@SzTQH zMMS1@y6~hHP#2p%z_1MZokswWFM@jK)YOqLX&QFBqbW|SyJh*^DzEn?l%*mDjfq)r z2`(e|dAbu9T=iT_0!F9+b(A|Qv!tIq2Pzd!dk0c4nqF-5xM58~GVDq-rk?`M{C&1P z`XYL>NJ=f{q{D1(yDGQa!(7)y)r@GV;~IFq6{ET%*@(SG3ei-MRH)aVi)9G?Hmqwh zl<=M(Yc0%mo^$L%Hd z)r~5SEZ3nhC=k0<4!nAO zH}CqBEXLPJ$eV4IcusPEL9#|S25p?A3C<%sTdeKlyVOmM3%ew8G(?7Wa08(DkXnGh z3geBhV#dh=of&CqS1}40h+P!riB+2WzA(KhyFKHN{ z^DV1PeD3bosMcoYZu*e=nvrhy=}}naQI;^QKzQe+ znk%k$;h zPj4cU%Ageo?I&t92BPSYNO#dBuhj%<;+m&#)hM5u8t-RP%WmInlA8+MSTeVqJoDY> zB{F+%LdaOfg*zBZnS7EnF;s3sG6ett0}qW&S3D2mbC zaMP5{P14$S!rPKh5Bt?P=;yDiDuiRDWV=d}_gcVa?#}l>v4M{8ImlOiq?R>U-pbi! z1(m?rlqHY)AI~Er>1sx7m}*4a8@EOxFMb!C{5?|{u@NG@jnJhnTZv|S8S}X-qc1-G z6nh8}B!<9lLG5k<#P(DW=o<~&9Nhpxo@x9+@cwXP-&&O_s(}ZCrd*GX8TUp00 zTj93-w|vrKnmZnDJTEz&%sCn(#pg}7jYrBd*(4qSdzQ2j;?n;;g68R_Xv$n#lm<}MJrmXD(zeGyYnWlS-9aS%~enQP0?A%rzSW%jGVl8?O#0&lOGmb7sc99 z6Qi(mDF|dN5+bTVAr>?8MTs=|heMhI%)4!>y6yh$O7vm+i^G(~&Wye1Nw|UKhv7S#BLW3MG9y2Oq#FMp> zMy-+^)U_5uPscrdPNV7fRJAnsSTG(d^#;w+=P|X;R?f4u<)tXn*sfzti?wRwRq`)Z zvG>O^w9p9LC#ZG{v13hb5hOB=ZAhX8kAu|io{=rl*17g24E#4b3>YGRb$aCVWf@+U zzWAnNMiV92?#E#pY3WspToh`_Zp3hlHr0^^YY&nL{J?$(OP<^pkJNk{X@gXwBC$x>M@){>GX}ieg7H)rb^2bly(Dz!Et;^5Yl2gP{{UQGKhC@f zeL?i@R&1Eg&*NrUK!z~pLaJC5Z4_BmCxA|>RQwC-Z}BbgBOM6XVoYG&82)SGj1PKy z^gg;8dU}@_ASA6PTW*l7M9q24Ux!?0j~IyGkV}Ig-*sXJzCH*WSYi(ffRB!#(Kmbc z%#d8-%2b`W`)j!8%i55YOkxQmY!22Wd76wHCEflwUq>Ez*iq- zpHfLSD0H1)tE|jmys=|DjA|vDYRvO|=g&ez2FTto+Qo++>Ri-nhYlPe(EOhBi4lGF zm6byHkwSn>XJxTg{>b#P@Q+VZDVQ0 zC*b3%w6!!y#@#qxUD{`RZ*xI?tq+^_^__h|^wiz!9{Qchfg+ z`g%Uw+Ril7&z&-3vX+WT6(5750HLc}@uIL4d9h&hAM^pIX1f^&+dU}2>{M9RL&+6VmqH53@7wut`#^z|O6r1x$`7Z0||;I$X#&OCM4daX#wgk#CuS58%m z3tJk%Q(S!XDcc?$AV}o3MRa&j7};DgWmCz&+W_mwKlN@9J+q5ucUOYrLwGz|*F3#? zT3YSu!I{qDleR6#+}r2&dR*?Ell@j$XGx{TRF6qxF)@)zHVV=8QoP;Unjek_>1%3{ zlo&|dZHXApQ(~7K)Wf(uQSN(Jq3akMC!=NFBQJeKc?5X z;J*0JKs%hWItUvYS!SL`Lo9Kuj~c7SQbDbiNZb3rBpc)&qSQc0j76dbkP%!pOW3Bb z!NBywaE!&@r?sR+v@eU>kU5c&tl<%d42K;PEoEsJCH2TLFf0*?t+f`vZo~0F-7iwd zT`m*O=awzq)nE!ryTesaX1<~mPpMT>xE%8w(HD{I^=3G6qsdthsx)91S5R70G4DE^%Vu1-39?FtKaek^>N0)AlAqKo+T~$sAH!Dm z>G~d)QxKV9dzm|vx%R1^$zOX;N&Le~{iExv4H&piHVFQdJuE@zb5MjA;7ODYQh8)g9dpWGW3 zx~m__>Zp3np&xXNo3!OZCwTj2SNwLqrquNEtOL#lU5Z4EtuL4DqQhw`9k+0>{NQ z&EGvLcg$kZ?*v6dk4nNrQaW7N4jnSrAPAJDoY#=F%iF5`FqbVwys(z-OdX2j9NjsmsJpjp?f73$<~N=- zf-E^?*>>E#Dj6DqA@^le3<$Oq0R(h1*V4>BlCr}#EPq-P1(w{oZ!z{{{U?5kl}aSjJcqmY)%e6Hb+APm}IAzYy) z5UdoiP|<27QWH?6Lr2R{EIQBs0Hf2>Z%$=okt=C}Vy##)q#ZRhQZs{I5!kRWkS4P$)mldTjP8rooxGEWd)GEpY@-L>omTWE> z@Z6S#SuV$U7_3+9^b^+A&~|ElI&)>jW8Xh-J^I)CE)dG?c{q7+9Iq7877Srab|OS9 z59P^Xb+1;vtOM0LP-6lT`brCNgriKAwZvC#m?eij>K|1pLA@!!wk1YG7Wuq}I6ce# zL#PwFV)j@uo;*3z1m;PHl><-Y{WOJDBV=a<1YwG{je5uN$>B%Tl@N?)3!7W!aa?dNJ7 zkzdbN!$^W^Lo%X^I5J4P;ZPU$=)E-cbjf{Nc7?Fi9u7p~l=FR;JwM`NM}gW~DfVC5 zlPQ_RXd?g+im`^W&mDodE&ZmC9TvaVRUsIqd!rfDuf>!LTogNtQ>^V>eOc?uFeM{$ zZ1*)3q_G(t&8-}VFHC)`#Vjhgs;dITG}yAZ40b4>aA}#WkZQR6Uwu2Poz&5ovUWe| zxDI(@w(-wP)MpaqqQc|)zNDHSO5DYc8jy(5RP@`7Vu%=pM$mxB&aC1<0){oKDN+=& zn)`sdAoZ&abc-25iwfKBWfQqTZc3|*!Pai7NTxP+TViu{O|f~*Z~EUxv5-wKkjWN- z5HSA$Znt7qxw~&=+kg(NIOneJCn1gjv>zp}+Ywst#y0cRI*ycCRHL@O>H+-XoGFhM zuSK&vNY01HhhU74Yq z)@UBcV8dGjiRGp-PpK%&4NN9iIVi6CUTLPQ0BJgMsOsB=Bs0p}nDOBy{{W%aGvOJc zF}On%sL@KIFA=tlQQ5450+aV@E~ty=r0YgxDpDkU-rYFn^UbZA3IF<3^B2ru#nH5)3DACzg!25_^NhEcjsRLsoRaU9A!_5eX z8GC$Y-3iG1w9)N(E?k)AxVtOMeIu&PK735okq?qN8}$UX#Hn!UBxGnpDpG5~^*sFL z>1ean7)M54?(vSKOj$uQwm3g?tpS{1`wBADqVBwyWXKNVg}xq|qlPS4q-IFdB25^x z?u-W{FbH-ssA5;`5+9Lct>JWPJEY$mVI+-l?u{77#ePSrHFZ{^Ls=@?EPLk;5Ulp_ zb$hV~%Ygo=o<&(0M#TG&uE>0dKe~c)#M>W=u9>34Q*@;rNzCJMD4)H`=&XMH^U^1& z7yuHBSD2xKpJ|TtSDe>QIC$9Pvlv-eIshyRE9wf;fJ0ESO*#GvuBde-5~w0oh1q?t zllHEql&6iXbN*>iG#GMI%fj>5ox>6YrnCe|8Iwl84I=Blr+`nl$s&Qf>PeMx5+bFn zgL7q6cW`{$+n|@IAzS0Q#j%qtzIfW<*lW4BTPiRV0cslr|S<8{_sgTBGyVzv?|an);f1ksNJ99H<%MoOk%>HcW~btYb!m zF%FI7iRnhE@UEa&KjlA*>Q*{Zl|pe8d$`A7lZq;f#b7I;j-LKCNIj_~Pk|KtSK-NB z0?NzC1(o4~K{BS%Dv>j_lBHRFRI^fmY}WO`9ZB@HAiH%XEB4VE2exF!zcqFH^;|U5 z?bRIS<5HK+@)TXwV~&U_f2U(6W^@uN1V97_XjK@-X~5)u;R|G68xBuhj)u0JolRmI zWMj^oy7FG}WLNEG4l&oJ$=wY&6P0(AqIa=e1#limgt-&BiRMVko=9LrvqeDcc4PLI zJb*xEBpL*BY;~m|W2dJgqwg!Y}45G>O>=pBd$p)$G5%9+wCw18R+&D zqx+dZ+&(o?VibEfyL^k{i2%{+==)+V(o?c=lJ@}HcJX&-d>t!LCP_5gy0`5-PwL}T!~c`!e-)SI;-V8sfnizr`X zbaQoUn|RH=Q^=Gs)t!J}8u-a8vWs+YVe23vRe+#Kp~$Ygq$9kM6!%J7vCc5_^Fc>k zm9b@=NhRVnv~!Eky6mL$+oM#_wLF~E<%Cv@j&GvVu6;$k!tD40p$D-=awRv8ooL$(Ap9h%bF7Z z04Hw$03X+()Ym6Mk;QQ>zx~eD@TdO0a|eh{k0{+yNCXzEQgkIj3$q?Qg%tP|T~((q zNwShMo!WrP`Nw9?Z*VyH>UKIT0>W}ymiRY(+UFt1BDKk5)M?m+4k zNh3P0)*8ZqpJK5u8i91S#*eR4>Os?qBxHW2SwEUU!F**7cvZNE}Kq+(aoi+=`CJ0ExI&mf@7ix(pxw34Iw5a9rbGJ7Q;BO5$YKY{q*ler~@YZkVpY;)2`mu|fCLm{uBE|7<#n{(VvS5aps6{f+oc{ne zI9^}xo|qFFGVMM#*Rn8Yc1J3NT1V^fe$ZcTNu$9%c_XR0j0}CUC1t$X3=ys@De=~S zsEkyR7o63g*j&BRbKiA;V#`C5BuB;I@yN`9*@(1Wb`QWM$R3QfN^AgrXZo&;jK-V4 za(3}qyYE5IC3P?)m-nac&MKOtxtmUUJegBSnk$6zI+JoW& zlv}Os@}z|z@J}60u^}uwg_I=R$FUK-{J0gc;gE?L5_UfqB-h_LRz(2Qq!yx)N2QU`h>jGk@@JKQ86mZmjtl4fi|o0 zoMjt&zP+q0kx3GU+BJ;{h%6YJ|JAam698wYzCWK6V~)dQCZMZjZ7@ z+i+=5l1*{&ULO4nCkU_IIN-_M<+I%{C+z&ZWCH@mB?3lwDuA)nB8~+%qo3^raq?`C zM~!VwA7ss}OMRnvz}pg5!HW26HQH6l9wY1IIhMck>ymGu3{p?=PKet2|7#Ygsv&qQ;gmezT2P>l$^<(N7iuo2z^~GT&gjqr4 zmZT)(ny zLFCyhaK~mg6ns#kdghrOSA4XH4LhM~V>PvKU@kH7y7;Ow{v>y%Ipvd&bwWTnX-t0o z1Q4Y0$Y+UU5(SBrDK=1$r~~YMb)rAbayl@#&61Zh%F}KOoHL0LE1d8XR=xUmy$b zDP$w=$F&Bi&*S@cQ9MzhfOAm;%&NmTFuO`}COnKnR zU4EVzUrAdUMhLAhkSd)?P=j>~$Z07`Sp!mjNj*^p5aKa~Z3brPiH~O3m&Q~bwOKl! zS{r3Vowvs4wl8!HqhE3Hi_95)n+8l}?gtV9COCGLpLHOrYN~)PpnyiFkH~8zb?stW zvW3o52O!H04+%q#0dR12-8XbiCr&zneA=xwnkv;TuZz44?X4rQK@2MZCsmV5Aj!A_ zMIUbaTClIj+9<=W$(OTpSd~GLSHZi_HTx9wtz+p*&uo;dj^ZLMI5%;LKJ0L{MrUTw z$gwFksaVRYC}3{>3Fp)nqIDEN>PhM9$+_){;0;QbiEj~T0*$9Xb#=`@P}jOqDK|%M zMw6dr9NB$U3@` zk?v{YF^q=T>8qmRM6AV1V5sK#p9%W)R!Iu@h!*_4G<~XLOhCsz+oDxCdKmg zWC7F_P~CHsnxYiA#Z1j-wSRo|qo=6qW@?DVr7E84SY!kjpV&|SVpM6PD5gntaLr2? zAcP`-*61(|$I65FEGMeLWE2-8U?fiMY?1zCzE1r*WMeOG4n5F?E8@i~@lg}I(C+y> zm@q~Z#`z;@S(rM+s1Mv-LmJc#ZiynO^(M83?L9iiQYz%aMp z08C>YJ3Y$D`HHy9B8IBV`Jm|UQ&%3+z07%b;)_Wb&v3Ve;Y%a64-+)oI})uCjjKpb zy9xmANMcx%=qiV)JsdO%H!U!Z-@9ov&+?V#yd30frO!eWUw+?i!tN~N{-2B4hsmV~(>mAuTD! z1Gu;5RVMGfXNLK0?(`!n805%yjxz5HG9r~MDvgi`r3j6)nhZe{K5iLq4cd~I+y4OR zVn5q2j#i#r^`WCE#w(C7F`@pi4Sm!$QrJ?YF!C~TBogTARL-sAA~Xm}1rK&sNk{;c zrTeH3q=uw*Cm@vesdJib&M>yVKJGuW=dGu-twtTPfQ*MX96u6qPQ`jXhlKHEmGx?m zc~ukw)KwXW#i6hpP!_$f=c_c~0OtW#nG=pBC+=~$1@6~gmc}=!D@^Avn)iEKuRc40 z(aB-f5=3ZGE|XH<;5Ap;N%+>!+BjaSj3X$eG9$}qFZC{~gkwjwcZK+1N{{VA6zoqrN>E}233ae(P!^wE@UxS{JKBVm4F5j1z8^n(zN=q@;p^X`= zHwv;gp<}v2M~`M|>SWZ2PgCi|x7rI7PIpFIl&d|zj{RSyJCq|SZZlyk2a3aV`0tz* z(3}sZChq?LOGA&A#ZxOTKNjjEmBe#1nBAjpB5DPg79y&Jo~VYtp38K%U>Q$dQ7Qc~ zgzRi=`*BaWm2~M#N;AU|%|sW<m6Q#zm4yAn?X^*Bq*BeqU{< zAwVyeT}KC}e-BgJ^z3fqskRN)3KV&GJL9bX08zQUT{t63k3Z$2HZA<#ZIWL^GkZ=Z zK*Ni#CSTWW-MPKRTwZO-Z5{2$#pkIHW$n_& z*t6p-kC5?XNC6hoF3K3G)k85|*nBwW^Us(tZPkkw?Tlv@DDs4)S@8ZZpq8$*Mo?td zDpHd1X7e%p5ydCRP5AgdsN+P2BqlT*Fbs7-Bh@{r2?0`8ENCbq+m5Kym=zs;;#Jug z+xXm%HZ=I})LNRljqu{Vu%^!?4-MU|HnpCtO1N`r3&kF$1d~TlRcx?W%AdH$s<=V1 zuWyrG94}B}5k;$aO1Z%!ZFk%4ab_M)88NIvb$d#yGwyc#e=F6l%ZBKgEtFSbBlskW z6+p;UeN22ERF(q2#o0WTmV||-<&C&zQEa(Qs&Qy@oIM73h$aDU9gxu z;A#mpAEpbehC)~s6f{{xKoxDMwya8>MvMI4RqT+0XP<0x=L*_e%WutgGpDP%X)H&Z zxh2H*)gNoz?QQUMZx%duj!36lW-T1Sg0+QqWl^m&Xh8}WhWr!LATx_(Vz~DNSMkhR z@A1uaiJO)&Y^y<)HJ{X(@qBSy^>!jKH^lPFuR0NNwAw8HE6O7 zOGM;jFxa^&-XBXM$%|82gY_hC9?Wf~frMiju`89E$ITw}{{UIWvlPQbTeFO{ZV%Y# z)YAT=3RxjLIoKw$298i;O;|dAZ7^VHf=DFY^yp4Hrs&QQj@u)c;mdoiv84IW99c%} z%0G>*pV+V7zC3kH9cOr1^Hb5*NaS$JSuAR#$N@F2E~POB|`s72E#8iGgwbaT|xW%R;squ#G= zsdWR~5rtwPOd5GewJ(VED{($&ooUf*y!~MR7vT= zQMw(mxc90Mx<6IC+O+hviwa4!sU6?LD(n*O{%W3Eqop3`;6h`CN;bYj`8+68ZHA`W zfOeus_KN4I^`lT?PAOJKQTJ{eq>G$9am~}ujRZn*$0lW{Z{QbGt*!@^F(czaS>c$3>92-xasWFq9jGyvLxAo z$wOa-YdN>2Ni#Ck39-w6<>iS)KkjZ4Wut#9`%NX#y}$h#@z>YgzuxUuwmT^tRIV|) z{=ie##*|3b`9`b0>Mp!VKOa2fqgnp|RmO1O$1uq9%@~)&GGdk};#b(DuDq_wRf4i| z++P$dpRJCjm_USN(;{Ss>oi3l%e&+rdKX4p881TAIldn{wZEwy{)Egkb9lHpg-3s z`@Cb09^vjW1(Dd0KJ)27fV8L-@v^X>Ncd_8gIfFI2A~!QOD-?Md~ore`0Fwror;F6 zGi<11sXo_s)>EJ8@zq)Wp~Wg=GRC9g#e`M{zyik%i(3{T{8z=NQ`W*Sx|I%R8??v^ z?Hr(2Li%x5P?q96w&Z`5j7OEc9x}aF$L}yrVI*Db6Uzg^93g zudv@**@wWcI?**eGe@1tMdR4UHS<@_Gks^ea#Tc@^GRiAJXDXx_qD3%OD@3qB~S}7 zV;FEPfI57N)Sd>#cxA88UW!I*DQ@seHA~)?DgK^#=%qly#&{&m_r#C+Vkh)--=3)C zPZl$Ughyl;AX7v|Ewm;wk1@qKNAa08*&BWUv!DH!JV6hD5)j%w&2Rs5){#UN) zYC*&zM+=peU%K;D_A58>(JCX)4uO9oF{ zAhT=(k_Q5|74a#mM6Ern2-2Yl;|*DEZEULw;Zvx_naR)E;y>1`Y(G{^_Uep|lX;iK zibm0SWGsa0grtf|JF<{CBrT8y*d2RB`m&L8!-YwYG^H2*Z~Z!aX2kX~Oj0}V;P$!7 zg_!4{xjnUUXGbzDi!LZok|!G~?9a1u#f?|Sq`0yQj)JGBsO;S_%!(xxIcUZ{5Iec+ zOG8^$L|H(QZE|3%%u&uU;LkRD+ahkp%aFyhk{wKN%_A6~NnOd-Gj>2A17VGW@yA*k zansZpOG0x)3`&ce{$$5~bMbWP>PJ-Br==av?CHXL%<`8>;g#1N`j$_tqR8$Ki;w#Y z8Chg<{!?gNJP|OWq%c6tK?+H~kPd#PqYZ8+4Kc(|w%{#q4;bk>ntLHkGJ$Le zjo#~IF?ew-+gR@X2X(@HKuqq^0<*h1T&3Ig;~4bTLhcX}p?@dy)v?vlW4d#j6{p=D z%XOHrFFCs?&solkBRX>DH7{=k)e05FN{R8)k8KRW$R&-3^N>R3zixLkiuA}z3A#RD`blA`zn(MNLq_pen$|fl7p0&dEV8v0Ch1J%07wAw!q_61m2c;gj+TsO&F$8j2Ukny=aI>d{y2k$It}+o^c(d~wpgPj5jfF_O|m#6%i%F85^m6UKvuB)|Fj z1P-UB)Fet1k^quj_uB6ycAVM4(G#16h}JfXXz_c$;}wptG)RCTQNTi6YaYy{Sd|0$ zs^kmfkHDr8V*_+0sf#7DQi9vdw2Zv`@B_kSDBCFojb9HrI0L^o`*rR%QkK!o>b z%d(il`87NM3tEx~EK#|>4INF2JqxW3e{b;tsMtlj@476xsug}vuDcUXc^Q9r^UK-Y zjBu4lXQLtr@-fxPkH|u)Ay^{-fbuE1H%7Q1^FW@DN7F_Gw#rf51SH06cC;-Mp{^{q zwrikd#U1z>;m>pRRaFlhJoO~qysQrlZvr!@BrJDBL!s0tBA03$(c|(uqfgVUsnnNu z*&CJwtgMeX{QPw2>qwSm&T=6t?cJ{);;rq%jzp5;Iz>>p4#SKNmSbq8Sdtk4 zM%V&S02;yvHp*(OmieQfEjcSDay028O0Gj8KHaNbuKxgfuDH9S?fxQR_MDtOu8)R{ z6f4*4$2-RzvXte^zSiMc(RMuX^2CxjP^Q+p815MdyWNOtF&0haj_ENPtn*mf-%5cd zX6#orQLl&H!(D(g)i@z(Q0`cL{>(|%+T0B}cCZ59#o0QZyxej0VW~MEXhe|4qqM72 z3wIY4#dU0DFak7YM&ywrcL_$^-rV6AFIJi+KoISIA9O`2dJw<{_$&!K0Yr@rk!Pj- zElCrT6eNx#ynA7fyPo%0zB)$zvy&si>?ca(Ng!hLbw${=bw+6+@yiVJt};lJP@!g+ zmLF->&cj{pzE2bdbuax~G$T06OaM86#(#ASE^?G2nftDiP4*G<&s~P3p)K1i+WkCpHeJ}Qgs}2oBse&rs`k5GCxcr%xyju4#Jj- zwv+pnwWVS_P|F0SpwKHw-Az7C|P9AE!5Qyi*q) zo-$h{Ule8bMoV&3mEY=klrTS_Sh1D14NHxAN~|THZF%& z>4ZVuv?;fEaq%jZ)(@Z0N!zwd8YEi)lZYd4JUDufR&1=`7FEx6?(oMbmbKsuw*6PEW5gH z{yutL&6UWwo+Ec9=H6(g>*Kap{;0v3#0jK;Nh@PW(bED7?zHQ)c1Fk;nifA4I?eSk zS$l#zgDVnC-Hcqtd)t=(03BKBrb1F#O4#lhuvp6ItG9~66_>@bWA@+lEAv<2-PQOC`gZrs17@-aeaYym=~ngmzl zn%PBs`j3OwoPM12K+Lb)eJIK}%@cQ(@Wj5>^%vBPrM6C(^Y(vL};UBm9$oNMe;HNzQQodK_x&M-Hx)gy&QEUEfSTKgm5ifk}>#bv%R&^>P{w@ z6Ny%>Sn>05zT|RZ`*bP~ruAsg+Q*AnxS=|FG&0Lf`Eq2Cp)m&b~9yIgGDV&zJa>UaPNQrOaH7sp^ zxUU2FY;@{bC^2z%%J>>bjw-IHuH99utQE8+X-$$0R(6TzyWV-~`eWle$rNnSFjQ@x zJKVDZ1CUgZKH3~t78u!~KBOttl&cYnCoLtSX1TV%*j=&>(ZQe8M*Debt9;Q_$3b&D zWU1qwStWqv#TDE{ zz66mBAzflCHmsf{jB}>D4S*kuB+=-nEqIal>O`kMN_z_I$8C|UGA&TH_$X>hQ+hjyEXH%Q?VlMnCtPy5LP6lTDX*9 zC?A@ayBvA4^H`i(&2C$^E;x@I=N*cw>l#|xbKMwd$dhjC zmiK^txxlSc+b2C<5cdA*lP*5d%DD2wEHfEi7ZS$m(MuYV3n}4>(N%6J^U`#*bam_M zK?sN0DM>4uj1zZy{$HN;M2?=FibV!d)ZOk*^%)WwRh+nb(ea$W=@9$OL5W?!5=uZI zpN$CuiLwO}Me)^NOG{4kvrJmX(Yi}_M!qb*I?bF#nWk=B*eM4MeZzseWAeD@Pj>Ac z$mC&VU}dyXnUKxnTUld9BTWLgz$zsH_3^I2gJ+~!1~Z13!x?qAMNH>1FLVLi9NyY-Bgifd}FuINZ0iYqqUr1GKmq4WCG&7yR7-X`EI(EyIx!OXtMlKEO-ET z2@|TQ1|31%TACBWvS~Ww+ZS?z_0!6w$XOcuZD)QypS4*>347?IUt=Z@X(x z^7-SYd_?g~A(0FS|^OoRbCOn&XZNF!cy{A)YO)MuV4jD`k_|vY;fA#*_|0_9n^e+l||q zX(lc+B=_KMH|OG-QwpA!GapW;RmI2MuYl zHU|fw)Ya2WG9Z~FWP4s+u12Y{xbM(3VuhzPvd`iz)noVTsIjpmRt5)nW(?A`aAjdl z@&&4pRg?p;v_-CwDMwdqAY*UBVJaf}^296J%20;~ z#F(!av?~UBDCE891}LNFy1zVEgQYCU(;8XjX&M;hK)^atLOC(|{Mt3x3dd>(`I^lQ zNlQ{BV$l}jQCL0UciP*gml&^2l%Yh*FcrIll%;Ok@sR0H6TIia-aDmW$vOA>&?`5Msm|%ypEWH@p*H~`M-pGw9SIfFqZ^a#7yzT zyA;#?JH0fH{iZyegaH-Se*xUd;IsEQ&>s+E$J!JFU>j7CGq%W!%U-&B)9=+!C@OTf;0qkpc zbB^W_knQ%xfg-%FKd66eCD({rLNgM^Y@^ObByV>$c?DUFu7m{Cg6>^&8DRdK0e z%0Tt>Wd&FQ+!OPCHpVQaq=?lrm$m-@Et&CApu%z1Z0-_^BT(Hhx7(7Nu#L`(<#Ee> zD|ZQ_$CJqa0KAR561vB++$mBdVPM(yKt~I$elzuT4LM0-1vI*rwst7T4Zh|yk5!(h zNz;{1F-rE%;R5(Ls=KhmjxQtO7}*|EDjJYTnh??Iy9NVyYAvug!*WWJ1pyT0qdShI z8ChW%+VT2QzpR(fJqOp)oL{Kvk|fioFAL|M*rBYLq)_fyv8>;;41q%*)9)lh$mE!% z=DkM1)zxeHJ!NX>>2ah;{%zhdR${LCk_8W1dLK$r$2)2@v-*A5d~xy8qhYa{Ic3>= z$RQkSFkt1K9MKEv08&0R8Q%+l8ISpPi6#OwDialq~ zT6y0hsLlod04Q!ZJW#xG)p3CCuX(qEKHKg6eD37MbtDl^GQ}~~Si5M-#f1WIWnE~7 zBy4S%k#xO3(UFv`j-xJOvD+rD`H?_YGB57*kEO6pn+GgTKXTZ&@B>uUWy=~_%vki> zAZ?24$oMU?f)`yyDRICJ_#ls^(ACx36WbUbRIY!^Yuy0+^VWW`8{J!)VoN;IUIX!5 zc`KRn<}snRL_3}j1Ra52+dqv@Jh1|ZKOHiAu*lMpo4p-ESxc#MeBXiX)Ut??O({w2 z?U4}3nG?m@bBj0z`3*Fvg_%5SL@Kkg$i&+cx}8s;B9G4?Q3QUsw`zX-_lISv!u~Uk z-1NB48cNDAVyh}zsyoVxKN-#R4VF!tT!oDQW|A~oStjxnMFxQmhk-{{9~2cq(u}J8 z*f}F#X~oCeek_!#+$o==kX=pzBX1GK*FE@u7x=!9;Y{*Jas+eZWY9e_NwEai!B#57 zmQiGEIx;wCw`%0GE-_oXHHNR|`t;Hg0POnq2&u1QSc-o)K(Dl#N_#_WDU+04>-KPM{9E^z^kV8sAWnkc@q|UuziF zN0fW>p0srJG@>!v0IMyNp7gG7&JH_tNtSu>Bvx+`Fgpm?BGihiQun6+0CJkvy=(;} zb>xneGq0-(-0j-Rgpr!L8W#!PvJKzUwPl=&;m9Aq71(U2mjD5U~e{^4V(^q=BH7Eb3B*Et(| zx0^Ub4zt~8j@C|^;>?-tjvh|fq|aLa0BM}ZqRRHhJ+_Q+ZNc%;*bQ6c3M;V;XkTAP z>83}SN&#-spT1Zt9&oSDDeEU)1qtcNz800f`Hw%}p663$$L5?E+Ay13j8|t;fmonx z)O#@$*1V~)Rn>8vWx88r$G-mn;x5*T#AO`SBQC_e_3b%FYq+=k#Fw{hk{>JkanlEA zo(NO)%$`FKwZF8T&#|-Y*YkS-!>e?esU=9R@B4*kvOIr6-gv%|ILVPHeMsT3jmNfA zTE^*W9uY(Kg}Z@!9h!YzPH1I%~VGq zan(9sPXi}Rc-^P88s>q={{TNco6cG=NsbolJokK6_2y<1VKYvujHh2Dzjo?Hd;)Hm z9nZ+-g>;R5Ic_#j>V=3H@Aq7D{c}zpky2*S1~n+Je#hN*J`fHLdV(yNN{HRGk-o%{ zR3e!a6VA2(V{Lx`04!MQMsSD}Mn-$-rZes^+v9JFG8}ay3?{5_^A{;eQdDcP&z$nb zitb0N)zQ&F@v@;i05%mu$e?bBAc6-~=*x00rdnbPkNmc>%`|a;wfEUXrpjgueX`08 zF{|R7812ti=5X2q6qdU*MxhGcs-HFsYwQ02C9ZF#?g>8A{adPE7UAdnd{<0}DesuE z?yuvB_CK5Y^b0GuN0B9oFIJGMupf1Lx39Z^2vQq@IQbSiJ$?Mtc84;^V>g<=^Clbo zz7m18H&J6FEyam-BnX$-&w4S{Z_qMsjL#Dl)ma+XQl-46{z@9>l{5nbM0CA*MkvQl zOpsko^#G7nZI$H3WzFKRu9B%-M{#ZKib?tBkB`qCRe}=Jtm!A}BQh$wO0lZ3kTCVt zRe?q(n$E{ye;1z#GSzpT4K{HM7^sbK-EdP33Y@hZ=ixmP)3~E$n!<^GIngU z$8)?C5TF1njhN6KdDhgSgDp~#exgX=cLi?8ElM`jYo>0V zMU;vXEiZT$rQ3{7`0^uH5N7mk*$Dea7S5s(vG8Zl$$6v zv79+l$06Foo6b5ZVj~tP_K8Zjc)Rb|Z{3EvsfF9-#mXPDN-TloaBV5YGN2$aWdIUS z991UQ=Ihn8)>;;gKb*&8?W!vbmay&M4lUE5Gy#8 zwzT*U#yYrrTx%oa?xff8y|K#lGq~VJ1koy@z!EabKuvX!KCzXn4MK>nYi>tFzD>dQ zhhlio%+nN<1%va~qpi1%(!0dGam+@`?4P-d3y~ZTlsqv3aI;84kjzx5a8Qz4SpNXM z3ao>ZWLHI`jO%JKYwCXzW19P+VCL`yyJGsH5|Yo@O4HgQA-hu5+gTHy8gtZX5(fye zaW2Zvk&r;tk+tx6ZKNrp6?A4Z>ZgPQ%F{wyFPi=0c z?`e~B%Y8wc3}oohq=;z|J(MX1)KFjDERW4|)-Jr=d2Diml6b>SEjNGBI!tx< zHqL_iltNVU2)y}Lzo$ieWLWs|ggC7#k7N%ilA68IHnONqmIK$|3$DE#768XnO&Tgo zDHVdg>#UiU9G!DlTX~0T1|{Hjz4BKz-;DRJm}bMpWrJf;9jigW44Mpn)kIOcbfRe=b>|BV#XO^ zeJsDGjMT)^mOQAYTLcl!b3(dobhR`RP~8YM?`~4M?L*Ju$5CmrHCrsh_Qp>RY;O(u zXziD)zf0rbIR4`Ui2_TNGY=l;m5WW6`q^4xU zd|W)o>5fZZo04Oyy-vUIXFV-3nF(!-jhm-m{_~4$e7#ri2?TxDxy1`2$B&nl1V|7m zSp2jRRc%nNz!7Bdbg&OlYw5t$Sj05z*bzV zPHD)IiX{?yl~!XyKVMn|FU8-ohCh}(jtL;?G~5{1@)2{`2~HwB;g^n^Db$R`J)wM( zOKFU@=CHU7_Q-krW2}Zil*~fv`uqiI*b)e`0Y4XCJPxPSgkcl-b427Mam|$9;x9OU z8}&EEh_M43ac&G!y}X4hp1pikIN1u)LJVx+?4S~*b>J4%S+*3XUzH$p(r5GtBdrmU z#mSZY#&_TQSALtPEtC6c!OdIQ-G_s{o$IXQ2P5{LD4Bm#k0WEt32^%sk=9w$W2jQL z>-RE|O<}mqWff0!{{WQ;q`AleBl3ZMIO^#dw+4b6YjwnG@><=M+Ye{AO1Y|^t(R7b zGNFy6*q{q9;#MPF$y8h8;FeM9Z>7!}YP(%IA7#nR5H*cY_(V7}7HM-6Ps2jIb)n!`9N1S7VM7eL5g4SB zNb*mGXJ%6}l`|EJ>~MWoopm%oSbXq#|l+`5|iR>M- z1ePMr8~lfS9CdcDsM3%`gp}FVdot z31O6Rc!}GS18Uz~Vx$hobwT*60RsvQFOfurI@$I%2_k}H1*(fFb5cmkD)RA`@BaW^ z?V7i@-Ot^fTOs?Cz0zn^Wj4H4ISwX-I8E@vn6mPDY zainLcT@4PUD}XhKrEY>prQ02P0~Nc9jCarETHYLHmwzUwO&Z=O4K zJi-|#5iCn>AZpsyQW%0w71vM=^Ti5N^V2stHU+NBRnjG@=!9h{I+hrGceb-Y zCI0|I`XgIPMaGMdyK%L?)^mKOIq@0$P?}Rg@%=yGFVo+?4(dXbqXJXdZSa(#vvU)rw)^h!$fhqn?)>%1%#$A#n-(=_{9-6$ zk>nDvCtFRpQjDJ(>e2d&z8&>-2vj8l1u|nB3(d&j;=#JjUsI%ID9Upp-Ue3q<;i&J z(&We6qg;tgv%&+-9DGJ3F?00KRgkowB z>x^6;BB(ODvEa6zm9yr_?sL3~;bLbFp~I6IK-a4uO?CVz9{iKFRDPg_sd`}j8Lfz>_)&690Gkw zvB^C_Elo`+M}O9+(M_0K0Ukk3gke~^?HYjEgQnV&d86&{cmM}NTU}{sp4tfqEis9^6;I6t z9Q9)JC^3;)X;h-?zdk`R(>HE_KdFs~yAn8$Z2}gd9yjYG0;B=Y7^>WTP08d zs;RU@Jh@b2OrE^+WNX$lrZQ!_ObiXOWPX}Tj9%^6#dFp2)PzD>akWpnLA1!V@c#hp zq13Z>n9?6AN8@Q8PkP+3I`XA~rPz=Z0@v(M$5;AaOQsvx$(n&5sxUL&EKvQwFU04o zC#m$loQX=t-EF&H!^$1Yt#kOQ}5P0-qdY7Wi7!Odu((rb@Fp~SK zF~MHxU4FdTZWKnd!c^M-0K%65OR=_6a8($MaPf7Jr0bd0@|BTMpdL#S4`7BgQnhwI zPc=n=2jiZai#3d*Pl$ztuf^}blb$(VlF!)1jOzaYP1U|*8ven_&p{3>vE_Mm^6sa3 z0+K;*Q@+QLTr!pd$J`juzfVt887`Wo`)4CDF>JAyj09dO>J4oT+rFOWq^OU#$G1^O zcWQX~=?5P_BlRpLLE&iDRL~(tI~E14LFbza4!=JmtrJp6$4)W+RcMgCz%U0poEP66 zeSD=AcJ8F%ZkzcQ{{Rm;;CerWI!vT%EKcpQli<9C*2{7E0>~Bc0}gAVAtF^IlXvZ@ z2}cr3Yq^j1=w-ALyV;1i0=?L;Ki2zn(*$ebL}gYss>a>amR1f=`7G)dhXVIrczm?u ztrJctjNVRzoLqm_ z!Y6GNLps`>Ngjc?CES%@RFZ2~YvZY_-!HZ?D-4)O_{{2F2furIt~!$Xbjl@I8&$6> zkgDegIPTW&aJ#0^n3hI<0g;sM0OiD%3K9WgNDKHSi5*X`D2nOEceOSwq*2Oyo_XVz zy!BV5+*H1zMb7Fy-T{1Ix5i98SnU%<1_b!hWHebSq{|2qqBoJfc3D@*>UCde+u4W) z?z)psM9F*Q8M5~2Nt9l4RSI~C(pKzx8M()+)7B9`W)=svhr8ZL1+&NP_dsSWJ z&l$nf1}qQbc^Q#3B~?_NDagCn7P1IX6#HyclkzpR-Kz;{Kxv{-Y_`JCTfA{s->BK? zvQ&`Q2#>cR!QZtF7mMmi6(iWHl{$|YEI<@f+W9sXtP^B01As1hSJb)2Blg)cKnIJv zaoY{9FRsQ=T8`1K5Plo0`D+<69lF4tMVe^$Wq65L+&Yr*{{Xr;p?fj=kHH6$Nb1H~ zF(~?CDY%H1$APMj6C_$*GSRV@CZ!fQgfT@qrCxt$`g@e^Id@65Lt%`QHPF#eDe}L|*JuxM+{*s^MynhN$M+0z<;ka6V{b)? z_AJ}bM`uvA$tH^%6bbzG=X0pKPUx9n%2UT25^XQH%6GS(%oJIQk$8Iz%Q-xG$5y*^ zQ>(m$!*1j#C`u-Ppyk?$ZU`LR*#n-c^!l(}(fXUXcE?j__OomL=YN~yNt%e=0r`E^ z{{YT0ZCd4J zRi0iy*ku+b88?yC+)-7HqH~(_j{Q%WERF~jIw`v{g_Oj{m3y)hH#7IdF0MYyD$~Ph7^kS*rK2W z$R+qrQT={w?L={85Gwk9oM4B(cGlpG^!Bvil=CRv5v!oM(T;+0(`qv|`@Ohh7rN9_ zA0zYFI*^@97{O4C;k0G=(W_P{M!amL0{;N+CakeEV`y$c6`M9FW|a|pVn!<7noCDv z?Txn+m!2uAFS@@UBrd~hEKG{2QV>V7$>bq*Te1agK1owxd`~@ZWVde41Y*8FTo?OR zEE+oQlXfzqRK`8=hvS?0zm6&Xt~zL#e&e=?q`fAxIYIHWY|W|v0EiYvav_(g+boe{ z@FWu@=V&{Q=|y(BdTQy9x-qtJ;@B-pmFzd zM_rGrA~KGjx>&tAx^N8hy$G%<^UZX1rh+q@x~Vr}MOa3vyp}ZJ=c1pfGR+)zp;sN> zQ0$ALv<3J6=Y5LbAR81%J~bt&ZN+OO^&u%1t~*2ybAvs2)04$Vn@FqQ+KlL0$-{+S zye|sG(F;@iTNVY0a1>IJ?R*k1VpsSUI!$WIKFw!OZCnC7L0@*}<1;1;dztHmW*>B} zA=n8WyPfK>Uy{0sCPmmJaXM6}gbf^mr^#%kZn6lKSR6kNQ-zYH( zT!0yA=cTTwv4IjT-NlrS%_a|*K6^b=#mLfc1hCOQM7_l@Yg*ZDixfPS{FA^H(umEI zaYCrw-TXUynWcZXN4H)PCAWV*=WTIC0WbY8!PWL$Xr=QAS;7LWtj@tC3Ic^71>k{Y zMKJ^lZkMSYQe&y<~PtLT2E^9SEmUHGmsN8&l>$5rFG9EH{yFK~A> zZFpUn5{*Tw?^1pb2c~JmQ&axP1vpKqY z86BTc?(%tQjd}v~fqn^P{{W5I)LUZ>DcLB-Q!yQuH{lq4$(P;8bDp?L26j&0wo_@b)o@Y8~`kvACvM$Q>Oy2Zlr3>(Vi9gBOD%Ui}BOo zl8vdC5#1R6su$aIR%qb6E$XIe#*Iqe%!}mVkH{5G7^PMudW!*v1KpS4jx>RT41; zTap+s`2b(R>P^WIjEcr2T)9+aLYX*d`Sa7Gr@7kij(Nt`oQ^j0j!Xy7R^Z6lVrUSw z?WigXD?3g^iU}@9s*_j1_@W0^Y3dS9wJF({!VwIL#-&UCn3sNfmQdFvE0GwkFk{K> zRK7U)bpMN*1^Im%&2_QqNip~6ZL{>5YX0Uj!(K2Lr=|Lt&C*cXI8BZ( zG+!27U)|+s>Zg84yLWo-crIRP;hi^_C<^}osDccobXucnHSBCKqO?y@`rRPRw5W3u zPNN@p%ySSb==gkeS~HCFqU{m0@1IC2low z>dZ;}voQHJbOya=YU}GpVG)u!WYj)tBgiE`-EXS&^km0&+qFcN+O)3^_0MCg7~(nD z)M=v&V9T(R_Z3N|AP~f`1!xU*U;qc8H8kJ81#P9ZKekKnW1o(jD6k}M)45(5LR|6O zc>e(HY&mhTRAps&;Ro5wVUXJ@$;!tXfRDxO#JAvdI&jjCH^ympu^Bk-q`usR<*etY z?$-4ijq)Pklc@zpWiG<7YgoLIhpQvoJdNtnQzS9x{}|n#mjh2S+j8?R4X2 zBO{*_aJ2a!8R}{1YR44>ZYCouuI37A_NG>>rRs#4xE;m>Na2=DxMV`h8z7b`2xt{w z)G=0Kk{@sJTAS)g?vu7~jBbT(D7Wn+PwbtnzLgcyoSAxdQ?6$e8sj5eEpuHq<3`Y! zky(|cjHi!KY2qZZvZ-J{zV-lWZ<-xG5ZV!rcUo;GwJW3Cpl;13dt;@~U0Ht#iHbRv zD-n`NImH*J{}V=`yrJafyAKUSGCMH8SCJWYA1Sa5B+`oZ~r0 zM45My{WjeZ@CoLSdhzNsr3qYBICToz@$IEcO1iS}KHrZ-e7r6M(aQ@vZdmq;>Yjw*ONWtM;QB}z0>i#j4 zRS+PPn8akJwxOSQBDO7D0vUd3td4yXN;Mes97)72yQ#90wTq=WdF#`V?N=h%d#XPd zlK%i7JY%W+5215JLW&$~`SSnWzb@HlKd`M!lGL+xI6nEmcnelR@wIwcIz%NZJKPYr6xrn?=1 zR2IUj=zQ}r?tbuFLlH@yqx#9$)b-T z*->am5}O+()oK*i?vjAJ9ZsOC{&)qG2kHs9aQg@s_NFPi{Ss|0zP)k0%2D$Y^A)Uv zyB-&ghGpWuJHy-~M0p}bk1iNkc{1>s7_*ck{p@saG;BSY5tsXv3FO0baf%rBo0J|h z(T?@v@t%Rzj&{p*OjI1*=F>h3uQt)s5yXSWGFDQ!?;1FjCXS3R!DUhdYRRyxW6$yc z>4ul3Vo21HHvZI$Pk&@&;G^Tg&rXbq2I6lO?TFShYjyr?ykn}&cE%XPML8D{9zY0G zRXb~`B(;NnzW^IG(?S!7MJEIGPF0nlx;J)qss86c$~tq38j>^ah{=ufxeyA*Z;pBB zju4y$Mnz*3A|GPx1(gir#h<~NB_6AWsMsx!XrqM22~#Al0{Et z1$7@J9xw6Ln>1w+lMtl#g)a@pQmC}@UTV4-jJ@u&ZZ;XS!ZKms?yI`Eh4ckGY~^!c z5G;|#SrEwbDV1qh$$EeWrI6n&SKE>YSz5lIQIoPsrV9j?oCbmMZ_P@@`M$c(QHjFD zYwAKW9OLb@;=JRVYpStf$_R%gcJ)L+$gLF`V5YT^n4M^o>H)A%QtIh?nA5jPV^uGz zo%3)9OiSYNeCMV8ZC|=tGm+bDq!rH!s`eU zp?KpzjP%Wi1h7N_38J84!ZkzWRRxvKtYzGQ4Gl>o9Y{5!4WvEB)iPKpwU>;87F$^p%pOM76-k<6b z8Io4M&!${TC3JnmWRTra3iKI9HcT9H0avC{2hx^ z!=W@82^LiKnd&_zm(*fHc&*YWSk0i@kJPU~7LS-~}V6<5JRJcH9?N9znt8uDta{pH$s3fZY2rW^lvp;ZFqE=9A<90B6OK(v8Z!tr^s^ z7^?(YpA~to-JefZaI!L~Rg;-+YO+fg<301=siLWq~D|i~IvZ zx;bf1S0Rn}nM6STxkho4Qd|YihE$`B)p1>8Q6Q2}Af}EbF3Vqd zVw$GQe>Qoc!9Nyyew=sNv6Nk_EjMn`oP5`43 zC(V7OTy3kcz-92wExT1X`$9`f=Grk_A0zmUp@v;1c{Pv}3ZNntDwY-a8&@@l^gg z8jkZz7jcwDD=&^rcH?F-+koVKoRhME)DPNdb(=jXMyDyt)h=sG_#?QgOjQp@t-2Sd zr8<>ysBrO#M3rC7-Tof5Y%G(Iu)OTTM*`9^3Pv?nG{Hb(D`fdmt$PwW(Dd4xkz*`; zC4=JkUt<(_b9u|$#}bz6+;Y|1d{W}R?>FV?vmQ4%!C~>v9+))h#gGBB5{bvnDte86 zSDWibKBG{TmU%bf{O=H>0UF0j-0Cv_0JpaoZ#eS!t_R2Cp_y{X(=1*hX=E(XF&l;; zP``0Qj%k=#vVMIj{aYAm606*#pDkj^VM03y^C1$Y9_BZ{-v0!v%#+@u%=okT|_NVjZJZzp%AZ)0T$^I#vFyT^L& znC{!jf>>3{e&j^FOx`jXrmjjZ)$^vrSLVOUC#fOZr>CZs`U-9`@b9n6XOokltG}tn zK)if>e?XD^)zG97Vfg~c41q`p%WRAhiHlHZfy%M@vJWacJuOXDBOTD7!7$tnnG%+h zZyE2^1{lgaXs#m=dA{~yo8^D6R&jEnTM?E8LVTI6k ztukpMq!|AIEu?B>U6%Z67&8K_MNvCjFa-5CsncVsYC?01e5B>u!-6kjx`#>{uo{S6 zh-JfDq}rF=&Ug;Gk3DCd<3&}C6Nhd#*Jfh8>~!B&7CkTWy>b%uM2o#x^6ZLnjP9n| z@Z|x?(X*T-?t-N_N3rK`9Nq-zoO9!$RSKKSWFH?4Jww?6LW6a&CtxhuHgu(^>?1ub z#6#Mo(Rj0Ie;aK$qn^2~t1YLpEmf08Jc(AB{qH<=23&*4#R*oS8lFb6lkin*+QDll z^YN>2vt-JSiy2=of(7#KD74_mdZ6o?8k0&`M7|@YE!XEhaZQ$B=xoxtGD*7ZBj-y2 z3H2tw<*1-&(FF1@sC`e=a6?N`v<6cb9MdK@0jdj(WDlAFS%Mw@eZg#I=V~pnj zu$Gw=&f^6PTV8iR265ngbrdecCfeK?3N*Ww1!#~!0f)sBEU4MI>Tjz!vXw^Mx%U(; zaYh>C#YYEDgdtn!h2X90L2H7WOy%*5I-PUzW5_L$u|I5F#&sb|F9-ad7>|+~?2*xL zjN}^9`eFobGM?@}+%@=;S$H}b5gqY0i7yO9t*;UG^UZ}6@{7?VjipzUcF{v>t3gW^ zQzgFv!Xc`&@Z4P|FN6n%YWBdE=j8^Hmq%@4W7wjZ@uUDKRr zihpgs+<&V70Q~UdE14wXK`Wu!e<wUU4s%yKD-M&5z^FU zA>1p1kLi*;xN6d`uGuOQF$HcF=Klaco(uDisO3kIJ1mO~Xpy038!!sm5H(e`)NnvG z$>WYXt5Q0w1c9o(=A@UgwkCfK{s*GdmYGBKIdUz?6AlJE>1-*2^+3uVf9Hl#ss1*1+elY5Fg98)qJN8nH8)HqU|Z7j8Rr z!_-0yP@LNelO}dOn@Brc&zhMv)KO)H_N*V8oGR zC%N(27i5A4)zcjb%9&0qL1y+uI`h> z&yZrYF|kdfW(M@t!x9K4^fV5n{Bc6q>CQ2@YDkF}3?mbBM?JrCoaXvmtP(ogj@THF z7ZH5-f1`>`nS6@=W$}?A@#`Bk1_ZM!05w(OfczihY@r6+U@3UK zbl5tPrIegE$Nu;J{rsf8n+yqi)J}m6-%EW>3^FmI?>-Ayp;C4)~TrM9$T?a!XAclhJW$-&N6O|ttRYL6k( z%RX;x#vQLJLOw*2Ha0sjAKXB?yPMYf#fX(Aw!A>v-QMVuj!u3`$3yAmgku>Dr6}-F ztw%URoF|`vRxWadn;&Q&#?*zkI=NCSLM%Fg$ff`>v31sI>V3#*=?Vtq-Mcx8#03X| zYby0!0;Kkm?H#qiXK*9S*|+o5bHf|HrNKbOB#IHH%;YtnxTpa7l@(f&IW<1Nr!^R| zoL$*qZvnpp_Y*1@0osLoJVT&wcKOF+3v5b{>WB10O&^2Hd zBEhTw03AoI>DYl0mBbybqxXMeoY*9>q znac8=!FL>39Y#hdja_8%$r(~vi3U2eezCKCtMgTV$m@D@RwD$2u~tp2w<58+uDb); z&YPl-wF8MrM*+_$U2#(H&;XdYOuy<9;=HKE6tWQ@c`Uh)VPHzYNzLCXza1pe(TGP- z-65#SLp`d!%|{C=?!H|DFq{GmU{-3&Lou?mbnPhS_6~_-}rfAyT4FLQJc~#ge zdmYv)N+I+KW?VkJjJTCvmj&Pyij-Q^fGAH zQbyIJ)k{%pjy(ug+m%%yRS$pWk3~EBWf9bmHtI$0mx3OnTp?RZ*}T49lfimK}5CMF?^s8JrIF$GH&vPIQVG{Alb7e}iNlMOZ}Y&6tnG{VR7GV}pBAJ#*bb)IwqZo2Ue#m^uCOq>w^Edn zU&UB_?k>6)OHzt{9KKz%>`riJ#t@LONnj@&pWTXUfM72&0EoUr*HQ>j~A#_1X{E1VpIL3 zaDHx^pPT5lB`z;yjzGmzi;R$8)kFJouXBjXGH>H?=M){e?^IdT$2ari@@Xs69KWas0)nD(I4()Yt*DNZ-gph&4S4Z^Nr!pwYxkjpq zRr6c1?eLv8;}NIb-BSE!vK_7LcD|U`w(cQf#cKRyhAfJz7B!HRJ4OwmJTrQmzKeBS zbBiiMe2slT-N$6}eJfK}P6f*z?tRYZJk|Mp*@aGu;ybLH22=xh-H-cHC~6~s_!{TuuCj6e09BbAfbjU? zXtq^O+HvG*Q+Y@Tmlk)E5TR-H>VL|YFMt22)O0MovH zr`9BGp2{)1=ZZxoSkL0C6s7uUX3p}6kfd_?Nv%`>paOQVj?J{1kzjH2N2w?Eqma6+ zQyAbmq22o@6~{%Rt*@tY`kSRLWd{eAF^x#iCHZrMuQK$B-d*K`BUbb=9VBWxs0yTe zHjB9+E%VO@g!LYDWfKPJM{XK7UlsmT+((nYRq5($YA)#Hs`o@otg)0^Gv4y?j1PsT zB_}O2G%>tyNJgz}Sq{M28`0F&C~xF+YcfiGsJ-#Zy;;)@!Ke}Sht?bWED^mCx~X(m@b!5P?o%wb4mR%`K|H7m^n*CnGG zxyw=~ZR3`)ffGD@{{V1qclv- zQ^7k~KE}F)j&FA0_Nyk6)9r5zn7z4K2P@7$1W`-O_J1p5ow z$Xj5=cu*LA-vad~g4fNOB#AMDK1XRE+rJ#-!mdsaNq>?n-6bMY118o_7PrmtC0LpJ ze1Q_@F2Pu=jDa1&C26&=tQ&4fr2x?%0>IOmW42P}#tJ<=nRkG6-+;CvY9%eaj-F|`l5lEBm( z9>kK?4Kc7RSQIGGX%UD*W~A7O^oh4b4Sv2XZW5voNuTlw&D(dm#-W0uMzyeX>p zdw+4lcIx~N`3WG61;ayCRy&tvUE|zr1cHF8x)_jK*#QjpT|@% zi!ca+{{WT*v4LZG{hn$7qd;80&QHoEkRTur9TJQ~azR_LHQgGywmgPE6d1=!a;Egt zAHuY-Dzw_!o@AbJ(d>*GN{L2iKF1eTj2XYnT~%o0WMM5u9DYV6of%z8t`qMnqmj?S zZ^5w!p;CX9-Ik069`Cm7q$!idVyTFPc8o-|j-|ZcchINZ{ zHe=%2Isj90pqf6RNdWR6OX_8t6SQTvcjo1J@LNNkldGtWL+W1K%6N0$kNtV#@bu4u z7CFL*k$`8@T4XJ{E~*#Qmu=dDlC(Ln4^(JFQaXU?!P6x|?Ty3>_GVA?!^@tel%iR) zI4m3BGlTuy+TTt~mm)>Gl}NQ3vxU7>3WdR|28Pc>w+5(D+R>M#$r)r3bFcJLJ(GD0VhAcy6!uuA$G4B8EwP zOwAymfRLbprMjyEvah;UL?gMtI4Z-pRp}AP z_q%^0*o@;_PQcb=Rz}Wq->=fhlmJ+oLM(>hw$w>t2p+ZtfGGNpo_&E=QZa@-?2@_5 zZC#B~ctCHb`-QpTjm5-HehA4*F>X6_8c38NmMJ0$dowV7X>0{30X228;90Z&6D|;p zb&kxwonOqK)E?s&;`4=(S+p^iBJE;-bQ&Mcm5kp7qzW5w^oA{hf{G2QvS>>)B9N*a z3RORg>QWkP=Q-+WY2)oC!aJ)L!Zu6d^U0o_A8ApJae)HPdH(?CdRpo>ZPoRSNsSbV z4!3JTslEXg2>{XL3Lx~IMiPM-&qA|lsi;co?Y#DFsV(BKqHN@e-Mb#;bKU4P%aJOG z;f~pm%49PTc2_D+s;m&-v(*W4vZKvheAq5&b)IpXnP$JTe1vjqYW{T^J<}<$$dwvPDvtC4$5BVn!UBQuJ4=0^h|dK#{lI3 z%;XgVlN&HnflUkc;f;F&4<`Dfe1Ko486-`lr4)<$kgOIK{{ZRGT*H|6v4{isJQaEE zcbqW3TP7HlrO*YnZb;dMDAvI&7vn_r?DJdV)ecWcfn6TD@x zjI2ZePOO#cR9SacMIo6<_$I{@z~iSz=2ZTYMEf-+O?zaHM!2ijE%n4qUzeioOaJ}eb2pIelG}+u_0B=ke0JW)`1+-)c`mv!M=&!z?rr` zakf&5RdM$J0O{WT9BE5#=Y1SWh~oILJL1yL&10Y?46(72JwmB-ueFeASN>lCgL6cl z0RqJ5)SOvN(m>)nV`Z2f)y!MCykffqq)5)4_Nw#wuZO*J@zrcN-TSH{10u_T-Xamv zWh4DBB*w<6NM}gYsIXWM&plbAC_(qS+HlPRPm_p|+@^EIIWtd178@&UwEPB7lBxJx zuZ}vagPjI{7S3mitpd3ad2ev2gZUKL$H%YhzFJAuiaL2%X4fkek$l5v10p~ z!&6STW)iD>ZZQ|Kd}Gf|Cl9t$F^dSxVdUJ|{{X-#=#(A5EasUck5y(ABuJyxSc0?* za;whPejD*dsl7ZqNF=Qz7OXPj>+Zl+c3!!=5o5AwD{r^?Tt*>)yOeo(YoZ;)200`Q z?F>=VQH|(I7<^g*WRO4tsBkzPCsJB=o8v4m+Qv~ldzHR2zXvB=HXP0|?;Wy}RYwiA z`Neb6o=0U#3$>^*=`y2E@sbRiEfoQ7xC9UdHT!(#>UwDJT#Aw_Y@;R48Euh+y8hVd z(bkU}Vwefa@^=)wu4uCtd>sMrJ(g3C`!A+Mu9;9@C`582$Rl?~L@cN^CV?aobzOT? zPJF?o12WbJ548htx3xX~PM@Q%O-F9a%}JF~4TU6f-X1Tn(RTSV*A7hX(-WtMXYx-Q z%c!+t;3AfnMplhMverQP9TuLR-9L7muD>a2^ku04_TG?0bCDarD;s-X9ZfwwwW)Zk`*zAEJ6votg{tiK=O!#Ud}X5E zMQrQyk$h&j>XV_UYVzJCAytA^)Qr< z_3mTGe-0uyg2qg3GQ`OD5Ig9PO<=1PEVMz?0BqeFu6bPabnf6ns=`Evj@AL6FBmh> z@6(AWzfHOflt?*R$DV0B+6gQt5;GPOBa#-pOrQV(W6uWL``Lp~CxUOL=!B&ow>+|p zreJYZRA?&3F*?#v})GdR_yYL;r;KTQcRI43FI^uF;576Yc~>OkTu823&GyU1IR&O82BrAiJrR^-N9^L&hqcTd}{{{Yl<{{VHP zP{n=rI)*z}sa==U>K~OPSKyOWWgShij?+*q-yO;FrCsAK@o!u~jbxBfYv%Fo9Au#H z`*cZjJjxE};{0T*d!q0F1hx7&+wsT+Xf<@^4KbX7mf0@$Rxh=(>fXtG-V5n)hT@aB zw9Z(&?Vrnw;=I9<@2j&Kk#q@hZT+WaWU_^votTeXzk%`Uj+wS2DM;oB2sk3}ocR2h zdg-{BM0Tns2=;B`$70GqaPd7y5RIAU*o{u=00cCYToW%5;D7I0T9sSC+%MCX9#zs73EtN8ah1rRBOjZ3+DQ6|UkC0p2NN5GHyYv>=T z19W2~dxWE4a2I5YsJvkBcCB5g)i^`?Ipds&$Uhgnu4Ol>SHy z>%xz3z~ipVWWk(RP|-O1oLg=e0>c?xv850SZX^rNR zK#~&0{b`CNgQ+S;r9p4CTCb?%r}bu!OX**3@+5JNKNXCzV`Qdw9CL+a(b_ziN)Jq!SVxf(o!zOAi>Ax`(Ue3RtTMS*d*{ExCdw|`(ty4i@_V^2fbYY#Gh$W8h7>Tzy@qI)ODff~ z8u=T2)DEggupv#lbBi2mF>0&~d?^|a$X{8riz(YE?eBApqKloUIj=aZeAUK>Hd)=B zVpuf+RIj>718nZL4y?Z*SifLu$4HKh)Mkk1I*qyIpgiODbDoRZ6}}H-VRFkRFjhM+bQx>~ZGH@A*f0(9FV?sK(8)lFsi-upO+6=e?%^g6dT_jR zSe|j6`${+#Zj+0#6z!v1&mCa5|3X8B-Qe z>>>cExG9Z!po!hF=v_uwlqMlg!2dA$_Y{!_{P>+wYF9&SZqQ3 zQKM7`rSzp^6kW>`QDbeF5YKzZ#l8CGmbA2|P}7;am)QOnb<^QhYPsM_;Nz7tv`DGt zSq`Kyay3Q_swj))oG&%cN{*bNJD`aiW3ZfqXYZZ?#vJQ?Rg|SQtInKa_EeZv3&nS9 zh3at{5h!Fs6ssTie`zhcfX`ty{wvs500Gre)r%%G*jR*-DzV5czHY+#qY9K|%r=1W zJ>R}ZwkomJe&E@V$15a$HdH==NNE$)8git9qymG2Sz4Ig3W6g}qz-J19Gh;w?rr<8 zYiC~3($k)=y^OeVmfTp|SI*SCyK!Y4XL*aOIP&<24B#MZW9l6b+f7EkTkc*O!F1s# z>C0@8vG)Ppatm2G%gfcenh?|BiFmDm*Ew0v&*@$>eH5uY!&Fy^ZZ;-U_c9HMA3IjI zHUUSlv+LB-bmb}_>PqoBL4htZ-BD+Q0m)BN&U;^U$#C+7Q;H)UrQ-eP^y)H_qL3^z zskTxX6-u)m&Y-dKGa9lD9)2jsHTI;h^sI`0Nmen=+v-WM)srdN2&}ggl{MKavsJfp z=e~NYEJ9$;sO;g21U`z(rHj~*Mu&ic+4WS56vcNqch~_meDh zj5xZZskL{6!a+`6W(j@i#&GUGNe@kr22&RDF3NwO+c6>F%-2H5!yx66+m9LARtF!79UEPJM>B44pq zBS0WJ>cm+t0a1JteQD_EYl6v?D+Gx0HTN+hRTp%f*TSS-Y>HFMyK{@KSfNEl^6sS$ zt|nT-Tfu<|48hp}3GCdGu1c{afWI2Cq3~~}%SI$sp8H#=Zol0p!9}6|-87AZyJMUr zV2&00b6B9xC~);+KI@wlu3jk7N~!>*mbD8^RM)E69<)a`4c}R^evHs{A~lIRE-dd` zq)}y`(YK?C3tiTg?P~A7N4Jk1?y5;Lcay@hIkDtTBPA8h5{S#H4ffcfV#|Dk)w)ci zl4Ar{F<>EC-3Yl4+2YI)nJvpFJ0b$I=6 z{8{IokM{hfF~N@nE+1gtU5B6=kZz5Td0)>eqUfHhhOVs)O*rkte{vW?vv0-QZKKrl zeMPLzK<0=P`ED_&{3Dz^6tgZ!K!#}<&^07%0RHd81tf)`Ou&+&*mKR=Gl8}<4DluU zcDMY{uWO6kXumZzz_mqkLzdYyJBD7j(*X@k)q@ zd|azEp0>tS1RGX(sb7sjq0c9&KCYyXQN3kzlf>4*qFgMBhno1_qwB~EHaor(OSi^%uy z#}aLotaT%1cq)!^XE@8=j9*L`h2ew3vGRD^MOq4~+_6w-At)(M$Bz(d9M!jamN?P8h5ck7nQWkR(@VgxggrPL`+g)?iY`%70k zi?PK}X3}WNK~*MkluYL?*835;7MbtYsEsC!Mb1LZ)<#`}wtsG;X`WYgI;Nn7WoEEx zRC|0il2|ATJ$W}ku+)Y^<=KNRyIbyBhlcC%(M67Z%%oqml$i6Hh{~`Zp1O&nEU~FUG?mw5?3*Bvl!JFHs*vI=8MNw%HqaZG*CjgMn0ZJ59BuUb;)?+su52V8L`SEl2G=VMN&q>Mo-(l7!6f+ z9>9_b*pb9`5+(H~<+u!^&28IU@>EYWb!n*xzzFy(Sv$MgbzHdZ=RHH+B8MwC9%NbK z@Vm;Du+%d6jBdfXz8HoL@(uOrLUYx2>hHW(q@-J1`;6ZOOTRq>oEWe2kH(Vn(C@4$H4AOetQQhguE713(gBmX@=rz9^BS zc#Vho_Xo3`sF|!*DTH;1hQl}=*?ds9-xP7vZXB@X#v^TKjX^UyqaiYEs>4=r3hqM} z+u$<+W2z>4ommi+Ch4c%nru?Rq^+Rd?blUA}BP*s)|3j6^_KSx{X%Wc?xtBE1H zaB1!Q-7RpL>WR!2QQafk{L4oXxZAh$%hxT3q;a}Q8P%0e$7UqzL5#T8I%DubpsmGG zKSQADN->;csNpxv=aNOYmCgv`q&kTm+gO&^vSc3xe_tmFRnYkG8a%M(MSc`WTAOfH zf{UUSlZ~tnH3aQKrX+;=W=852EMIarFF!nS&n_|%+LB2EgUQ-ak(^?%rx(=D%Fg0d zSCN-ez^b;kL|US_QO5>|y1s0Y6g1*$G*8=DVWoAuHz>voPXaAgSFRdlZ)Fnf?IInx z0Kwy*9Y*^)DOW^P)k86RJg{44a!`$d*zHAD!4=SYiIGj);1Wo%V$oq}4cpS*4dsGg;% zQicnz^nNJuo(g7|VxrJeeZ9N;o<@hdTgO0;ZZ9M+46(|w((c((mI_p=dcLCn0CV6G zWR~ReSE1?HO&vj&DJLk_ZLfDZ=f5Y8nP%mIP7tBV&N8%fjCbm96p@B!LPG_!xd(B< z)pZA7$sZQSlS8YaJy|Rz^x0$`ktP2Cirjh1(*FQ{l{xC(V|LY&5URf$(qEkpxOPtF4sOl#*nT%WK1m5E9AS;q9B7sWUU!MIl((lxX^(1dMXCfN zmP5GylHJZ5!hgFkf#-v1S~Xz6BZ%unO5BwK&&ee4LHt-9OzF!~Ug*gHU9>rBmXafv zDSW-Fj!a-wMzpRjn_ryy6++wq{mcbs2(#DuZ@X^X6H}=3aLcW z*Qq+!$QDu5xavEFNc*DPA&5N~U6@N;u8tETVkS zWaFXP9j<9qmRaXmn8h=oF{{d}$#)}AtXY5T)pB{A(cdNw8-D$(zl)6$tk7fkuE}qb z)OA^%iOpY!ZqJX-GNs)NEFbjHz`|5W#4hB85p2wi2o=4z3VAdDVyA_|G0WAYAz@lZRxh@! zs-yP>D>A7%>;~iR2tot$qnj+Kd+yAp*Ur}|ea<}d(mt^~Qa9gHaX)%dsz0-QJw|1e z`J)QF#^6UxZ*YJWBDTG1=mZvidgR6tV~a$h%E5N2@m_P{y6K9Po$b-KJL7l7*=1K5 z9;?sfg$!H2Yf| z+;*e#t$q#_XOe7rs#79P)WHuCgkl&42Y|q82U85W5Y`oLw4hzIRIU>_ z!ESna2%?*1R1HT6Q+uH$^HTk*l&pCf5W+-&G;$%LOEKgs0LPG|S^R%BTpp^>)zyr~ zOr<9YD2ze;REpqAF8p*3oG)~w2$E2aRPa^)X$x##3*);&OW7`C2*oW(y9_AOmQY20 zO08d7X0x|*BI40ikmtE;1y&% z*#6N-2{-C5peMCs4M!$;eB*3d9K7?}i|Tn?LIquJ_RdOWC1&Mw%W_`(Yy*#r1eDJa zUtn4$Ku8PdSqbD_Z$yF!wdSlPDG7pB*7h@1{0;NMTm3RD(%s8OE^`}xDdB0){B;NE zjxKyssJ`Fa5JQ%M5XTl?fpGFd5$bXfG!9mSNFy>6U=EVlZFIFIe57Gloy+cOGW}Lj zi$|&TryWY&vdmy7Yl^vNIQXpb(PtY-)_n^gLmGfpg=z|cXc<5o1Hl}V_VfnZ9G?tE zpKsl?tG@iv@zk+f-55=aceWsST(3y@+%PY`dtZBIO%Rgx8msBapJpteBV5$X@- zjfp6gBm-xloC@6Sd2AU)uRm$e+urzWI%m~_Eyr$os&QDfM@ibwL+#69sIUU@Al)TS#d7%ok=1^ zN+d6^R19?t+kyp;f=R3Ox+L&hXL8IOWOWIt-N-S#I5}{f^)Tv^O|b&0mf1ACxTYgj zD=70r&}_!Yh5X2-bY%;rfQcvHw(D|i2El!PNWYGdrWFPaebZZTR_tfO_pVau(e6OnQ6R^>MN32Sdr0^ zloCcCfv^5|yaLua>(ik2>TTt%(ytgh=JH)8I;)>FnVCV0th$ET*ag_fAy60q125fV zYisNqWj%6!qgQomGN!hk=?%Co%K0D1PSBLLZV678-=-FGdzvqbi*(@*I*a#FVO2;? z3Unk$q=C8E(II#~)HNKPz6$kqXUsH-MyOb6bBt7^O2Zr<+o7G#q%tn-oMONEGlkylMsAL!8*z7Duq-P0YsDS=|~uk^Ntn{{U{3!e~~cGf0}2uM}Qe!-t>T>*T)C zm?6lU8!lB->cM7IjeRzviY&1OsGfKq9M@XjifOC-L4tCzaJ;_cDm=MY<*vU;)b~W0 zM0oce(np8IUTq(@y^L&d-C6ZlzZC>eQ)*)9J7UJQ`N#Fsz*&C`BZr*l0Xj`MU#K)<&XfseS1LPrc&Cx0!Ns*bE< zS#=7^42o8rt6K4jD$A&5`CWDhf`p!-49{5r5J@#Y31?J;+yiR!A@UTs zX(`Vc>b6D+jQd2ast~Fc4qaJ@y`0|Ufydxe3JcGrqo*QG#gI#8nJI0P@fKAtH@m%2 z!0j}<3txA+VT!>_tnzs?RgR;0KT#5yA6oWJL0)$J>q>n}GZtaE3t$2-D_7HMODOi@ zF9Y&}69qgtF1qBkbfLOZ9o{1t=diMoo92r1(X1%o#$x5=Syqaw4|xb0s4O-jH#S@r z17Yj<=(N2qtaAf*7g}_+$hM~Bc=@i~BkIOp;ILEOCIfxT!%u7!5_)UL&WJ2wmN#QM2b9#kl`)D17-o=G=DLrOZ)efm;?B{spE?t6QL@sg~oq^^@GG8b;Fcq`iXrQs1P z{{TxHB+=o_T2&4Xv5y)s8%RJvh*_urrHdbyARoZ$?MuX2&OXqLB^iL@^&1AQ$8*n0 zbr`X^u($1$F>YvR4<6({er9OlQnw^4!SRqnyk!j#>TMl}P%Q9Go8)ws8?&i6l+Z(c zRd;1o99@s(X=pBh=@WLY7d)|`SGH&XVJdlFVMKab}__g_-GrzdQ7tM^J)g?8bNdo|0|`dX}O zbfF`P+%h<(z&p`n+pCz+sAYGNG$Ae8Fm)wg*w7)trduVB#eNO-OmsDf$(%l?v+gws zNtwmVz*QF8BJo{Qi_yGi3PwD06Xfr?O89xegZb|`EC z{os;7Jx3;)lwqPSpSbRkxlm`a*U8j6tZsmXob1K5Y-*VIw?1nROc?o)Mp`_nMm)N) z&`IUkwXG(g?mj^wNEbkR4xOQ?ur`*fBqk2iJZ6qLza8?Z!(eSCAkOH{LCbh=jG12F zj=Ef^SklOn!@{zN)DS^ovlfqK1A@bzEPe-C#-TFEYMfgsK_cT3H!NQ}Zw*_06B)?& zI&IPiIvKb}Yqgf}`NqMLid5HD`BGmB#Dl zCUZqMiaXoL+-u#a_V?I-v`jvHd3voMfn`Ny*tW{VYh<85CLoiL^{&bw=?0BKA|iW!oR>w}bP3VaeLi zll(EXM7s=^R(9=bps3+-)#CFkFw2^NuWmG2Grj-(==TBecbX&t;JlV4m=m) zlN_F#KXj^1eXx=t!E zEkm2BZH;mIOtx8P8KCKK`52anZO(Aq_Ml}r@Qh#!l7=q*gQ5CGK1F*mHDBTX55-?&xh))f& z)3Wdc_YT#Bf~a0 zm4szcrcfDy00&T~KoPeju(h>OWK|jcK?z2sQG3GhX4RF)j2I$=(+u5{w( zw0-ig^;vcEEN2}AnMf&+=QSHqKUQ2{aX&R(LK&q6OaaKHmsj#1iy9RxU=}2yBFF>y z0eTSD`mo-S2ZjkcmIHGvOE&_ ztFkCUWMOJ*+fNwegSCEo(ody0?B6$%IF9SZmmqtn9B>aIr>#9@#GnK2Sfei6Vj^v! zyXW>gwcTTpbLO36jwrIQ@bh8PHAT}t1bLJtmDJ9%me=P)&m11SC8`S0^km<{*Ed5Kq>{YB|?m6M_Sn64{#>H%@FoH)Q zM@*Cfq5-Lp5~pPfyp8M!^*jO88=(lBj7Y1LV#SNiv6N++tER8Z*S@5ci<7-a9QS^6 z{{SyXu;BfocS$2;15|KLvI4+y_7KGIZ)5TJ>HFb5IIx6c?KY$&M5}G8kmsGti?Bdk zt~N(ZuOx_mZHZj*{{SyRbFq&8R)J5BCecd(o}@Cl0dLb znhFUTd=O9fDC)nV0gv#K={Cw>-)fy8V9348Gtws~^+s~<_nBOlZUYp)dFQ46@fz&K zWv|r8!D4Is#-suk!6>VC@az;V@s? z=BV#(dZSK%QX8QuNqDP|o(4mYG@N;AknM>ast1$w#MUbXNl9zg#9 zd#b4_1(%ElE#n~aN#JY(fGUlSxj5Q;<6N7vwUpc<{@FY|1Z3&+s}%;L^y@A$a!mgK z@1DGu6=j?RbrhyvX}AGt6gMguBGFSoSg*%XYv86hZ5W6(`8nq@BCno$swAZy#G^lJ z?PK2D2P2y1`_X+YD(x*e z#?gNv%BNImPQ9cwi32MGv`8n^Q3sxM zw41@UpD6VDWtRLhxg*G zZFS-Rg2dBpz&v%MsLSb_2+oU0U=HaSNVzC(YP%HlhIdOM8LNe|WO>Sd{{W7?7~@$t zI#G>Ks8-`)MTz^vdsqVgFP=J9->Cwj5>bwAHs0H+`n<&BaVg>hMa$h>B_FcBtfe#Qo&gxn+G|w zsW-z?^$mk zpXRTr^p|ru?@Y%xeUW5f&uTk$ETi_$Tdb;*?f`LMAB^|%^vQ`gfwd^Q7^tuyxJ3X) z#O*+XCCPrwMUnvNa-1ZF$ud>kM)7yS``yT=9P}EL!FQxvxVj9z%jF8Y?TmEIi;-{_ z*UA3?7DWZztpQ|^7_j(Z!B7v$qRr5is{N%=D1*Yv?!5DP&2iLH+Dhjp_@)%&oLQfa z&6%gKWoTuBc%+KsV8~WP0jYHWf~R6ZJFRkzIOKK8gYDGR6l@>9R9k3LxU;(3$4Q)G z+7To6?u|o|uD(7a{{XK-@UovG6CAHo!talg(ebg3fLVvyL~})?i$D@tuDVMt)BYO5 zBa>)H8Ru(CuOt0OquRzWMnp=bme^hty@*}jf0*!fbaw^?m7P^|;kRI|t59|~bwB(=zrBTP~FBDg9ktlnsC;ByIZ}PD8{~$(Pqza?z)X`Q7Z~l&MCfZkNM)2jkk~W zD~{-X&NItpM90F1ci38}VOy(Oo%pq3V1IF?4P8O?V?EK?DIf^TZG2Q-+*xivJp|(| zNTDdz2ml6d#T5RvUAnID`6&aks)dk8>$!A1HH$2vxhl+7{XqVD=}K{`OzsHoHsi9k z{`?C3hE0J|oL<2mSn)<%ep@&?Aeid#g=u_yQHb{x}3vBMnN9?fg~C zX5=f22Dr_?3w6-Q(=CtGzq{WeRNd7DCyQF+2UhX%W=S%oGN^+O1@l}ydoPw9qsBt6 z^h-SHMN~hLfumL^lr+sSCn8+?f?wJ=!JbR}uTwhhf@#x%k)C;qOD8K~@p-6JMm3_)#B*$m;02i|I)%WO(E+RtlqJR+tGjpg4NA0r;W@;;D z!TcH`xuYE>R!M}FcpBPe(=Y6B8i-b}eBiECM8k<>9R;gB7g&}ycQQvu1KE0yX^RuWk0yQ7Rs zqZPE~F%H$wLn&>2?jlEMZ&0w{i~ZLb@zf=;@y@PfcYRS+SJVbRK*QJ+paSp#92(#g zKBl}Q9kSdQvLhm{t(L0pqUwwm=DIItp-;68NwP(8<;{1`mad9n#Umh=<|`vE>{~|* zu?%BY*m{5zSO5>7k<#=hr@1vDqzESHM{+iZ>8B@-)yD#VhWCuQi|xZg@oDoWxcqc~ z8x}^8h-EQYAw$F@BhoC1G zDAQxI1LiKwi{FrM^XY>n7>)NNYzpYC{>`AFNG00}5c&y()yI&__cv$a~<{Cao1vW_(kh=m-q*1aIF)MXU( zCAj`s&q^jji{HJv&*uEt%TW!dwcHi33}Y2>6!`634SZa%a}2Tg$enyFrPWz{VEE3~ zKu1;#Q`MA>EDI2tW|FBGh5^=;z`jao4%dEZ$5iQVaZ#D_UwrT!(OBc2{R$@~QbrN1 zj~qqk3a-VZ46L@G@*8_wKDvN;vDXJvQIQQ!Gk)!>XA%|ut{>l{+Y^>+x}}DT$7lDi z->%_L)C8F06DOB;j7Lt=Fl1pR5BZ&d2iAr0L#DcOWAB#XMnt8y+ELw7r9Lx@qdgZW z#EhD&Szk0^t`61bp1)+q(7Vh`afDY=q#itkFNxR+bqt*nL1=(VIw~DOq5(rd zyuTQz2l5T`(`5-yPBMO=ZEcpaTqS-2Ienz-|0c`F&di(WF)(}Z-jG*iADccZbK+luqkzQy#gcV%M7S~@qk%BWHa1$nJ6 z^Yhl?N-^6g>5$u2PU%my;!RqXH2653QoY{nC`#=9Y{B>*D;FAinma6j76Ztj0#Ud& zt}HdJGXO1l0?)@QhL)x$qpK<1a4{=5O+<}WEFSlsxi59bC8*GmuH5^t_rRO;((HR>$Nn%kbB9Q2JLUK1VK9*v6u_X)DG{uDTkKj7p4duq9)? zH{X<4g_}lF3K3K&l8i+fqDihBaC2~s&upUV6WboyCSG{MjHqX? zN^DsScRY$R!@-OH0Qa(a&q8w_#P0}Q7gh^u!Y{)WVhQ_}RzHhT@$ph?I+B*y>l5u5 z#u%jd9QaYsPSa;U5pRYPB2{+Mzl9=)f)=-O^N)r5S7t& zYnofEi5PBJ>Ol~(+*4TnE;_D2{J+YX&UZBy}@Gx7f4{$9nS%P)vy*V5?9y}&m*V0 zb0dT$S(f5MVAkEs?W*BE4!t%+Z+AHNMLBDkNvi`jRgCp;i=#T5YGJA2i z;gIg6k{alI8vz|XLkwp-_ggQi9ls=){&D4eUl3!Qi}0M7OkMDN`L3m&c1V$7Qdon^ zY~C`9WDqW$fnj!NgH|{`kEqlJBc~|v*hWQjw`}f}+msv2(iq!R#k!3^l{6SdPTZ%* zLa--XoR=l#F^MS}RR|kWqL?3G-*PISg0wgtE)mkbv(Y0bzWMIAIT@zklKX>CO4N09 zntkVaFqEek{Sih{uhf1q$4xRSv@amy_T@&W*Mg*KegQg`Bkn9X7uKeo(H25{jHEvd zqZ1q-799?rtTw-`+!eKs+?L8K&n=kZ@xVVMUPlqCGX?R5S7oPeBx=`g0A2%Dzm9rC z>2%lXF@%G}QzO_A96gNJJyKH{HJWP0uD%+jM}b-Ft%70OLDeBVrj_O z&;;8206Hm7IET}r{YXIn0Lf8#z#J6hI*;pU)4ufG&%EB8-ziJacPe?Q`+f_YlRn_a zfnH%Iz;79=C|O#79N*;M&m=UoblF%zNeZ(!669hF?d&&sL&r+i)X`!`>N4GuSfRSh zWWC*lb6=i>_Xm9J=6MFurz(Pg3P}KcfQ8c7lERIA8|ZyRX(c(sWqrGox%VL?4(NBG z6tmKc0NJY)LH;AMUj{Vhe`5at*oH&A_!tbR!LhvkzG78=$DC$knr1Yy#U$}Z{h+Dm zVtPGCQ&It-z-T?Xp6ps|l13@x+Zy4?hiU0dmg&oI)fZyt?P@adcrDIE>+}L-Xo@M4 zGCW&(LOE~Ckapb<=7#(!7hPs*XnL5<)zlU@X(M`%#AY9i#=qUo<~J&EG-C+lR-XQE zldiJc!z6J6`(`(pn>%+h_d92jbB}#LL85($ zfT{*J!)Y&2IY@HjPndg?#nt;Y<5ViXwhLw~xIY{S`-RX=)mi%;fU!TrlwY343z^QK zqN$V!tb}1O93+X;iB7S3w7mm3a2m`d3Qu3!M|jV_f>XLFzqyo8%qxIkgly?Q#05O> zo1g&5@L8*}k@dpifb z7ilHm;EqpArVO17GyY;V_Zsx3BV-{e`rJ^>!0=Yl?j#=SdcW4ZWkO7yPa(Zd1qrK4 z+g8q6GqMN9*V$5bS;d>d=Z7(iJg2#~Mjo62yM1%`NhY%7xSz$b;ijidufOO#3uRGc zySZ1hc^QF&;!RVUBy4D2jDLj4d@2^+X(VoAdpeih000)OTo&r$g|q6 zp|F;;(kIgjQ>?WT1^G9fNG*krXQLl)KsCF=)gfD&pE|&cAWmhC=(dQ}GgJrKkY#id zTLEtxY^tm%=S6nZ1m~{L(cpnRZ9K&g265fQ;f0j+U=MystM@S8`suanhpUOL?gqE? z17S0l-3OSMGpJ))a#9|Jxq|E)uKz=PD#A6vdaME8d#+r`#(Ba`@Q=}OIV`bETAVa* zbIHZP4FkDx*tuWnH33yVXG}Y)l8?Sd5>1oP&bFgTe+S~KMf?EwcJUaGv!*^SOl*hu zCc@C>$}HB0>sd3ZJ9tHh@92wC2`7?1zC}?kof_1nz`Y>7>-eDy1~7gWmQt<8o?fFn z>!MYS=i})LZ~l3}DgQCfEyTQODU3|wERW=LBU+bqGOBx!&zNge6sOY8Cft2HBRLJt zL4OV0bbZBEwyeaAWMs4b3|1jSZuJl&#o(m0YJ80)YHpQmq-m*K^-{ngzQG-SlOMBE zV+HnbrWpA+n!lEz4!EvZc)+VZ%3;tovoQsGo}?JjAMf<&$(_%J`kDpOGZTu` z=kD-oUBJ_pa}>vm#FOR16PMQjqh()~Ty#SzVe;H>DjjCng1#ucXcKMSHi%thbMOH;smc|)JL<_6}fFCPgEE+%=KL;+AOdO4Z z*eL6}YEqOWJ~kp^MT`68-e~eEpz(Is{lHD>3zG~B;!OOM;`4!|iqXK{=!2W#_xO$n zUpw;t4q;&nN_Fi-l^ox=u#hy|3??)zP}x1jua{Hsc&YR%&6Z8r03 zmku@5rMNoJO>w4|P2|=GTkkk4cDYYkQbd|GGAo*TFnE;CFy77owI1Q@UfpoU^At1E#kr7UfNi;}*Zs#xP9ctZ&+~1?tQ2b_sZt0+R{`+5KAP5)0vON9s$8e_0);(G84wT=|+r7jr=Gsk=G~38_<)$yUVqMtlYHu{LZY*hU zSedZ!#Dn}3Tsdrc;399{Wc_$;|Dsz_O0|{IVo4vUs){v?-pzRrHivK8=!)ckMvGyvF%yUTTAt>G*(WPlS{MF0FTx$Ovr8tY+uHoZPNVeh-k8vWRt*deHB$lsbbFPl!zg^5a?UBa_R9hTxG!k&y?X+Wot{88hfb{ zQs$FhOk-}hTE6lLE4?ej0<5YwW&%_^ zQt~<0bbe&qJXyU0K%_vRV0C}=SDdp;H`j*5$`NC0ZOAhGCyXLgv$_(0>f&RZ!4UTC zA2eF}5L_RAft^5ozVVvsMxC*eija?FSkCKZdsYWIr0Q(E5;!B_@Wf0dC<{j2Fv{?* zl=iid^;)?Ir3k@c>tM)IK|aFBSn;fi7&J%rl7*X+S#w|^L)KVSxr(h0*?-1bX;zB_ zHHMYVz4ZhaEn(|h)HT;ED zkP6+IEW*z2LlY@|MIoxHRm(Ek9=)oRqvIcN-gw;~M-pbQ^)IQXlDy}kRNN0Li3jV@ zr`nfD=?u7IS)i}ci}TUhQjRuF{g`*im3<32BUe!6TO+~duP;@iikDLoxBZgWqAwxf z>_4@?Py)9+B!iQ?ngP-TLB)}oF}+*d`1DStDUVrK!-a{%_qeF~wdFkcy&r*$hfoEb znSX%BqHjo`zw7(2&CWEkuw;+jt_lZU5>@P&C2zIc!k%Z^yY;iDL>^s7s6fJ`DirkiPs7BUtAYrYD$(zcoN^HoOew_PkjkWavQtdi&EVFXtWaqAYf3% zT@BYtb!HM-Q+hV*@xWyS0t%(CA7IVzA_ggeN0p1Ig6-ZqX+Mqf#74pBf@ zmFG;!Cfuje)4$%LqyL2F1T(e)QQ{Ve6l7jC>2g;u^415^wrR9AS#q{1A62PCUH)qse)pYpz{qdi>uL8dD1R zUeYf=9zYlDGm3UaF5D2o6FR$)GtpAaxZ zO!{}qnYkY<*W#I{?#XiMVk(Z@9v6)w^oxTCjv=dg5FE~tT!~Jn84W*bQ-D7%Y#UI~ z_}ib<@eO!c&e0St37PsqL-Kk8;Z>}JD6WBuDdLSBu}Zue!}6a_flndyO4nN85+9hE zjo6-ap0nxJrEQ>Gd`DH+QBBFK1qdeQo@D1x{2wRKL5B>rIWqY&GEW9@9Ti!rwQ&3# z$YN(#b$7Q`CA6W;bIqut-DElbsKi7%?fXZ6Wy$X)_%J1LrwF$3gBF_4(RCLT%jf#o zN6s#-%$}|PtHxj*Rh=%ui-sQc(uaesxTnJ{CXiXa*0EywQFO%h&}T!zbULaAf$Qfg!ia?6k@w>6G9;}d{W zfOAJLDfZL%zq3tLN2aMS*Seb9bhFI#)qWF)Sl9*9r&pH&*YU`9h&YPoxk1Aums@25 z*~~*)60THE1%cRHEr?N4SBvC|ZBmA*ma8&(VWD_@%`|JW)%~#bz^=Zs{Jgz|G-6Tu zyPE8x`2EWn$aAr)+n&82Zs_QHHH5F$Apk4i9RWPIb_&W91%u0$=el?Q^y3fLIsI-X zaI<327-v6f<->j`Wf^n)wlxfsvO@d==s_iIml`uO37hdzm$(SOe-{1qNhFLjN4iLW z9cZW;GeXMd#;YT;!=J7|#}}kkz*8+moWS?EZj`&UEif+``0Qq4YmI|t@Xql{A*5n= zl=%dpU4h&hYVf(v9V~KgR{Je!5kR*WUFQidO|` zzfN-qbIUwgg;0zHrJ{BB@W|-c_$M3g8FEp5PqVjF3BH@Vp%M7-2+qCcKl))PVS;k1 z+?=2^=5O-!SGmMiLamus9c}X>;O_FEEQBW;$8ldEDt)3H#FhSe(7<8gB{Q7h$6mwT zw$GSgB7>fP1eVid=>C=SX+zyg?(8I@8{RilfRmVs}QXjAr z{nu|0KRa?LOVd)DM{S$}FILgIIIDccTbB>+Nqd>S7NRz!q)fWQ?Alvx*8}!k$Rf*L zCnLbcCJ;^sq}6u4_s#84X^u)s<*_nS@ItNzlS`dYrvwuvy-)T9cb%3u$oV6m^a)(; z!^f9vSL?rY2g@$Oy?<54IKCGZ2^(gacS3LBC4uL$PEpb0jXQA`8g|A*RJw;zD-g+y zMq6-aIUMI{^(!8ldsa$~*q+)L>{PP*NZ6)}GqjeFo!*7RE0jcaKZ~1nH1pKJSoD_~ z_b4EqX^dfj_JMd-+fXp$J9|lJ-464jsOzeCP8}@_&w5_Vl~blqkRJ&$o{Le9=C=Kz z(MZgJYHX2Sf;Fl&#zbziqJjtK-k;W<`9R^9pPT74nW$O$w?CF8KG=p_3Mi10lX$7W z&rirPzpnv0&(8wQ0jcE&Mpr9VT>P!OI(~mn8u_w^!4NOvgEM8|-S^rJc(c(3nP`7t zD#zrNf0rHZG0*k(*?|zO7DgYPUG`-V*Vpqc0jXe84Sv?$H#G%L8Syq~IZ5z{S8yXH zRv7R8rB`vvrO)`*J|4^+3B2vz2#Ip(O`qjxPQ9%rHRG5$t(q5b#wGjWSD*fB1t_FM zkXkSDIxVk)_NVBBDMxjk0!P@z^g9#5&%_>H^n(hWxWVWe{;*=IM0PBvcx_rI_K;GW zLW@b`2#8Xr2ECo{1Te3cgQs$)`Ux4LBwTvH{S=yO?Y( zj7(6Btf|LJTX~HPH6OoxBP$y3}kh)gmXwo?m)Ct+&1On4OzcS^zhJ$jsv6Q8~yWRs9pX% z$QGi;=*IzFMqY!BrsdbTXg}A#;Xqm!pzDUJaJ~;J@UrXNOT>>M8^;g+<`dnWRy67b zX<^9`tLbq6)gOrF(oq-Cd>SatEqvc|CA*u=dhuQ3y`sseERV|1N_pk)twOSlkp|Y0 zLM=$f7@3mBQHShPfRoaQX1PwhPd6Cvf6y&bNdh-+$?s{G!1`zCQah3!~k^H z3M{TRAePmBb@4*3kBybKp7-gu2LnuMlItJnDXeCPx9`5d((k+Ix(>p37b~b#j#ac z+KjND!R$&pp?u9TK#i4N1kjbnE<^Y55{+@)?xd_#r3IqKW-^z1|uaXZ!GbO-cbTL`?n9k~Pq|#FDqzBaB2YEI@`|t_0yd`3WqitZe8w zyIy6+^-c0ygF9ruGW`1n$I;04P@sAhLjAO;!Tbxp#fQV6D!=PJzT!gDE*4je)E639 zaWGRg{{eC!2Ln@^_DN^6Ns|Cc<6thn6XJ!{uzGE+>2gZdbX$wDT*2H==NpeJbFXTT zej_>s_WZHkPU)rs@Txt)Jt^K0icc&b7_AtRab%}i1o)tP9J=!Hcf8YQ2S(ZkBRER! zhf@u`-+N@*p?c0vM?7{N)z$CEK@Pr=(~L2^@EGwXqOTCH6q{8OTH%_qtHoIJDf$D&e_Yu*R3c6~@)> zga|*M2z=;lW;0T__{i`+1&P5{7RPj3c#G4{WP;G|1@l9|sgrw_=pLn^pnp@K|B~`8LZnL5W9rz#Mtp(<(poj(`O_OAinU+bEH6GVM3bsAUz;-3B zEU(Ml)%9&~L1h)j@Jc!5M!T0>$jYhU(kGu%DsXNd(2;dKK7dufRI_Zgda?_~AeOSD zk|P_Pl7t~h5=D-6v4`r@pla77!czYxl}9mY4(Pf@yKhxe=hEgbb?0;(To3p1aVjC0 z?#xk-B(HVYg^%y-n=o>)d??mZ!!jXV1IT%-yG5vPJ;(L+@~SdSa{eHT6MS~v6h+l` z2{I|=c(^hBpqfkfoNM?Gz+xv_*Ga;YjouN(V!T{&4YY_^a5ACNcQXiQj2thm6%}A( zaPoiT=BO%77~X#F#Vl*#Y8B@B2Y{wV=t2(PPL}8`B6f&Ny4woVD}K$5F8+*cD^;WG zEMu)iEBj%j7O-OO=6B;Z`U7Cc-52bOA+KAJ-p!i#HQS27#VK`r$f-47Y;6d)+1a?N zyF%V_1;Ersbex~eXsu1b>b6uPHX-#8TK}sVd8u%X3yje zk5kl$V4r=yMh>%y>J^w7-#K~ZBVexqow~2qB&qU+a_=Jb54Y(0e}I?y#f$Uy>+H)G zqkesVxMA)|ny0D&?(IFskzUIVfIoSBgrj?Qg;{Uk`{|{DtOB<1`&w zFPAVEMraq<^hX|qiuRVLub0DxWSs)DZzP?+6`R6@_GTYyr;_YK-}r~gv&J=DM1{rq z+kF?l(I}Zyt8uf)OCc8J3_ukv_hw`6e5 z-;s(Od|BObypW|txtlxICC%s~F*|Oxw20?)y@|`MeyJea(Z==n{BZM9p7c*mtDzGQ z{&YzoLqj2>)$fuSXgb$yvVO{Jy&bxRD6V{Yb1gA@>y=l#il=Mb&)t^%mvmjOYN_rv zBs~G^(lT3LkKT{hN5|`m5Tx3QC%s!$%J>{P%6v~gH21&(xT}<8IEn`?Mo8}mK}}{W2KbD>HDoassneZDWiWq! zmGa6>i{6tBCdPWWh3RGpXF z{^5^to8NWb`A;t+n|@$={7trAc@e`Km+X>iSCKURL6$&%mQ9KJ?VDBVkKi-~9{t1( zorMeUD1)jxD8H_nj0XAJgiPA^gud2i0hjYZHVAU)h&vm%a$0iL%5q}s4a=St^e49P zW%m*MJ5i-qrC!R;J|QiQ<9$$y>1;#HT8o6&-f*W4=9Y6#;P zj8{$jq|0{j8T1P?A2e!+!SPuz3IPLUW?r`S7+V|bS>UVIe=vZ;UEjmE*qY*K&&bQ8 z-bDXCUiJKy#7zYwI3fzMRhjX>Y{+~ZpSFR$8V zB_fzl`%3Ym2!NVCLSHjGw?JDvh6~;om_F*$nmVk1wN2}-HoRwGaSyaUgbDgk4sP!}DvLFlP@dB^x&J^FdT z`O4KlfXl5K!XZ$F)$^MYa)QNNUDXQF#7^?L=H>QVhHPsgYI(~^^GHohjE$uC`y`A` z{7Hkr^Ko*jK~QT zAzYG!aRH02bSP?bSFAL`XG*iWs&~h$eMLbaDj;^_M!5~v!$EK1V%DL((|5iRdTF@J z$X4e8>27VqannpQmrZx`<~J7m5>w*Z3$+3_HyzylQTBWOZ*Zv?Z~_Y`DIZ3%3O?Di zlw7mWI2_R&uNe%E7`^$xjmQmGu2ooVEFRa0$LEG<30tq~B27En*uI*I$bN(BGVCPJ zFR;@Xwk0rIuK%X^N$5$tC7+YL@ezB`pI>DEu0Q%-B5W!dDOIDam_+7jo(Ws~U;xws zvK&OX|LH3;O{%XHK%K~dzt{tIKDk8FNoZ^7Jrs9TQRvw@Wc(VR3gqusPfU=UIt#G% zuy{US5%rB4RG00JPDrA$ z_|WaS`+cLiwT7}D56b8{lwut9ap}mJumU}jaXWZ-sI)I2v>#sv0%l0rRwb(n#IYhT51o5*A{7HM=!IND_qI%l(i*Fy)Gw&t2)0QY9#=eSBT)-iok7oD+D!^&93no2lovO|i9?AU}wis&c3I<5S)UNiz4Z>v?R z#ChLV)GK?>9;<#W9&Ui9W*WznbyP@vuD9wvGT)lup*gnz;xf>@SXtvE{rPdjzizt# zmq#q=XC`%6Ba8Md^z~@Y+jRyuMGfP!_tB8-A1Q>S#xI^^*J+FdIvQ+P*a)mC?lN5K zp2Wp-fzd9npt9}>f&EWT|Z$Cw4_po&jPWbNVYURP#57I@$owW}a9PvzC zb9<%7XMT4N9w(PQe@z?_KTvt&bI01m>5C4KW5tt_QCIfj);4^>VaGWLnz|Fo0DGH= zdzIG!UnZDY%?KMA@NJrU4Vsf)P9|^)n7wozFU(LDXC%d@&Rlx$nD}yUOV9Zjs3lAE ziwokc_q83jmRW{0FJRq-k$hv+CU+K?zubQe6tew6)1zkU@TKUpfseQ#hjm)5EDI6T z!|&BQKW&q~l7%#-d1jT7S$;`esHCyYSbo(!YgR6vU?rcV8-0inoi{mYpmEmdrRv`( z{lIh-1HY9>?yU`$d{-}p%MdL`k2v=aL`Zs#6`QEHzF4@r8XBitL6_ieC+1^gjRT)M zIJeOzo-%!;E(M|y7G#Vt*W>4=MI(Ci778`N#=_-NYnifrWU9#AiVdeCSp8Ik!E&3xc%W2R^L0>*YPv6z8fdQ=Ym;-;JYwG2dLbP)xl-k<9=W*F?&*&+7 z_e1$8ux&bvtKjR!&90KUEp=<@YkIi}o=Cg0wM5m1p>X;VhIkXG%0EEsCn}!b9n(T% zRZr$?Np*&kV7BXEgAx1rd~cFFp6RRO?^#p2!i?`wB5)_ybl-3w&39C4HOXFONWDG& z>t@VqKZYO|fPhHs3HB=sKeo`J3ww`L(DY7je;G^Iu%dB^we#MY+ik<332(kXHpX zE$?wr&&MfQ7=N>|8T4n0_i};tOBp+9G0`oKCs*uLeb4Nkn7D^e*}w)!46~!wBR~%$ zQzdg4Lf_ZVhe^?`NV)OF+1||$PiTn`q<60m$N%1c+i50X;RCvSl(^(13JG8>euQY=F?6QF0m&oPT=FIu;Ze!b`-$uIxfdxh06;ZYy>~rt0~Lw;f^h_Yk`y< zGW6pjV}vrdh8K;L8cRPgeyJs+`b>Vq13+<2u6iIRYo0jRyiU(u2h<|Urb?z^R!uvGwjh0z5LSR|1);>K{LLdleh~YgQ{1ehBC!uoq5+Xf zvdTKVpL2BZt#~lvpH&O-^Fle35*f^h`<$byI+aBj+1%@21zh`0ZK&vfw;1jt!@>WMFw-m__hCW23AA5R0rM^DsYyyV!jzyCf1^u`oec6D zc^kIfPxAV9=a05|Sc(a=Uo?faleKl#0P$JuvgreUAMRK3UUo$`YG!9j9P#+2`&f6h z2sEj)>!Tw_c!>?i>O(2jJNAVQ+5V-$(7*M`l`OK0Ycg==O~hJOW~Bu7SlP^l#=y5dzxLZ}xw{ zCY-V(V?Gq3X6pWg3+WouW3$Gu6Jb@8Jd<@Z*%t@IVbE=YwbZ;F*vv1uq3IrfpjhQ3z~1}de#&{ zqAhe?QN!^3kKvxg0p7G`Dy#r-u2J)|@&aI@VjaqF##xLX*M$E}-c@}hFCKQ`T8(+( z)``hC#nk|joK@#}_r)TsB&NyYZTNb4SWyDXuQF61QyLtkkGlD7?LFycO=v}<3@t%1 zGjg}6X{h0ECKYKQ?iv(f1@6AK;R4yHPA2|B`RjVKwcS4vD&o&$H-fOz2$mR=aT<35 z`K*_Fr=!C06W>AVj@zo%KlhrzLnWni(KBwZn$V)U@HfMLKY?G(<(9&QZQ8Y}s5B-# zi%Hu0tbXs{9cpxHFx#f5TZ)kGz6nZx8U_zSgh=TE@h6OQfZ7f`Uej%$Ut9h($;E4- z_5J#z);#jb4ZHUQ5@!x+(^Bej^Wq~I&fv8MwssULe_pq?)8Ygk=ytsndU5O57UuYk z#%WrDnU7X3h-4#Sf8|E|Ik{;sRHMDVE?1unEFNx8a#>n7-1jx|!by%zkxH(Rj;pSO za*ovb#GcT5rAj3Mnr2timi;a&cyf}OSM35Ns51aH`On5Q<&m7%3#wMiOUCR8t_igo zc(j4}=NA!+%ErzpIzW@=nYjs_mhm53{xNc#`1$K1lDtxWL7t1BT0ERL-}-xfdP#f6 zxm9PI&@r^aZl{dX;-yFc5hanxkRWz_`2}l_XxwAxY$pHb>PJfD-gs<(MucYUnkgzucaL%}NYDUI&wN*h1rzF^jfVa+K{~P*INz`gyisR*-sM z1byhF$#BDMo$?x8;%A^2-)j{XnjF|)%bPh^qpOGA4lbUAxQ3q3kAp<6H_~-;7H66( z-dcI=X#ad9j!Q{@#o)UcK6hU?4I`Ul4^=tMNLOfa6>zvXX_`-^U6K;$X|Va;oqKryeTaFbI`R-+wUYh2StiM)J#rPs&e!Zhm_>S zz&nh-ji0WCf;iB@O-kswZbeP#-zj5Vz} zm`={Z0GnBAkYC%Tz+N(P>4TJL6P2=V9AfM32N1F8Q}r#}S|@XJT-vyaW%}NOVgr#n zNr!|DNK@5M*vqLN@>4!b48X|V?@14$D2mB_JQEuy1yn0 zE)~jBqemmJpq-Th6Dk{iM29`b(O)179)y0?y8+WojFr2HP^`A*KWnZIQ2xm`0@cc!AiJsvk6rKlQ#;jJ2r1 zPlMcn1F_lEL-;sPGfr?qurNjM0uJp64RBa}nTK@PX!_ZPU8L?0D(zAnGor$6bR2)y zLu_2b0ZDi>kEvsiI@7wU=xqL~6-py~S=BHhB>N$`T_??7QNaBO`yfd>ZTzOYxUTRt zYoe7u$ArmFIWdmoJaL;>&ESNa+>-CuTHJ6WAaM|+K(Onddq(TO<8^;DmHKL}oRXbS z!rIFpanYX9d3=>kUv)S+e(Y8HT0(-On^pG|$U1XRip`ReR!FMnAoy?$tGJs? zU$O8<$klw>B+Up8@twUma%*{Rb_uaN4Z8^HRuRb(oeMbK2^anq7XL@^Qsy6EqO`(5 z<-LK*(yPxXcj?>*cklw`7p2GaHW+l>Y}JAb`t{%=oRwY>X+m%d52_-kV!{i2uP``r{Zy<00{{%o>3&20)nRzrhyp~(w zVQ5bZ+E01X3dnVV@zcpht^i>}nqgw2pzyyPhb)vi2$V!Ez_SOPS!Jr&bjUrt&KP}< z6HV_z1}ptB#OEiA|2*wizTCaE%IPpLL-`FniV?tp;vyylXx_h+lfg zP_--FwDMCEhimTVC!M6c#(PP@Ph)qBcSki$&A=6gPU(4wpC}Ag8-PZ|!Qakdg%!S4 z)>Ep7DaOTbf-%#ddVde!VE!#J?fM)v{p9_a#|3NV_Z(l0UpVI|0@fdmEkTAattfsu zR7SDX2}D^x2{bX~T}%;#1t}L2l#*qKcmGNt{0I0^Fgg~2c8_Me&5$G}8R8?pbyNKO z1&N)TBfJY=Ifi7)1~S~I0+X!;l>3LzAAKS4@RPyQ?BG76-(AQxu*6WXHMHrsC5Ozn z$SPI%%1)>(w1FZ5M@y6NLFV~YjVeGB;E{y&#TPmA{Re1HcshP+oONG7L70%E?DPSV zYqkIU8SrUk1|{fm<^vtKL8VEoZU0u`%M^3~37S*`)@Q|d6qzx!1j!{j3t>h*gRbiK zCORG~d#lBH2G@P0@yv3;L*51))$7Hnc2*y*LkBjt5{eGrynM%U6oP%;CHO4&7b z)CItD8YsnOFZJ>IGRJvBYi)z)aX#VFN-9*6g`qsy#)Fq)q&$52IX1G`>G|d@GNq^e z4-im*G>!cS*bUEbXGduEZA!0))kCID`lPK4)+?@wi?NQcQq)w^ z=cH9XlO>yLnE-nuZIK8q*V!81 zCSPFXe3AB-%@?vpkxD;p5!bD!eC_*VnuYMc<9?g4HnetK!t)|OP33ND(dWD#zvE@u zCrSJ0bRA7R#%AMJk2C%I(bwT+AeE=a39T3DJYmw}jTocCZ8ZX?hpxCXi?2l)o{k=o zjXobq9Q=#aWib!&1y;??FUx3=Pqy2--ArUOFRY&9i|J4m06a~eXrF`J|E>@}><9Q5 zVtA3p=nPaqzkL3RwIINQHNaYsy7beT)2F<1=Q5Ogj+0JY_hQ~~EpwXguZEt^cw`g~ zR^d+gN;u*U`OEvPg=M4$s+#Sm=C_z%=ImZRKjAMLziEnj4^|+;L#2(7ll&}0d$px~ z8|L|#Nh|f@c?qe@Yv;u_$R0(P75 z>1io?NSB`7sl0xtc6$OW5*)+ef~@KzI8NhdPqBUBEOHV0BURztq2S?ovp~GL2Z7u3 zivm;ji4#xfO0aZ)mihYBKQ1xOph zPUW5iFYgXrw}pN-;LAI&xqC>q|8GDFD)Qta$PQw!nUOHz%H zudhwMrEr*hQ!6w&R{)D!Hjv4B4TM}{)nQL-I|5}&>gmN<)^R9jW|{ZWsD-TyA|J0w zFN#xtr2h4pR(X+*p;2eV&o6~BinNr%+Ag-b??Q?<|0!{bT~Onw;wWCvlA(O`ZNgk` zv4U*}6-B)GEDN|VCdZO2-ueefM79rt>MZvd0xjf~+cDVG`}EKASEROg^~tK}@=Vf9 z^DsIRdsdC?-tLc@+~4n!#D0b!4*c|DXVktcToQ&Mn;_QE<0${{XO&vi?U^nVTR;Hd?Bv_ojv8 zcNS}G17qnR7KR!k;=zj{9#6;0M(Fko((#!AsxDWGSLY(x|CeFD5Je8RnJzeKvd9w$ zZ7D*90WtvBl>Mu&)TC6?PJv9df{az=T+$eB;rW1T=^tQkPxRIE=r%Iv3~p|T z^v7a(ep0Au0JZUiE+YJ3t^)CJt!>l;T!2neJQ)zm*l3jld+s={$$Uqqo~%|%0ffPd z=cl4O-Nim46)wwtl!)Q+d}27IsK}uN?C1@pdu6E$VpLWUTqM$Qgwl)Kz7jdr4b2G| zJA1t9MNS*m-`?=7Rb98mo%S^979|$bJ&mFY66>GUT4wu*oJnbglS7KWnzf+3bu@ zBO(U35WW>zt3W>bGOC>7_~Y8=!eU0vGm~4-w|M^mK3Zn~0A56;z+6QA)@t4rA={xj{%`If%r-W!F7k*(vc@}LMiZo;mPyC8i;&6+J; z&f~1N{WIVn;M(gSz~ZerTdgko4^=zFetraDsic?hIU*?3&H@!K%rt09om5MQD$Nmw z1v{TH#o%9iK2JxshbJ{&wpMdXF$v%Bw@d9ER%XhW9gREQ%6&@D;=EL<;MVG!i+UlM z1t_d?#=pYi(u!ZU+eF+hL8!@QrVk7MOorjnrx&BN9bp-KiuatyZ}wViNKJxL!q=aJ z5a4{n>>`tjxR-f#P(FO?^ayu2z>?B_p(PA)f*us!J0ro=C>5^8vKp6Jba)<%-*{p+N2PHr5of`cE8-UUUlprgF! z`VhL9c0hUjZ$(EP4V@GK0AK?+-eqf<(Y^`8L0-`!4`Sq}hMc^ThSlrWfl){&QB<1pe<5oIM>3^fCUsg#Qu!e+K=(tNPzTku?DzJ|!TF`F~XW X{}&bm^FOsfMZRm0=Pl&T0Kk6%2M?yo literal 0 HcmV?d00001 diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024307.zip b/substrabac/fixtures/chunantes/datasamples/train/0024307.zip new file mode 100644 index 0000000000000000000000000000000000000000..e4c7b3a09f75a2323c9ad454ca8ec98d696cfbae GIT binary patch literal 274698 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℘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%0DQhDMlst`Re$Bd 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 Jb0Wdp{{lAyt(E`) literal 0 HcmV?d00001 diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index 10322c737..5f351c082 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -11,6 +11,7 @@ class LedgerTrainTupleSerializer(serializers.Serializer): data_manager_key = serializers.CharField(min_length=64, max_length=64) objective_key = serializers.CharField(min_length=64, max_length=64) rank = serializers.IntegerField(allow_null=True, required=False) + rank = serializers.IntegerField(allow_null=True, required=False, default=0) FLtask_key = serializers.CharField(min_length=64, max_length=64, allow_blank=True, required=False) in_models_keys = serializers.ListField(child=serializers.CharField(min_length=64, max_length=64), min_length=0, @@ -48,7 +49,7 @@ def get_args(self, validated_data): data_manager_key, ','.join([x for x in train_data_sample_keys]), FLtask_key, - rank, + str(rank), tag, ] diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 577d0c47f..2e9690316 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -68,45 +68,34 @@ def queryLedger(fcn, args=None): }) client._peers[peer['name']] = target_peer - response = client.chaincode_query( - requestor=requestor, - channel_name=channel_name, - peer_names=[peer['name']], - args=args, - cc_name=chaincode_name, - cc_version=chaincode_version, - fcn=fcn) - - st = status.HTTP_200_OK - - data = response - - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - try: - # json transformation if needed - data = json.loads(response) - except: - logging.error('Failed to json parse response in query') - + response = client.chaincode_query( + requestor=requestor, + channel_name=channel_name, + peer_names=[peer['name']], + args=args, + cc_name=chaincode_name, + cc_version=chaincode_version, + fcn=fcn) + except Exception as e: + st = status.HTTP_400_BAD_REQUEST + data = {'message': str(e)} + else: msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' print(msg, flush=True) + st = status.HTTP_200_OK + + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py try: - msg = response.split('Error')[-1].split('\n')[0] - data = {'message': msg} + data = json.loads(response) except: - msg = response - data = {'message': msg} - finally: - st = status.HTTP_400_BAD_REQUEST - if 'access denied' in msg: - st = status.HTTP_403_FORBIDDEN - elif 'no element with key' in msg: - st = status.HTTP_404_NOT_FOUND + logging.error('Failed to json parse response in query') + data = response - return data, st + finally: + return data, st def invokeLedger(fcn, args=None, sync=False): @@ -152,42 +141,34 @@ def invokeLedger(fcn, args=None, sync=False): }) client._orderers[orderer['name']] = target_orderer - response = client.chaincode_invoke( - requestor=requestor, - channel_name=channel_name, - peer_names=[peer['name']], - args=args, - cc_name=chaincode_name, - cc_version=chaincode_version, - fcn=fcn, - wait_for_event=sync, - wait_for_event_timeout=45) - - st = status.HTTP_201_CREATED - - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - msg = response - data = {'message': msg} - - if 'Error' in msg or 'ERRO' in msg: - # https://github.com/hyperledger/fabric/blob/eca1b14b7e3453a5d32296af79cc7bad10c7673b/peer/chaincode/common.go - if "timed out waiting for txid on all peers" in msg or "failed to receive txid on all peers" in msg: - st = status.HTTP_408_REQUEST_TIMEOUT - else: - st = status.HTTP_400_BAD_REQUEST - elif 'access denied' in msg or 'authentication handshake failed' in msg: - st = status.HTTP_403_FORBIDDEN - elif 'Chaincode invoke successful' in msg: + try: + response = client.chaincode_invoke( + requestor=requestor, + channel_name=channel_name, + peer_names=[peer['name']], + args=args, + cc_name=chaincode_name, + cc_version=chaincode_version, + fcn=fcn, + wait_for_event=sync, + wait_for_event_timeout=45) + except TimeoutError as e: + st = status.HTTP_408_REQUEST_TIMEOUT + data = {'message': str(e)} + except Exception as e: + st = status.HTTP_400_BAD_REQUEST + data = {'message': str(e)} + else: + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py + # elif 'access denied' in msg or 'authentication handshake failed' in msg: + # st = status.HTTP_403_FORBIDDEN + st = status.HTTP_201_CREATED - try: - msg = msg.split('result: status:')[1].split('\n')[0].split('payload:')[1].strip().strip('"') - except: - pass - finally: - data = {'pkhash': msg} + data = {'pkhash': response} - return data, st + finally: + return data, st def get_dir_hash(archive_content): From bcf000c9761b12f83f9eacfd916532e1f638004e Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 17 Apr 2019 11:57:48 +0200 Subject: [PATCH 008/457] Fix bugs. --- substrabac/substrapp/views/testtuple.py | 3 ++- substrabac/substrapp/views/traintuple.py | 3 ++- substrabac/substrapp/views/utils.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 69acd6a17..93101f2f4 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -63,7 +63,8 @@ def create(self, request, *args, **kwargs): # Get testtuple pkhash of the proposal with a queryLedger in case of 408 timeout args = serializer.get_args(serializer.validated_data) - data, st = queryLedger({'args': '{"Args":["createTesttuple", ' + args + ']}'}) + data, st = queryLedger(fcn='createTesttuple', args=args) + print(data) if st == status.HTTP_200_OK: pkhash = data.get('key', data.get('keys')) else: diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 69ed77efb..258631411 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -75,7 +75,8 @@ def create(self, request, *args, **kwargs): # Get traintuple pkhash of the proposal with a queryLedger in case of 408 timeout args = serializer.get_args(serializer.validated_data) - data, st = queryLedger({'args': '{"Args":["createTraintuple", ' + args + ']}'}) + data, st = queryLedger(fcn='createTraintuple', args=args) + print(data) if st == status.HTTP_200_OK: pkhash = data.get('key', data.get('keys')) else: diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 62ff2876d..577f1867c 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -56,7 +56,7 @@ def get_filters(query_params): def getObjectFromLedger(pk, query): # get instance from remote node - data, st = queryLedger(fcn='query', args=[f'{pk}']) + data, st = queryLedger(fcn=query, args=[f'{pk}']) if st == status.HTTP_404_NOT_FOUND: raise Http404('Not found') From 937caf36aac9ff5208222a05c891fad36c64f84c Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 24 Apr 2019 14:28:03 +0200 Subject: [PATCH 009/457] Update query/invoke. --- substrabac/substrapp/utils.py | 15 +++++++++----- substrabac/substrapp/views/testtuple.py | 26 ++++++++---------------- substrabac/substrapp/views/traintuple.py | 26 ++++++++---------------- 3 files changed, 28 insertions(+), 39 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 2e9690316..ff6dd49e5 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -90,9 +90,9 @@ def queryLedger(fcn, args=None): # May have changed by using fabric-sdk-py try: data = json.loads(response) - except: - logging.error('Failed to json parse response in query') - data = response + except json.decoder.JSONDecodeError: + st = status.HTTP_400_BAD_REQUEST + data = {'message': response} finally: return data, st @@ -165,8 +165,13 @@ def invokeLedger(fcn, args=None, sync=False): # st = status.HTTP_403_FORBIDDEN st = status.HTTP_201_CREATED - data = {'pkhash': response} - + try: + response = json.loads(response) + pkhash = response.get('key', response.get('keys')) + data = {'pkhash': pkhash} + except json.decoder.JSONDecodeError: + st = status.HTTP_400_BAD_REQUEST + data = {'message': response} finally: return data, st diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 93101f2f4..61478cebb 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -64,25 +64,21 @@ def create(self, request, *args, **kwargs): # Get testtuple pkhash of the proposal with a queryLedger in case of 408 timeout args = serializer.get_args(serializer.validated_data) data, st = queryLedger(fcn='createTesttuple', args=args) - print(data) + if st == status.HTTP_200_OK: pkhash = data.get('key', data.get('keys')) else: # If queryLedger fails, invoke will fail too so we handle the issue right now - try: - data['message'] = data['message'].split('Error')[-1] - msg = json.loads(data['message'].split('payload:')[-1].strip().strip('"').encode('utf-8').decode('unicode_escape')) - pkhash = msg['error'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() if len(pkhash) != 64: raise Exception('bad pkhash') else: st = status.HTTP_409_CONFLICT - return Response({'message': data['message'].split('payload')[0], - 'pkhash': pkhash}, status=st) - except: - return Response(data, status=st) + return Response({'message': data['message'], + 'pkhash': pkhash}, status=st) # create on ledger data, st = serializer.create(serializer.validated_data) @@ -92,20 +88,16 @@ def create(self, request, *args, **kwargs): 'pkhash': pkhash}, status=st) if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED): - try: - data['message'] = data['message'].split('Error')[-1] - msg = json.loads(data['message'].split('payload:')[-1].strip().strip('"').encode('utf-8').decode('unicode_escape')) - pkhash = msg['error'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() if len(pkhash) != 64: raise Exception('bad pkhash') else: st = status.HTTP_409_CONFLICT - return Response({'message': data['message'].split('payload')[0], - 'pkhash': pkhash}, status=st) - except: - return Response(data, status=st) + return Response({'message': data['message'], + 'pkhash': pkhash}, status=st) headers = self.get_success_headers(serializer.data) return Response(data, status=st, headers=headers) diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 258631411..173559328 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -76,25 +76,21 @@ def create(self, request, *args, **kwargs): # Get traintuple pkhash of the proposal with a queryLedger in case of 408 timeout args = serializer.get_args(serializer.validated_data) data, st = queryLedger(fcn='createTraintuple', args=args) - print(data) + if st == status.HTTP_200_OK: pkhash = data.get('key', data.get('keys')) else: # If queryLedger fails, invoke will fail too so we handle the issue right now - try: - data['message'] = data['message'].split('Error')[-1] - msg = json.loads(data['message'].split('payload:')[-1].strip().strip('"').encode('utf-8').decode('unicode_escape')) - pkhash = msg['error'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() if len(pkhash) != 64: raise Exception('bad pkhash') else: st = status.HTTP_409_CONFLICT - return Response({'message': data['message'].split('payload')[0], - 'pkhash': pkhash}, status=st) - except: - return Response(data, status=st) + return Response({'message': data['message'], + 'pkhash': pkhash}, status=st) # create on ledger data, st = serializer.create(serializer.validated_data) @@ -104,20 +100,16 @@ def create(self, request, *args, **kwargs): 'pkhash': pkhash}, status=st) if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED): - try: - data['message'] = data['message'].split('Error')[-1] - msg = json.loads(data['message'].split('payload:')[-1].strip().strip('"').encode('utf-8').decode('unicode_escape')) - pkhash = msg['error'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() if len(pkhash) != 64: raise Exception('bad pkhash') else: st = status.HTTP_409_CONFLICT - return Response({'message': data['message'].split('payload')[0], - 'pkhash': pkhash}, status=st) - except: - return Response(data, status=st) + return Response({'message': data['message'], + 'pkhash': pkhash}, status=st) headers = self.get_success_headers(serializer.data) return Response(data, status=st, headers=headers) From 30953f0c829075b773696ab3c3c516a9999ba171 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 25 Apr 2019 14:40:54 +0200 Subject: [PATCH 010/457] Use async fabric-sdk-client. --- substrabac/requirements.txt | 3 +- substrabac/substrapp/utils.py | 270 ++++++++++++----------- substrabac/substrapp/views/testtuple.py | 2 - substrabac/substrapp/views/traintuple.py | 2 - 4 files changed, 149 insertions(+), 128 deletions(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index 98e6ebb4e..938b3016a 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -25,5 +25,6 @@ requests == 2.20.0 rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 +<<<<<<< HEAD uwsgi == 2.0.18 -git+https://github.com/hyperledger/fabric-sdk-py.git@865252e51079a4579fd2ea18b822c9796f480399 +git+https://github.com/hyperledger/fabric-sdk-py.git@9db0f1d1df1fe76cf1247e2f42e62a3143d52902 diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index ff6dd49e5..6082a4c95 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -1,4 +1,6 @@ +import contextlib import io +import asyncio import hashlib import json import glob @@ -30,150 +32,172 @@ def clean_env_variables(): os.environ.pop('CORE_PEER_MSPCONFIGPATH', None) os.environ.pop('CORE_PEER_ADDRESS', None) + ####### # /!\ # ####### -# careful, passing invoke parameters to queryLedger will NOT fail +@contextlib.contextmanager +def get_event_loop(): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + try: + yield loop + finally: + loop.close() +# careful, passing invoke parameters to queryLedger will NOT fail def queryLedger(fcn, args=None): - if args is None: - args = [] - - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - chaincode_version = LEDGER['chaincode_version'] - peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] - requestor_config = LEDGER['client'] - - client = Client() - client.new_channel(channel_name) - - requestor = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - - target_peer = Peer(name=peer['name']) - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) - client._peers[peer['name']] = target_peer + with get_event_loop() as loop: - try: - response = client.chaincode_query( - requestor=requestor, - channel_name=channel_name, - peer_names=[peer['name']], - args=args, - cc_name=chaincode_name, - cc_version=chaincode_version, - fcn=fcn) - except Exception as e: - st = status.HTTP_400_BAD_REQUEST - data = {'message': str(e)} - else: - msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' - print(msg, flush=True) + if args is None: + args = [] + + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + chaincode_version = LEDGER['chaincode_version'] + peer = LEDGER['peer'] + peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + + requestor_config = LEDGER['client'] + + client = Client() + client.new_channel(channel_name) + + requestor = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + target_peer = Peer(name=peer['name']) - st = status.HTTP_200_OK + # Need loop + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + + client._peers[peer['name']] = target_peer - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py try: - data = json.loads(response) - except json.decoder.JSONDecodeError: + # Async - need loop + response = loop.run_until_complete( + client.chaincode_query( + requestor=requestor, + channel_name=channel_name, + peers=[peer['name']], + args=args, + cc_name=chaincode_name, + cc_version=chaincode_version, + fcn=fcn)) + except Exception as e: st = status.HTTP_400_BAD_REQUEST - data = {'message': response} + data = {'message': str(e)} + else: + msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' + print(msg, flush=True) - finally: - return data, st + st = status.HTTP_200_OK + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py + try: + # json transformation if needed + data = json.loads(response) + except json.decoder.JSONDecodeError: + st = status.HTTP_400_BAD_REQUEST + data = {'message': response} -def invokeLedger(fcn, args=None, sync=False): + return data, st - if args is None: - args = [] - - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - chaincode_version = LEDGER['chaincode_version'] - peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] - - orderer = LEDGER['orderer'] - - requestor_config = LEDGER['client'] - - client = Client() - client.new_channel(channel_name) - - requestor = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - - target_peer = Peer(name=peer['name']) - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) - client._peers[peer['name']] = target_peer - - target_orderer = Orderer(name=orderer['name']) - target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', - 'grpcOptions': orderer['grpcOptions'], - 'tlsCACerts': {'path': orderer['ca']}, - 'clientKey': {'path': orderer['clientKey']}, - 'clientCert': {'path': orderer['clientCert']}, - }) - client._orderers[orderer['name']] = target_orderer - try: - response = client.chaincode_invoke( - requestor=requestor, - channel_name=channel_name, - peer_names=[peer['name']], - args=args, - cc_name=chaincode_name, - cc_version=chaincode_version, - fcn=fcn, - wait_for_event=sync, - wait_for_event_timeout=45) - except TimeoutError as e: - st = status.HTTP_408_REQUEST_TIMEOUT - data = {'message': str(e)} - except Exception as e: - st = status.HTTP_400_BAD_REQUEST - data = {'message': str(e)} - else: - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - # elif 'access denied' in msg or 'authentication handshake failed' in msg: - # st = status.HTTP_403_FORBIDDEN +def invokeLedger(fcn, args=None, sync=False): + + with get_event_loop() as loop: + if args is None: + args = [] + + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + chaincode_version = LEDGER['chaincode_version'] + peer = LEDGER['peer'] + peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + orderer = LEDGER['orderer'] + + requestor_config = LEDGER['client'] + + client = Client() + client.new_channel(channel_name) + + requestor = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + target_peer = Peer(name=peer['name']) + + # Need loop + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + client._peers[peer['name']] = target_peer + + target_orderer = Orderer(name=orderer['name']) + + # Need loop + target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', + 'grpcOptions': orderer['grpcOptions'], + 'tlsCACerts': {'path': orderer['ca']}, + 'clientKey': {'path': orderer['clientKey']}, + 'clientCert': {'path': orderer['clientCert']}, + }) + client._orderers[orderer['name']] = target_orderer - st = status.HTTP_201_CREATED try: - response = json.loads(response) - pkhash = response.get('key', response.get('keys')) - data = {'pkhash': pkhash} - except json.decoder.JSONDecodeError: + # Async - need loop + response = loop.run_until_complete(client.chaincode_invoke( + requestor=requestor, + channel_name=channel_name, + peers=[peer['name']], + args=args, + cc_name=chaincode_name, + cc_version=chaincode_version, + fcn=fcn, + wait_for_event=sync, + wait_for_event_timeout=45)) + except TimeoutError as e: + st = status.HTTP_408_REQUEST_TIMEOUT + data = {'message': str(e)} + except Exception as e: st = status.HTTP_400_BAD_REQUEST - data = {'message': response} - finally: - return data, st + data = {'message': str(e)} + else: + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py + # elif 'access denied' in msg or 'authentication handshake failed' in msg: + # st = status.HTTP_403_FORBIDDEN + + st = status.HTTP_201_CREATED + try: + response = json.loads(response) + pkhash = response.get('key', response.get('keys')) + data = {'pkhash': pkhash} + except json.decoder.JSONDecodeError: + st = status.HTTP_400_BAD_REQUEST + data = {'message': response} + + return data, st def get_dir_hash(archive_content): diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 61478cebb..d7214b35a 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -1,5 +1,3 @@ -import json - from django.http import Http404 from rest_framework import mixins, status from rest_framework.response import Response diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 173559328..5fd650650 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -1,5 +1,3 @@ -import json - from django.http import Http404 from rest_framework import mixins, status from rest_framework.response import Response From 375bf88f9693db63c61006bc2820363c33ca1cce Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 25 Apr 2019 16:41:22 +0200 Subject: [PATCH 011/457] Remove orderer dependencies. --- substrabac/substrapp/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 6082a4c95..0d049cef1 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -159,8 +159,8 @@ def invokeLedger(fcn, args=None, sync=False): target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', 'grpcOptions': orderer['grpcOptions'], 'tlsCACerts': {'path': orderer['ca']}, - 'clientKey': {'path': orderer['clientKey']}, - 'clientCert': {'path': orderer['clientCert']}, + 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) }) client._orderers[orderer['name']] = target_orderer From 401a06588fbe5df204f14716786f57577c06c1ae Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 26 Apr 2019 12:04:06 +0200 Subject: [PATCH 012/457] Get chaincode version from ledger --- substrabac/substrapp/utils.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 0d049cef1..862ebd671 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -57,7 +57,6 @@ def queryLedger(fcn, args=None): channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] - chaincode_version = LEDGER['chaincode_version'] peer = LEDGER['peer'] peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] @@ -85,6 +84,19 @@ def queryLedger(fcn, args=None): client._peers[peer['name']] = target_peer + # Get chaincode version + response = loop.run_until_complete( + client.query_instantiated_chaincodes( + requestor=requestor, + channel_name=channel_name, + peers=[peer['name']], + decode=True + )) + for ccs in response: + for cc in ccs.chaincodes: + if cc.name == chaincode_name: + chaincode_version = cc.version + try: # Async - need loop response = loop.run_until_complete( @@ -125,7 +137,6 @@ def invokeLedger(fcn, args=None, sync=False): channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] - chaincode_version = LEDGER['chaincode_version'] peer = LEDGER['peer'] peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] orderer = LEDGER['orderer'] @@ -164,6 +175,19 @@ def invokeLedger(fcn, args=None, sync=False): }) client._orderers[orderer['name']] = target_orderer + # Get chaincode version + response = loop.run_until_complete( + client.query_instantiated_chaincodes( + requestor=requestor, + channel_name=channel_name, + peers=[peer['name']], + decode=True + )) + for ccs in response: + for cc in ccs.chaincodes: + if cc.name == chaincode_name: + chaincode_version = cc.version + try: # Async - need loop response = loop.run_until_complete(client.chaincode_invoke( From 5c98d6cd043fb5fdff19271dfd5bc10a66d084ca Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 3 May 2019 08:45:59 +0200 Subject: [PATCH 013/457] Fix issue in requirements --- substrabac/requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index 938b3016a..0dc40c514 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -25,6 +25,5 @@ requests == 2.20.0 rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 -<<<<<<< HEAD uwsgi == 2.0.18 git+https://github.com/hyperledger/fabric-sdk-py.git@9db0f1d1df1fe76cf1247e2f42e62a3143d52902 From 031d024cbc345bb374f3bacfe36e41cf51c79b70 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 9 May 2019 15:11:47 +0200 Subject: [PATCH 014/457] Fix --- substrabac/requirements.txt | 2 +- substrabac/substrapp/utils.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index 0dc40c514..c37a0586f 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,4 +26,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -git+https://github.com/hyperledger/fabric-sdk-py.git@9db0f1d1df1fe76cf1247e2f42e62a3143d52902 +git+https://github.com/hyperledger/fabric-sdk-py.git@943b1a5b1ee00781f596a9e8a5e8836f09effd46 diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 862ebd671..33c6eb14a 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -124,6 +124,12 @@ def queryLedger(fcn, args=None): data = json.loads(response) except json.decoder.JSONDecodeError: st = status.HTTP_400_BAD_REQUEST + + if 'access denied' in response: + st = status.HTTP_403_FORBIDDEN + elif 'no element with key' in response: + st = status.HTTP_404_NOT_FOUND + data = {'message': response} return data, st From 38cc0a4e7856c21e26f55039b8464557cc3b7829 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 3 May 2019 15:58:23 +0200 Subject: [PATCH 015/457] save progress --- substrabac/events/__init__.py | 1 + substrabac/events/apps.py | 64 +++++++++++++++++++ substrabac/populate.py | 2 + substrabac/substrabac/celery.py | 10 +-- substrabac/substrabac/settings/common.py | 1 + .../serializers/ledger/traintuple/util.py | 2 +- substrabac/substrapp/utils.py | 27 ++++---- 7 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 substrabac/events/__init__.py create mode 100644 substrabac/events/apps.py diff --git a/substrabac/events/__init__.py b/substrabac/events/__init__.py new file mode 100644 index 000000000..9cb9c2d5a --- /dev/null +++ b/substrabac/events/__init__.py @@ -0,0 +1 @@ +default_app_config = 'events.apps.EventsConfig' diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py new file mode 100644 index 000000000..02367abf3 --- /dev/null +++ b/substrabac/events/apps.py @@ -0,0 +1,64 @@ +import asyncio + +from django.apps import AppConfig + +from django.conf import settings + +import glob + +from hfc.fabric import Client +from hfc.fabric.peer import Peer +from hfc.fabric.user import create_user +from hfc.util.keyvaluestore import FileKeyValueStore + +from substrapp.utils import get_event_loop + +LEDGER = getattr(settings, 'LEDGER', None) + + +async def main(stream): + await stream + +class EventsConfig(AppConfig): + name = 'events' + + def onEvent(self, block): + print(block) + + def ready(self): + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] + + client = Client() + + channel = client.new_channel(channel_name) + + target_peer = Peer(name=peer['name']) + requestor_config = LEDGER['client'] + + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer["docker_port"]}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + + requestor = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + + channel_event_hub = channel.newChannelEventHub(target_peer, + requestor) + + # use chaincode event + stream = channel_event_hub.connect() + cr = channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=self.onEvent) + + asyncio.run(main(stream)) + + diff --git a/substrabac/populate.py b/substrabac/populate.py index 20cb01706..6e5bffe70 100644 --- a/substrabac/populate.py +++ b/substrabac/populate.py @@ -298,6 +298,8 @@ def do_populate(): testtuple_key = get_or_create(data, org_1, 'testtuple') + + client.set_config(org_1) res_t = client.get('testtuple', testtuple_key) print(colored(json.dumps(res_t, indent=2), 'yellow')) diff --git a/substrabac/substrabac/celery.py b/substrabac/substrabac/celery.py index faf074883..c3443c0ed 100644 --- a/substrabac/substrabac/celery.py +++ b/substrabac/substrabac/celery.py @@ -27,8 +27,8 @@ def debug_task(self): def setup_periodic_tasks(sender, **kwargs): from substrapp.tasks import prepareTrainingTask, prepareTestingTask - period = 10 - sender.add_periodic_task(period, prepareTrainingTask.s(), queue='scheduler', - name='query Traintuples to prepare train task on todo traintuples') - sender.add_periodic_task(period, prepareTestingTask.s(), queue='scheduler', - name='query Testuples to prepare test task on todo testuples') + #period = 10 + #sender.add_periodic_task(period, prepareTrainingTask.s(), queue='scheduler', + # name='query Traintuples to prepare train task on todo traintuples') + #sender.add_periodic_task(period, prepareTestingTask.s(), queue='scheduler', + # name='query Testuples to prepare test task on todo testuples') diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 6598755b5..519a5de45 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -58,6 +58,7 @@ 'rest_framework_swagger', 'rest_framework', 'substrapp', + 'events', ] MIDDLEWARE = [ diff --git a/substrabac/substrapp/serializers/ledger/traintuple/util.py b/substrabac/substrapp/serializers/ledger/traintuple/util.py index be771ee07..fa9e610f8 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/util.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/util.py @@ -5,4 +5,4 @@ def createLedgerTraintuple(args, sync=False): - return invokeLedger(fcn='createTraintuple', args=args, sync=sync) + return invokeLedger(fcn='createTraintuple', args=args, cc_pattern='traintuple-creation', sync=sync) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 33c6eb14a..80e2f8383 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -135,7 +135,7 @@ def queryLedger(fcn, args=None): return data, st -def invokeLedger(fcn, args=None, sync=False): +def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): with get_event_loop() as loop: if args is None: @@ -196,16 +196,21 @@ def invokeLedger(fcn, args=None, sync=False): try: # Async - need loop - response = loop.run_until_complete(client.chaincode_invoke( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - args=args, - cc_name=chaincode_name, - cc_version=chaincode_version, - fcn=fcn, - wait_for_event=sync, - wait_for_event_timeout=45)) + kwargs = { + 'requestor': requestor, + 'channel_name': channel_name, + 'peers': [peer['name']], + 'args': args, + 'cc_name': chaincode_name, + 'cc_version': chaincode_version, + 'fcn': fcn, + 'wait_for_event': sync, + 'wait_for_event_timeout': 45 + } + if cc_pattern: + kwargs['cc_pattern'] = cc_pattern + + response = loop.run_until_complete(client.chaincode_invoke(**kwargs)) except TimeoutError as e: st = status.HTTP_408_REQUEST_TIMEOUT data = {'message': str(e)} From 6350fa344d87fdb5850485931cfb9e9cfd77a388 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 9 May 2019 15:13:31 +0200 Subject: [PATCH 016/457] use alone script --- substrabac/events/apps.py | 1 + substrabac/events/events.py | 61 ++++++++++++++++++++++++ substrabac/substrabac/settings/common.py | 2 +- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 substrabac/events/events.py diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 02367abf3..c465afa45 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -19,6 +19,7 @@ async def main(stream): await stream + class EventsConfig(AppConfig): name = 'events' diff --git a/substrabac/events/events.py b/substrabac/events/events.py new file mode 100644 index 000000000..b533a427c --- /dev/null +++ b/substrabac/events/events.py @@ -0,0 +1,61 @@ +import asyncio +import contextlib + +from django.conf import settings + +import glob + +from hfc.fabric import Client +from hfc.fabric.peer import Peer +from hfc.fabric.user import create_user +from hfc.util.keyvaluestore import FileKeyValueStore + +LEDGER = getattr(settings, 'LEDGER', None) + +@contextlib.contextmanager +def get_event_loop(): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + try: + yield loop + finally: + loop.close() + + +def onEvent(self, block): + print(block) + +with get_event_loop() as loop: + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] + + client = Client() + + channel = client.new_channel(channel_name) + + target_peer = Peer(name=peer['name']) + requestor_config = LEDGER['client'] + + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer["docker_port"]}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + + requestor = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + channel_event_hub = channel.newChannelEventHub(target_peer, + requestor) + + # use chaincode event + stream = channel_event_hub.connect() + cr = channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=onEvent) + loop.run_until_complete(stream) + diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 519a5de45..f8553395b 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -58,7 +58,7 @@ 'rest_framework_swagger', 'rest_framework', 'substrapp', - 'events', + #'events', ] MIDDLEWARE = [ From 9ca1e18b8e878c6bd30772433856eecf71624e96 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 9 May 2019 18:44:59 +0200 Subject: [PATCH 017/457] working poc --- substrabac/events/apps.py | 89 +++++++++++++----------- substrabac/events/events.py | 61 ---------------- substrabac/substrabac/settings/common.py | 2 +- substrabac/substrapp/tasks.py | 34 +++++++++ 4 files changed, 85 insertions(+), 101 deletions(-) delete mode 100644 substrabac/events/events.py diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index c465afa45..b5bcf44b8 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -1,4 +1,6 @@ import asyncio +import contextlib +import json from django.apps import AppConfig @@ -11,55 +13,64 @@ from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore -from substrapp.utils import get_event_loop +from substrapp.tasks import prepareTrainTuple LEDGER = getattr(settings, 'LEDGER', None) - -async def main(stream): - await stream +@contextlib.contextmanager +def get_event_loop(): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + try: + yield loop + finally: + loop.close() class EventsConfig(AppConfig): name = 'events' def onEvent(self, block): - print(block) + payload = json.loads( + block['data']['data'][0]['payload']['data']['actions'][0]['payload']['action']['proposal_response_payload'][ + 'extension']['events']['payload']) + print(payload) + worker_queue = f"{settings.LEDGER['name']}.worker" + if payload['status'] == 'todo': + prepareTrainTuple.apply_async((payload,), queue=worker_queue) def ready(self): - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] - - client = Client() - - channel = client.new_channel(channel_name) - - target_peer = Peer(name=peer['name']) - requestor_config = LEDGER['client'] - - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer["docker_port"]}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) - - requestor = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - - - channel_event_hub = channel.newChannelEventHub(target_peer, - requestor) - - # use chaincode event - stream = channel_event_hub.connect() - cr = channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=self.onEvent) - - asyncio.run(main(stream)) + with get_event_loop() as loop: + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] + + client = Client() + + channel = client.new_channel(channel_name) + + target_peer = Peer(name=peer['name']) + requestor_config = LEDGER['client'] + + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer["port"]}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + + requestor = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + channel_event_hub = channel.newChannelEventHub(target_peer, requestor) + + # use chaincode event + stream = channel_event_hub.connect(unregister=False, filtered=False) + cr = channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=self.onEvent) + loop.run_until_complete(stream) diff --git a/substrabac/events/events.py b/substrabac/events/events.py deleted file mode 100644 index b533a427c..000000000 --- a/substrabac/events/events.py +++ /dev/null @@ -1,61 +0,0 @@ -import asyncio -import contextlib - -from django.conf import settings - -import glob - -from hfc.fabric import Client -from hfc.fabric.peer import Peer -from hfc.fabric.user import create_user -from hfc.util.keyvaluestore import FileKeyValueStore - -LEDGER = getattr(settings, 'LEDGER', None) - -@contextlib.contextmanager -def get_event_loop(): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - try: - yield loop - finally: - loop.close() - - -def onEvent(self, block): - print(block) - -with get_event_loop() as loop: - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] - - client = Client() - - channel = client.new_channel(channel_name) - - target_peer = Peer(name=peer['name']) - requestor_config = LEDGER['client'] - - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer["docker_port"]}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) - - requestor = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - - channel_event_hub = channel.newChannelEventHub(target_peer, - requestor) - - # use chaincode event - stream = channel_event_hub.connect() - cr = channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=onEvent) - loop.run_until_complete(stream) - diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index f8553395b..519a5de45 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -58,7 +58,7 @@ 'rest_framework_swagger', 'rest_framework', 'substrapp', - #'events', + 'events', ] MIDDLEWARE = [ diff --git a/substrabac/substrapp/tasks.py b/substrabac/substrapp/tasks.py index 7b2eca1b1..eb22d1c5f 100644 --- a/substrabac/substrapp/tasks.py +++ b/substrabac/substrapp/tasks.py @@ -217,6 +217,40 @@ def fail(key, err_msg, tuple_type): resources_manager = manager.ResourcesManager() +@app.task(ignore_result=False) +def prepareTrainTuple(subtuple): + from django_celery_results.models import TaskResult + + fltask = None + worker_queue = f"{settings.LEDGER['name']}.worker" + + if 'fltask' in subtuple and subtuple['fltask']: + fltask = subtuple['fltask'] + flresults = TaskResult.objects.filter(task_name='substrapp.tasks.computeTask', + result__icontains=f'"fltask": "{fltask}"') + + if flresults and flresults.count() > 0: + worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] + + try: + # Log Start of the Subtuple + start_type = 'logStartTrain' + data, st = invokeLedger(fcn=start_type, + args=[f'{subtuple["key"]}'], + sync=True) + + if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): + logging.error( + f'Failed to invoke ledger on prepareTask traintuple. Error: {data}') + else: + computeTask.apply_async(('traintuple', subtuple, 'inModels', fltask), queue=worker_queue) + + except Exception as e: + error_code = compute_error_code(e) + logging.error(error_code, exc_info=True) + return fail(subtuple['key'], error_code, 'traintuple') + + def prepareTask(tuple_type, model_type): from django_celery_results.models import TaskResult From d0757c2a1a27d7f5559d8b3ec4df1f3cc0fe7006 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 14 May 2019 17:41:43 +0200 Subject: [PATCH 018/457] Use new unregister with multiprocess --- substrabac/events/apps.py | 91 +++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index b5bcf44b8..ba707a59f 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -1,6 +1,6 @@ import asyncio -import contextlib import json +import multiprocessing from django.apps import AppConfig @@ -13,64 +13,63 @@ from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore -from substrapp.tasks import prepareTrainTuple LEDGER = getattr(settings, 'LEDGER', None) -@contextlib.contextmanager -def get_event_loop(): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - try: - yield loop - finally: - loop.close() +def onEvent(block): + payload = json.loads( + block['data']['data'][0]['payload']['data']['actions'][0]['payload']['action']['proposal_response_payload'][ + 'extension']['events']['payload']) + print(payload) + worker_queue = f"{settings.LEDGER['name']}.worker" + # TODO check if owner is the one to run task + # if payload['status'] == 'todo': + # prepareTrainTuple.apply_async((payload,), queue=worker_queue) -class EventsConfig(AppConfig): - name = 'events' - def onEvent(self, block): - payload = json.loads( - block['data']['data'][0]['payload']['data']['actions'][0]['payload']['action']['proposal_response_payload'][ - 'extension']['events']['payload']) - print(payload) - worker_queue = f"{settings.LEDGER['name']}.worker" - if payload['status'] == 'todo': - prepareTrainTuple.apply_async((payload,), queue=worker_queue) +def wait(): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] - def ready(self): - with get_event_loop() as loop: - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] + client = Client() - client = Client() + channel = client.new_channel(channel_name) - channel = client.new_channel(channel_name) + target_peer = Peer(name=peer['name']) + requestor_config = LEDGER['client'] - target_peer = Peer(name=peer['name']) - requestor_config = LEDGER['client'] + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer["port"]}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer["port"]}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) + requestor = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) - requestor = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) + channel_event_hub = channel.newChannelEventHub(target_peer, requestor) - channel_event_hub = channel.newChannelEventHub(target_peer, requestor) + # use chaincode event + stream = channel_event_hub.connect(start=0, filtered=False) + channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=onEvent) - # use chaincode event - stream = channel_event_hub.connect(unregister=False, filtered=False) - cr = channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=self.onEvent) - loop.run_until_complete(stream) + loop.run_until_complete(stream) + loop.close() +class EventsConfig(AppConfig): + name = 'events' + + def ready(self): + p1 = multiprocessing.Process(target=wait) + # always wait + p1.start() From f4de9ad8d625bb8036a6fdf71c5a0d740fe27fcb Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 20 May 2019 10:05:12 +0200 Subject: [PATCH 019/457] clean --- substrabac/events/apps.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index ba707a59f..ed843f48f 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -23,7 +23,7 @@ def onEvent(block): print(payload) worker_queue = f"{settings.LEDGER['name']}.worker" - # TODO check if owner is the one to run task + # TODO check if owner is the one to run task, wait for chaincode to send full traintuple with key inside # if payload['status'] == 'todo': # prepareTrainTuple.apply_async((payload,), queue=worker_queue) @@ -49,21 +49,25 @@ def wait(): 'clientCert': {'path': peer['clientCert']}, }) - requestor = create_user(name=requestor_config['name'], + try: + # can fail + requestor = create_user(name=requestor_config['name'], org=requestor_config['org'], state_store=FileKeyValueStore(requestor_config['state_store']), msp_id=requestor_config['msp_id'], key_path=glob.glob(requestor_config['key_path'])[0], cert_path=requestor_config['cert_path']) - - channel_event_hub = channel.newChannelEventHub(target_peer, requestor) - - # use chaincode event - stream = channel_event_hub.connect(start=0, filtered=False) - channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=onEvent) - - loop.run_until_complete(stream) - loop.close() + except: + pass + else: + channel_event_hub = channel.newChannelEventHub(target_peer, requestor) + + # use chaincode event + stream = channel_event_hub.connect(filtered=False) + channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=onEvent) + loop.run_until_complete(stream) + finally: + loop.close() class EventsConfig(AppConfig): From 1c0c366b2acd96b03035532f984b38f1b5d1b4b7 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 20 May 2019 15:12:43 +0200 Subject: [PATCH 020/457] Add comments --- substrabac/events/apps.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index ed843f48f..5e1ba8dc5 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -63,7 +63,11 @@ def wait(): channel_event_hub = channel.newChannelEventHub(target_peer, requestor) # use chaincode event + + # uncomment this line if you want to replay blocks from the beginning for debugging purposes + # stream = channel_event_hub.connect(start=0, filtered=False) stream = channel_event_hub.connect(filtered=False) + channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=onEvent) loop.run_until_complete(stream) finally: From 6ad547006711ca0bda5cc45a94f518fa0f862ddb Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 21 May 2019 18:20:14 +0200 Subject: [PATCH 021/457] Update events app to be compatible with docker. --- docker/celerybeat/Dockerfile | 1 + docker/celeryworker/Dockerfile | 1 + docker/start.py | 29 ++++++++++++++++++++++++ docker/substrabac/Dockerfile | 1 + substrabac/events/apps.py | 29 +++++++++++++----------- substrabac/requirements.txt | 2 +- substrabac/substrabac/settings/common.py | 1 - 7 files changed, 49 insertions(+), 15 deletions(-) diff --git a/docker/celerybeat/Dockerfile b/docker/celerybeat/Dockerfile index 144cdad4f..fc295cc1b 100644 --- a/docker/celerybeat/Dockerfile +++ b/docker/celerybeat/Dockerfile @@ -13,4 +13,5 @@ RUN pip3 install -r requirements.txt COPY ./substrabac/libs /usr/src/app/libs COPY ./substrabac/substrapp /usr/src/app/substrapp +COPY ./substrabac/events /usr/src/app/events COPY ./substrabac/substrabac /usr/src/app/substrabac diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index 6bf39448d..eaa7a6ae3 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -19,4 +19,5 @@ COPY ./substrabac/base_metrics /usr/src/app/base_metrics COPY ./substrabac/fake_metrics /usr/src/app/fake_metrics COPY ./substrabac/fake_data_sample /usr/src/app/fake_data_sample COPY ./substrabac/substrapp /usr/src/app/substrapp +COPY ./substrabac/events /usr/src/app/events COPY ./substrabac/substrabac /usr/src/app/substrabac diff --git a/docker/start.py b/docker/start.py index 998381faa..af63e85be 100644 --- a/docker/start.py +++ b/docker/start.py @@ -156,6 +156,34 @@ def generate_docker_compose_file(conf, launch_settings): '/substra/static:/usr/src/app/substrabac/statics'] + hlf_volumes, 'depends_on': ['postgresql', 'rabbit']} + events = {'container_name': f'{org_name_stripped}.events', + 'image': 'substra/substrabac', + 'restart': 'unless-stopped', + # 'ports': [f'{port}:{port}'], + 'command': f'/bin/bash -c "python events/apps.py"', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': ['DATABASE_HOST=postgresql', + 'SUBSTRABAC_PEER_PORT=internal', + f'CELERY_BROKER_URL={CELERY_BROKER_URL}', + f'SUBSTRABAC_ORG={org_name}', + f'SUBSTRABAC_DEFAULT_PORT={port}', + f'DJANGO_SETTINGS_MODULE=substrabac.settings.{launch_settings}', + 'PYTHONUNBUFFERED=1', + f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', '')}", + f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', '')}", + f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", + f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", + f"FABRIC_CFG_PATH_ENV={org['peer']['docker_core_dir']}", + f"CORE_PEER_ADDRESS_ENV={org['peer']['host']}:{org['peer']['port']['internal']}", + f"FABRIC_LOGGING_SPEC={FABRIC_LOGGING_SPEC}"], + 'volumes': [f'/substra/conf/{org_name}:/substra/conf/{org_name}', + f'{orderer_ca}:{orderer_ca}', + f'/substra/data/orgs/{org_name}/ca-cert.pem:/substra/data/orgs/{org_name}/ca-cert.pem', + f'{org["core_peer_mspconfigpath"]}:{org["core_peer_mspconfigpath"]}', + f'/substra/data/orgs/{org_name}/tls/{peer}:/substra/data/orgs/{org_name}/tls/{peer}', + ], + 'depends_on': ['postgresql', 'rabbit']} + scheduler = {'container_name': f'{org_name_stripped}.scheduler', 'hostname': f'{org_name}.scheduler', 'image': 'substra/celeryworker', @@ -217,6 +245,7 @@ def generate_docker_compose_file(conf, launch_settings): dryrunner['environment'].append(f"RAVEN_URL={raven_dryrunner_url}") docker_compose['substrabac_services']['substrabac' + org_name_stripped] = backend + docker_compose['substrabac_services']['events' + org_name_stripped] = events docker_compose['substrabac_services']['scheduler' + org_name_stripped] = scheduler docker_compose['substrabac_services']['worker' + org_name_stripped] = worker docker_compose['substrabac_services']['dryrunner' + org_name_stripped] = dryrunner diff --git a/docker/substrabac/Dockerfile b/docker/substrabac/Dockerfile index 053c45257..44ca550c9 100644 --- a/docker/substrabac/Dockerfile +++ b/docker/substrabac/Dockerfile @@ -17,4 +17,5 @@ RUN pip3 install -r requirements.txt COPY ./substrabac/manage.py /usr/src/app/manage.py COPY ./substrabac/libs /usr/src/app/libs COPY ./substrabac/substrapp /usr/src/app/substrapp +COPY ./substrabac/events /usr/src/app/events COPY ./substrabac/substrabac /usr/src/app/substrabac diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 5e1ba8dc5..edcb20882 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -1,10 +1,7 @@ import asyncio import json import multiprocessing - -from django.apps import AppConfig - -from django.conf import settings +import os import glob @@ -14,14 +11,20 @@ from hfc.util.keyvaluestore import FileKeyValueStore -LEDGER = getattr(settings, 'LEDGER', None) +ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') + +try: + LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) +except: + pass + def onEvent(block): payload = json.loads( block['data']['data'][0]['payload']['data']['actions'][0]['payload']['action']['proposal_response_payload'][ 'extension']['events']['payload']) print(payload) - worker_queue = f"{settings.LEDGER['name']}.worker" + worker_queue = f"{LEDGER['name']}.worker" # TODO check if owner is the one to run task, wait for chaincode to send full traintuple with key inside # if payload['status'] == 'todo': @@ -35,6 +38,8 @@ def wait(): chaincode_name = LEDGER['chaincode_name'] peer = LEDGER['peer'] + peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + client = Client() channel = client.new_channel(channel_name) @@ -42,7 +47,7 @@ def wait(): target_peer = Peer(name=peer['name']) requestor_config = LEDGER['client'] - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer["port"]}', + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', 'grpcOptions': peer['grpcOptions'], 'tlsCACerts': {'path': peer['tlsCACerts']}, 'clientKey': {'path': peer['clientKey']}, @@ -74,10 +79,8 @@ def wait(): loop.close() -class EventsConfig(AppConfig): - name = 'events' +if __name__ == '__main__': - def ready(self): - p1 = multiprocessing.Process(target=wait) - # always wait - p1.start() + p1 = multiprocessing.Process(target=wait) + # always wait + p1.start() diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index c37a0586f..bae7fbcd9 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,4 +26,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -git+https://github.com/hyperledger/fabric-sdk-py.git@943b1a5b1ee00781f596a9e8a5e8836f09effd46 +git+https://github.com/hyperledger/fabric-sdk-py.git@da79711005db8509f5c5b97f384cb19715bff75e diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 519a5de45..6598755b5 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -58,7 +58,6 @@ 'rest_framework_swagger', 'rest_framework', 'substrapp', - 'events', ] MIDDLEWARE = [ From 89437dd625639c9a702bcbacdbdb5b4570faec9a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 22 May 2019 15:20:49 +0200 Subject: [PATCH 022/457] Update docker events service --- docker/start.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/docker/start.py b/docker/start.py index af63e85be..77f9696a0 100644 --- a/docker/start.py +++ b/docker/start.py @@ -159,29 +159,10 @@ def generate_docker_compose_file(conf, launch_settings): events = {'container_name': f'{org_name_stripped}.events', 'image': 'substra/substrabac', 'restart': 'unless-stopped', - # 'ports': [f'{port}:{port}'], 'command': f'/bin/bash -c "python events/apps.py"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': ['DATABASE_HOST=postgresql', - 'SUBSTRABAC_PEER_PORT=internal', - f'CELERY_BROKER_URL={CELERY_BROKER_URL}', - f'SUBSTRABAC_ORG={org_name}', - f'SUBSTRABAC_DEFAULT_PORT={port}', - f'DJANGO_SETTINGS_MODULE=substrabac.settings.{launch_settings}', - 'PYTHONUNBUFFERED=1', - f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', '')}", - f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', '')}", - f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", - f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", - f"FABRIC_CFG_PATH_ENV={org['peer']['docker_core_dir']}", - f"CORE_PEER_ADDRESS_ENV={org['peer']['host']}:{org['peer']['port']['internal']}", - f"FABRIC_LOGGING_SPEC={FABRIC_LOGGING_SPEC}"], - 'volumes': [f'/substra/conf/{org_name}:/substra/conf/{org_name}', - f'{orderer_ca}:{orderer_ca}', - f'/substra/data/orgs/{org_name}/ca-cert.pem:/substra/data/orgs/{org_name}/ca-cert.pem', - f'{org["core_peer_mspconfigpath"]}:{org["core_peer_mspconfigpath"]}', - f'/substra/data/orgs/{org_name}/tls/{peer}:/substra/data/orgs/{org_name}/tls/{peer}', - ], + 'environment': backend_global_env.copy(), + 'volumes': hlf_volumes.copy(), 'depends_on': ['postgresql', 'rabbit']} scheduler = {'container_name': f'{org_name_stripped}.scheduler', From abcd25f9e443f61595b2e2a290daf6c141641b89 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 23 May 2019 10:31:21 +0200 Subject: [PATCH 023/457] Fix events startup in docker. --- docker/celerybeat/Dockerfile | 1 - docker/celeryworker/Dockerfile | 1 - docker/start.py | 14 +-- substrabac/events/apps.py | 86 ++++++++++++------- substrabac/substrabac/celery.py | 10 +-- .../substrabac/settings/events/__init__.py | 0 substrabac/substrabac/settings/events/dev.py | 5 ++ substrabac/substrabac/settings/events/prod.py | 5 ++ substrabac/substrabac/settings/prod.py | 1 - 9 files changed, 72 insertions(+), 51 deletions(-) create mode 100644 substrabac/substrabac/settings/events/__init__.py create mode 100644 substrabac/substrabac/settings/events/dev.py create mode 100644 substrabac/substrabac/settings/events/prod.py diff --git a/docker/celerybeat/Dockerfile b/docker/celerybeat/Dockerfile index fc295cc1b..144cdad4f 100644 --- a/docker/celerybeat/Dockerfile +++ b/docker/celerybeat/Dockerfile @@ -13,5 +13,4 @@ RUN pip3 install -r requirements.txt COPY ./substrabac/libs /usr/src/app/libs COPY ./substrabac/substrapp /usr/src/app/substrapp -COPY ./substrabac/events /usr/src/app/events COPY ./substrabac/substrabac /usr/src/app/substrabac diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index eaa7a6ae3..6bf39448d 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -19,5 +19,4 @@ COPY ./substrabac/base_metrics /usr/src/app/base_metrics COPY ./substrabac/fake_metrics /usr/src/app/fake_metrics COPY ./substrabac/fake_data_sample /usr/src/app/fake_data_sample COPY ./substrabac/substrapp /usr/src/app/substrapp -COPY ./substrabac/events /usr/src/app/events COPY ./substrabac/substrabac /usr/src/app/substrabac diff --git a/docker/start.py b/docker/start.py index 77f9696a0..6297a3375 100644 --- a/docker/start.py +++ b/docker/start.py @@ -97,10 +97,10 @@ def generate_docker_compose_file(conf, launch_settings): processes = 2 * int(cpu_count) + 1 if launch_settings == 'prod': - django_server = f'python3 manage.py collectstatic --noinput; uwsgi --http :{port} --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes {processes} --threads 2' + django_server = f'python3 manage.py collectstatic --noinput; DJANGO_SETTINGS_MODULE=substrabac.settings.events.prod uwsgi --http :{port} --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes {processes} --threads 2' else: - django_server = f'python3 manage.py runserver 0.0.0.0:{port}' + django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.events.dev python3 manage.py runserver 0.0.0.0:{port}' backend_global_env = [ f'ORG={org_name_stripped}', @@ -156,15 +156,6 @@ def generate_docker_compose_file(conf, launch_settings): '/substra/static:/usr/src/app/substrabac/statics'] + hlf_volumes, 'depends_on': ['postgresql', 'rabbit']} - events = {'container_name': f'{org_name_stripped}.events', - 'image': 'substra/substrabac', - 'restart': 'unless-stopped', - 'command': f'/bin/bash -c "python events/apps.py"', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': backend_global_env.copy(), - 'volumes': hlf_volumes.copy(), - 'depends_on': ['postgresql', 'rabbit']} - scheduler = {'container_name': f'{org_name_stripped}.scheduler', 'hostname': f'{org_name}.scheduler', 'image': 'substra/celeryworker', @@ -226,7 +217,6 @@ def generate_docker_compose_file(conf, launch_settings): dryrunner['environment'].append(f"RAVEN_URL={raven_dryrunner_url}") docker_compose['substrabac_services']['substrabac' + org_name_stripped] = backend - docker_compose['substrabac_services']['events' + org_name_stripped] = events docker_compose['substrabac_services']['scheduler' + org_name_stripped] = scheduler docker_compose['substrabac_services']['worker' + org_name_stripped] = worker docker_compose['substrabac_services']['dryrunner' + org_name_stripped] = dryrunner diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index edcb20882..4805b803a 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -1,8 +1,13 @@ import asyncio import json +import logging import multiprocessing import os +from django.apps import AppConfig + +from django.conf import settings + import glob from hfc.fabric import Client @@ -10,25 +15,36 @@ from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore +from substrapp.tasks import prepareTrainTuple +from substrapp.utils import get_hash -ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') - -try: - LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) -except: - pass +LEDGER = getattr(settings, 'LEDGER', None) -def onEvent(block): +def get_block_payload(block): payload = json.loads( block['data']['data'][0]['payload']['data']['actions'][0]['payload']['action']['proposal_response_payload'][ 'extension']['events']['payload']) - print(payload) - worker_queue = f"{LEDGER['name']}.worker" + return payload + +def onEvent(block): + payload = get_block_payload(block) + + import pprint + pp = pprint.PrettyPrinter(indent=4) + pp.pprint(payload) + print('_' * 100) + + worker_queue = f"{LEDGER['name']}.worker" # TODO check if owner is the one to run task, wait for chaincode to send full traintuple with key inside - # if payload['status'] == 'todo': - # prepareTrainTuple.apply_async((payload,), queue=worker_queue) + try: + data_owner = get_hash(LEDGER['signcert']) + except Exception as e: + logging.error(e, exc_info=True) + else: + if data_owner == payload['dataset']['worker']: + prepareTrainTuple.apply_async((payload,), queue=worker_queue) def wait(): @@ -47,40 +63,48 @@ def wait(): target_peer = Peer(name=peer['name']) requestor_config = LEDGER['client'] - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) + target_peer.init_with_bundle({ + 'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) try: # can fail - requestor = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) + requestor = create_user( + name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path'] + ) except: pass else: - channel_event_hub = channel.newChannelEventHub(target_peer, requestor) + channel_event_hub = channel.newChannelEventHub(target_peer, + requestor) # use chaincode event # uncomment this line if you want to replay blocks from the beginning for debugging purposes - # stream = channel_event_hub.connect(start=0, filtered=False) - stream = channel_event_hub.connect(filtered=False) + stream = channel_event_hub.connect(start=0, filtered=False) + # stream = channel_event_hub.connect(filtered=False) - channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', onEvent=onEvent) + channel_event_hub.registerChaincodeEvent(chaincode_name, + 'traintuple-creation', + onEvent=onEvent) loop.run_until_complete(stream) finally: loop.close() -if __name__ == '__main__': +class EventsConfig(AppConfig): + name = 'events' - p1 = multiprocessing.Process(target=wait) - # always wait - p1.start() + def ready(self): + # always wait + p1 = multiprocessing.Process(target=wait) + p1.start() diff --git a/substrabac/substrabac/celery.py b/substrabac/substrabac/celery.py index c3443c0ed..e6b614f54 100644 --- a/substrabac/substrabac/celery.py +++ b/substrabac/substrabac/celery.py @@ -27,8 +27,8 @@ def debug_task(self): def setup_periodic_tasks(sender, **kwargs): from substrapp.tasks import prepareTrainingTask, prepareTestingTask - #period = 10 - #sender.add_periodic_task(period, prepareTrainingTask.s(), queue='scheduler', - # name='query Traintuples to prepare train task on todo traintuples') - #sender.add_periodic_task(period, prepareTestingTask.s(), queue='scheduler', - # name='query Testuples to prepare test task on todo testuples') + period = 3 * 3600 + sender.add_periodic_task(period, prepareTrainingTask.s(), queue='scheduler', + name='query Traintuples to prepare train task on todo traintuples') + sender.add_periodic_task(period, prepareTestingTask.s(), queue='scheduler', + name='query Testuples to prepare test task on todo testuples') diff --git a/substrabac/substrabac/settings/events/__init__.py b/substrabac/substrabac/settings/events/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/substrabac/settings/events/dev.py b/substrabac/substrabac/settings/events/dev.py new file mode 100644 index 000000000..d90cec828 --- /dev/null +++ b/substrabac/substrabac/settings/events/dev.py @@ -0,0 +1,5 @@ +import os + +from ..dev import * + +INSTALLED_APPS += ['events'] diff --git a/substrabac/substrabac/settings/events/prod.py b/substrabac/substrabac/settings/events/prod.py new file mode 100644 index 000000000..1d6058bf5 --- /dev/null +++ b/substrabac/substrabac/settings/events/prod.py @@ -0,0 +1,5 @@ +import os + +from ..prod import * + +INSTALLED_APPS += ['events'] diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 40cb1fee6..157d295e2 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -53,7 +53,6 @@ BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', None) MIDDLEWARE += ['libs.BasicAuthMiddleware.BasicAuthMiddleware'] - LOGGING = { 'version': 1, 'disable_existing_loggers': False, From 8cd2009f9c93f1600a62555f6cbeb20a44e913a6 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 23 May 2019 11:33:33 +0200 Subject: [PATCH 024/457] Add testtuple events. --- substrabac/events/apps.py | 32 +++++++++++++++++++++---- substrabac/requirements.txt | 2 +- substrabac/substrabac/settings/dev.py | 2 +- substrabac/substrapp/tasks.py | 34 +++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 4805b803a..c0376b525 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -15,7 +15,7 @@ from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore -from substrapp.tasks import prepareTrainTuple +from substrapp.tasks import prepareTrainTuple, prepareTestTuple from substrapp.utils import get_hash LEDGER = getattr(settings, 'LEDGER', None) @@ -28,7 +28,26 @@ def get_block_payload(block): return payload -def onEvent(block): +def onTesttupleEvent(block): + payload = get_block_payload(block) + + import pprint + pp = pprint.PrettyPrinter(indent=4) + pp.pprint(payload) + print('_' * 100) + + worker_queue = f"{LEDGER['name']}.worker" + # TODO check if owner is the one to run task, wait for chaincode to send full traintuple with key inside + try: + data_owner = get_hash(LEDGER['signcert']) + except Exception as e: + logging.error(e, exc_info=True) + else: + if data_owner == payload['dataset']['worker']: + prepareTestTuple.apply_async((payload,), queue=worker_queue) + + +def onTraintupleEvent(block): payload = get_block_payload(block) import pprint @@ -90,12 +109,15 @@ def wait(): # use chaincode event # uncomment this line if you want to replay blocks from the beginning for debugging purposes - stream = channel_event_hub.connect(start=0, filtered=False) - # stream = channel_event_hub.connect(filtered=False) + # stream = channel_event_hub.connect(start=0, filtered=False) + stream = channel_event_hub.connect(filtered=False) channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', - onEvent=onEvent) + onEvent=onTraintupleEvent) + channel_event_hub.registerChaincodeEvent(chaincode_name, + 'testtuple-creation', + onEvent=onTesttupleEvent) loop.run_until_complete(stream) finally: loop.close() diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index bae7fbcd9..f09240373 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,4 +26,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -git+https://github.com/hyperledger/fabric-sdk-py.git@da79711005db8509f5c5b97f384cb19715bff75e +git+https://github.com/hyperledger/fabric-sdk-py.git@282b4f0d19409a4686a34f5ace603e7226ef5dd3 diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index f9c580123..714c3e105 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -80,7 +80,7 @@ 'django.request': { 'handlers': ['mail_admins', 'error_file'], 'level': 'INFO', - 'propagate': True, + 'propagate': False, }, } } diff --git a/substrabac/substrapp/tasks.py b/substrabac/substrapp/tasks.py index eb22d1c5f..3ed7feff2 100644 --- a/substrabac/substrapp/tasks.py +++ b/substrabac/substrapp/tasks.py @@ -251,6 +251,40 @@ def prepareTrainTuple(subtuple): return fail(subtuple['key'], error_code, 'traintuple') +@app.task(ignore_result=False) +def prepareTestTuple(subtuple): + from django_celery_results.models import TaskResult + + fltask = None + worker_queue = f"{settings.LEDGER['name']}.worker" + + if 'fltask' in subtuple and subtuple['fltask']: + fltask = subtuple['fltask'] + flresults = TaskResult.objects.filter(task_name='substrapp.tasks.computeTask', + result__icontains=f'"fltask": "{fltask}"') + + if flresults and flresults.count() > 0: + worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] + + try: + # Log Start of the Subtuple + start_type = 'logStartTest' + data, st = invokeLedger(fcn=start_type, + args=[f'{subtuple["key"]}'], + sync=True) + + if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): + logging.error( + f'Failed to invoke ledger on prepareTask testtuple. Error: {data}') + else: + computeTask.apply_async(('testtuple', subtuple, 'model', fltask), queue=worker_queue) + + except Exception as e: + error_code = compute_error_code(e) + logging.error(error_code, exc_info=True) + return fail(subtuple['key'], error_code, 'testtuple') + + def prepareTask(tuple_type, model_type): from django_celery_results.models import TaskResult From 55182098acfb69331e699bc76d7067591c37d0e8 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 23 May 2019 12:07:19 +0200 Subject: [PATCH 025/457] Clean + Refacto + Doc --- README.md | 9 ++- substrabac/events/apps.py | 143 +++++++++++++++------------------- substrabac/substrapp/tasks.py | 84 +++----------------- 3 files changed, 77 insertions(+), 159 deletions(-) diff --git a/README.md b/README.md index 4be9757c2..7ef72dd27 100644 --- a/README.md +++ b/README.md @@ -154,14 +154,15 @@ DJANGO_SETTINGS_MODULE=substrabac.settings.common celery -A substrabac beat -l i ## Launch the servers -Go in the `substrabac` folder and run the server locally: +Go in the `substrabac` folder and run the server locally: +:warning:

Be very careful, --settings is different here, `events` is needed.

``` - SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.dev - SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.dev + SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.events.dev + SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.events.dev ``` -## Test with unit and functionnal tests +## Test with unit and functional tests ``` DJANGO_SETTINGS_MODULE=substrabac.settings.test coverage run manage.py test diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index c0376b525..663dd5b01 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -15,8 +15,8 @@ from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore -from substrapp.tasks import prepareTrainTuple, prepareTestTuple -from substrapp.utils import get_hash +from substrapp.tasks import prepareTuple +from substrapp.utils import get_hash, get_event_loop LEDGER = getattr(settings, 'LEDGER', None) @@ -28,99 +28,78 @@ def get_block_payload(block): return payload -def onTesttupleEvent(block): +def onTupleEvent(block): payload = get_block_payload(block) - import pprint - pp = pprint.PrettyPrinter(indent=4) - pp.pprint(payload) - print('_' * 100) - worker_queue = f"{LEDGER['name']}.worker" - # TODO check if owner is the one to run task, wait for chaincode to send full traintuple with key inside try: data_owner = get_hash(LEDGER['signcert']) except Exception as e: logging.error(e, exc_info=True) else: if data_owner == payload['dataset']['worker']: - prepareTestTuple.apply_async((payload,), queue=worker_queue) - - -def onTraintupleEvent(block): - payload = get_block_payload(block) - - import pprint - pp = pprint.PrettyPrinter(indent=4) - pp.pprint(payload) - print('_' * 100) + tuple_type, model_type = (None, None) + if 'inModels' in payload: + tuple_type, model_type = ('traintuple', 'inModels') + elif 'model' in payload: + tuple_type, model_type = ('testtuple', 'model') - worker_queue = f"{LEDGER['name']}.worker" - # TODO check if owner is the one to run task, wait for chaincode to send full traintuple with key inside - try: - data_owner = get_hash(LEDGER['signcert']) - except Exception as e: - logging.error(e, exc_info=True) - else: - if data_owner == payload['dataset']['worker']: - prepareTrainTuple.apply_async((payload,), queue=worker_queue) + if tuple_type is not None and model_type is not None: + prepareTuple.apply_async((payload, tuple_type, model_type), queue=worker_queue) def wait(): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] - - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] - - client = Client() - - channel = client.new_channel(channel_name) - - target_peer = Peer(name=peer['name']) - requestor_config = LEDGER['client'] - - target_peer.init_with_bundle({ - 'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) - - try: - # can fail - requestor = create_user( - name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path'] - ) - except: - pass - else: - channel_event_hub = channel.newChannelEventHub(target_peer, - requestor) - - # use chaincode event - - # uncomment this line if you want to replay blocks from the beginning for debugging purposes - # stream = channel_event_hub.connect(start=0, filtered=False) - stream = channel_event_hub.connect(filtered=False) - - channel_event_hub.registerChaincodeEvent(chaincode_name, - 'traintuple-creation', - onEvent=onTraintupleEvent) - channel_event_hub.registerChaincodeEvent(chaincode_name, - 'testtuple-creation', - onEvent=onTesttupleEvent) - loop.run_until_complete(stream) - finally: - loop.close() + with get_event_loop() as loop: + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] + + peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + + client = Client() + + channel = client.new_channel(channel_name) + + target_peer = Peer(name=peer['name']) + requestor_config = LEDGER['client'] + + target_peer.init_with_bundle({ + 'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + + try: + # can fail + requestor = create_user( + name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path'] + ) + except: + pass + else: + channel_event_hub = channel.newChannelEventHub(target_peer, + requestor) + + # use chaincode event + + # uncomment this line if you want to replay blocks from the beginning for debugging purposes + # stream = channel_event_hub.connect(start=0, filtered=False) + stream = channel_event_hub.connect(filtered=False) + + channel_event_hub.registerChaincodeEvent(chaincode_name, + 'traintuple-creation', + onEvent=onTupleEvent) + channel_event_hub.registerChaincodeEvent(chaincode_name, + 'testtuple-creation', + onEvent=onTupleEvent) + loop.run_until_complete(stream) class EventsConfig(AppConfig): diff --git a/substrabac/substrapp/tasks.py b/substrabac/substrapp/tasks.py index 3ed7feff2..d0c65963f 100644 --- a/substrabac/substrapp/tasks.py +++ b/substrabac/substrapp/tasks.py @@ -218,7 +218,7 @@ def fail(key, err_msg, tuple_type): @app.task(ignore_result=False) -def prepareTrainTuple(subtuple): +def prepareTuple(subtuple, tuple_type, model_type): from django_celery_results.models import TaskResult fltask = None @@ -226,63 +226,32 @@ def prepareTrainTuple(subtuple): if 'fltask' in subtuple and subtuple['fltask']: fltask = subtuple['fltask'] - flresults = TaskResult.objects.filter(task_name='substrapp.tasks.computeTask', - result__icontains=f'"fltask": "{fltask}"') + flresults = TaskResult.objects.filter( + task_name='substrapp.tasks.computeTask', + result__icontains=f'"fltask": "{fltask}"') if flresults and flresults.count() > 0: worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] try: # Log Start of the Subtuple - start_type = 'logStartTrain' + start_type = 'logStartTrain' if tuple_type == 'traintuple' else 'logStartTest' if tuple_type == 'testtuple' else None data, st = invokeLedger(fcn=start_type, args=[f'{subtuple["key"]}'], sync=True) if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): logging.error( - f'Failed to invoke ledger on prepareTask traintuple. Error: {data}') + f'Failed to invoke ledger on prepareTask {tuple_type}. Error: {data}') else: - computeTask.apply_async(('traintuple', subtuple, 'inModels', fltask), queue=worker_queue) + computeTask.apply_async( + (tuple_type, subtuple, model_type, fltask), + queue=worker_queue) except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - return fail(subtuple['key'], error_code, 'traintuple') - - -@app.task(ignore_result=False) -def prepareTestTuple(subtuple): - from django_celery_results.models import TaskResult - - fltask = None - worker_queue = f"{settings.LEDGER['name']}.worker" - - if 'fltask' in subtuple and subtuple['fltask']: - fltask = subtuple['fltask'] - flresults = TaskResult.objects.filter(task_name='substrapp.tasks.computeTask', - result__icontains=f'"fltask": "{fltask}"') - - if flresults and flresults.count() > 0: - worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] - - try: - # Log Start of the Subtuple - start_type = 'logStartTest' - data, st = invokeLedger(fcn=start_type, - args=[f'{subtuple["key"]}'], - sync=True) - - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - logging.error( - f'Failed to invoke ledger on prepareTask testtuple. Error: {data}') - else: - computeTask.apply_async(('testtuple', subtuple, 'model', fltask), queue=worker_queue) - - except Exception as e: - error_code = compute_error_code(e) - logging.error(error_code, exc_info=True) - return fail(subtuple['key'], error_code, 'testtuple') + return fail(subtuple['key'], error_code, tuple_type) def prepareTask(tuple_type, model_type): @@ -300,38 +269,7 @@ def prepareTask(tuple_type, model_type): if st == status.HTTP_200_OK and subtuples is not None: for subtuple in subtuples: - - fltask = None - worker_queue = f"{settings.LEDGER['name']}.worker" - - if 'fltask' in subtuple and subtuple['fltask']: - fltask = subtuple['fltask'] - flresults = TaskResult.objects.filter( - task_name='substrapp.tasks.computeTask', - result__icontains=f'"fltask": "{fltask}"') - - if flresults and flresults.count() > 0: - worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] - - try: - # Log Start of the Subtuple - start_type = 'logStartTrain' if tuple_type == 'traintuple' else 'logStartTest' if tuple_type == 'testtuple' else None - data, st = invokeLedger(fcn=start_type, - args=[f'{subtuple["key"]}'], - sync=True) - - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - logging.error( - f'Failed to invoke ledger on prepareTask {tuple_type}. Error: {data}') - else: - computeTask.apply_async( - (tuple_type, subtuple, model_type, fltask), - queue=worker_queue) - - except Exception as e: - error_code = compute_error_code(e) - logging.error(error_code, exc_info=True) - return fail(subtuple['key'], error_code, tuple_type) + prepareTuple(subtuple, tuple_type, model_type) @app.task(bind=True, ignore_result=True) From 4745532e69404701c8392502058ea0cddcd5fadd Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 23 May 2019 15:31:23 +0200 Subject: [PATCH 026/457] Improve fabric-sdk-py intergration with events. --- docker/celeryworker/Dockerfile | 3 - docker/start.py | 12 - docker/substrabac/Dockerfile | 3 - substrabac/events/apps.py | 15 +- substrabac/substrabac/settings/dev.py | 52 +++++ substrabac/substrabac/settings/prod.py | 69 +++++- substrabac/substrapp/utils.py | 297 +++++++++---------------- 7 files changed, 238 insertions(+), 213 deletions(-) diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index 6bf39448d..af5740534 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -7,9 +7,6 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./bootstrap.sh /usr/src/ -RUN cd ../; sh bootstrap.sh; cd app - COPY ./substrabac/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt diff --git a/docker/start.py b/docker/start.py index 6297a3375..958a67d61 100644 --- a/docker/start.py +++ b/docker/start.py @@ -119,18 +119,6 @@ def generate_docker_compose_file(conf, launch_settings): f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', '')}", f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", - - # HLF overwrite config from core.yaml - f"FABRIC_CFG_PATH_ENV={org['peer']['docker_core_dir']}", - f"FABRIC_LOGGING_SPEC={FABRIC_LOGGING_SPEC}", - f"CORE_PEER_ADDRESS_ENV={org['peer']['host']}:{org['peer']['port']['internal']}", - f"CORE_PEER_MSPCONFIGPATH={org['core_peer_mspconfigpath']}", - f"CORE_PEER_TLS_CERT_FILE={tls_peer_dir}/server/server.crt", - f"CORE_PEER_TLS_KEY_FILE={tls_peer_dir}/server/server.key", - f"CORE_PEER_TLS_ROOTCERT_FILE={tls_peer_dir}/server/server.pem", - f"CORE_PEER_TLS_CLIENTCERT_FILE={tls_peer_dir}/client/client.crt", - f"CORE_PEER_TLS_CLIENTKEY_FILE={tls_peer_dir}/client/client.key", - f"CORE_PEER_TLS_CLIENTROOTCAS_FILES={tls_peer_dir}/client/client.pem", ] hlf_volumes = [ diff --git a/docker/substrabac/Dockerfile b/docker/substrabac/Dockerfile index 44ca550c9..4e62bed49 100644 --- a/docker/substrabac/Dockerfile +++ b/docker/substrabac/Dockerfile @@ -7,9 +7,6 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./bootstrap.sh /usr/src/ -RUN cd ../; sh bootstrap.sh; cd app - COPY ./substrabac/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 663dd5b01..d2b47eeb3 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -3,6 +3,7 @@ import logging import multiprocessing import os +import contextlib from django.apps import AppConfig @@ -16,11 +17,21 @@ from hfc.util.keyvaluestore import FileKeyValueStore from substrapp.tasks import prepareTuple -from substrapp.utils import get_hash, get_event_loop +from substrapp.utils import get_hash LEDGER = getattr(settings, 'LEDGER', None) +@contextlib.contextmanager +def get_event_loop(): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + try: + yield loop + finally: + loop.close() + + def get_block_payload(block): payload = json.loads( block['data']['data'][0]['payload']['data']['actions'][0]['payload']['action']['proposal_response_payload'][ @@ -74,7 +85,7 @@ def wait(): try: # can fail requestor = create_user( - name=requestor_config['name'], + name=requestor_config['name'] + '_events', org=requestor_config['org'], state_store=FileKeyValueStore(requestor_config['state_store']), msp_id=requestor_config['msp_id'], diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 714c3e105..04830fa88 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -1,10 +1,18 @@ import os +import asyncio +import glob from .common import * from .deps.restframework import * from .deps.cors import * +from hfc.fabric import Client +from hfc.fabric.peer import Peer +from hfc.fabric.user import create_user +from hfc.fabric.orderer import Orderer +from hfc.util.keyvaluestore import FileKeyValueStore + DEBUG = True @@ -18,6 +26,50 @@ LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) except: pass +else: + HLF_LOOP = asyncio.new_event_loop() + asyncio.set_event_loop(HLF_LOOP) + + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] + peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + orderer = LEDGER['orderer'] + + requestor_config = LEDGER['client'] + + CLIENT = Client() + CLIENT.new_channel(channel_name) + + REQUESTOR = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + target_peer = Peer(name=peer['name']) + + # Need loop + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + CLIENT._peers[peer['name']] = target_peer + + target_orderer = Orderer(name=orderer['name']) + + # Need loop + target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', + 'grpcOptions': orderer['grpcOptions'], + 'tlsCACerts': {'path': orderer['ca']}, + 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) + }) + CLIENT._orderers[orderer['name']] = target_orderer + # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 157d295e2..f8421c582 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -1,4 +1,6 @@ import os +import asyncio +import glob from .common import * @@ -6,7 +8,26 @@ from .deps.cors import * from .deps.raven import * +from hfc.fabric import Client +from hfc.fabric.peer import Peer +from hfc.fabric.user import create_user +from hfc.fabric.orderer import Orderer +from hfc.util.keyvaluestore import FileKeyValueStore + + DEBUG = False + + +@contextlib.contextmanager +def get_event_loop(): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + try: + yield loop + finally: + loop.close() + + USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') os.environ['HTTPS'] = "on" @@ -20,7 +41,53 @@ ORG_NAME = ORG.replace('-', '') ORG_DB_NAME = ORG.replace('-', '_').upper() -LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) +try: + LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) +except: + pass +else: + HLF_LOOP = asyncio.new_event_loop() + asyncio.set_event_loop(HLF_LOOP) + + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] + peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + orderer = LEDGER['orderer'] + + requestor_config = LEDGER['client'] + + CLIENT = Client() + CLIENT.new_channel(channel_name) + + REQUESTOR = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + + target_peer = Peer(name=peer['name']) + + # Need loop + target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) + CLIENT._peers[peer['name']] = target_peer + + target_orderer = Orderer(name=orderer['name']) + + # Need loop + target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', + 'grpcOptions': orderer['grpcOptions'], + 'tlsCACerts': {'path': orderer['ca']}, + 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) + }) + CLIENT._orderers[orderer['name']] = target_orderer # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 80e2f8383..150afa113 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -1,9 +1,8 @@ -import contextlib + import io import asyncio import hashlib import json -import glob import logging import os import tempfile @@ -19,218 +18,132 @@ from django.conf import settings LEDGER = getattr(settings, 'LEDGER', None) - -from hfc.fabric import Client -from hfc.fabric.peer import Peer -from hfc.fabric.user import create_user -from hfc.fabric.orderer import Orderer -from hfc.util.keyvaluestore import FileKeyValueStore - - -def clean_env_variables(): - os.environ.pop('FABRIC_CFG_PATH', None) - os.environ.pop('CORE_PEER_MSPCONFIGPATH', None) - os.environ.pop('CORE_PEER_ADDRESS', None) - - -####### -# /!\ # -####### - -@contextlib.contextmanager -def get_event_loop(): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - try: - yield loop - finally: - loop.close() +CLIENT = getattr(settings, 'CLIENT', None) +REQUESTOR = getattr(settings, 'REQUESTOR', None) +HLF_LOOP = getattr(settings, 'HLF_LOOP', None) +asyncio.set_event_loop(HLF_LOOP) # careful, passing invoke parameters to queryLedger will NOT fail def queryLedger(fcn, args=None): - with get_event_loop() as loop: - - if args is None: - args = [] - - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] - - requestor_config = LEDGER['client'] - - client = Client() - client.new_channel(channel_name) - - requestor = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - - target_peer = Peer(name=peer['name']) - - # Need loop - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) + if args is None: + args = [] + + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] + + # Get chaincode version + response = HLF_LOOP.run_until_complete( + CLIENT.query_instantiated_chaincodes( + requestor=REQUESTOR, + channel_name=channel_name, + peers=[peer['name']], + decode=True + )) + for ccs in response: + for cc in ccs.chaincodes: + if cc.name == chaincode_name: + chaincode_version = cc.version - client._peers[peer['name']] = target_peer - - # Get chaincode version - response = loop.run_until_complete( - client.query_instantiated_chaincodes( - requestor=requestor, + try: + # Async - need loop + response = HLF_LOOP.run_until_complete( + CLIENT.chaincode_query( + requestor=REQUESTOR, channel_name=channel_name, peers=[peer['name']], - decode=True - )) - for ccs in response: - for cc in ccs.chaincodes: - if cc.name == chaincode_name: - chaincode_version = cc.version + args=args, + cc_name=chaincode_name, + cc_version=chaincode_version, + fcn=fcn)) + except Exception as e: + st = status.HTTP_400_BAD_REQUEST + data = {'message': str(e)} + else: + msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' + print(msg, flush=True) + + st = status.HTTP_200_OK + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py try: - # Async - need loop - response = loop.run_until_complete( - client.chaincode_query( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - args=args, - cc_name=chaincode_name, - cc_version=chaincode_version, - fcn=fcn)) - except Exception as e: + # json transformation if needed + data = json.loads(response) + except json.decoder.JSONDecodeError: st = status.HTTP_400_BAD_REQUEST - data = {'message': str(e)} - else: - msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' - print(msg, flush=True) - - st = status.HTTP_200_OK - - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - try: - # json transformation if needed - data = json.loads(response) - except json.decoder.JSONDecodeError: - st = status.HTTP_400_BAD_REQUEST - if 'access denied' in response: - st = status.HTTP_403_FORBIDDEN - elif 'no element with key' in response: - st = status.HTTP_404_NOT_FOUND + if 'access denied' in response: + st = status.HTTP_403_FORBIDDEN + elif 'no element with key' in response: + st = status.HTTP_404_NOT_FOUND - data = {'message': response} + data = {'message': response} return data, st def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): - with get_event_loop() as loop: - if args is None: - args = [] - - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] - orderer = LEDGER['orderer'] - - requestor_config = LEDGER['client'] - - client = Client() - client.new_channel(channel_name) - - requestor = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - - target_peer = Peer(name=peer['name']) - - # Need loop - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) - client._peers[peer['name']] = target_peer - - target_orderer = Orderer(name=orderer['name']) - - # Need loop - target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', - 'grpcOptions': orderer['grpcOptions'], - 'tlsCACerts': {'path': orderer['ca']}, - 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) - 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) - }) - client._orderers[orderer['name']] = target_orderer - - # Get chaincode version - response = loop.run_until_complete( - client.query_instantiated_chaincodes( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - decode=True - )) - for ccs in response: - for cc in ccs.chaincodes: - if cc.name == chaincode_name: - chaincode_version = cc.version + if args is None: + args = [] + + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + peer = LEDGER['peer'] + + # Get chaincode version + response = HLF_LOOP.run_until_complete( + CLIENT.query_instantiated_chaincodes( + requestor=REQUESTOR, + channel_name=channel_name, + peers=[peer['name']], + decode=True + )) + for ccs in response: + for cc in ccs.chaincodes: + if cc.name == chaincode_name: + chaincode_version = cc.version + try: + # Async - need loop + kwargs = { + 'requestor': REQUESTOR, + 'channel_name': channel_name, + 'peers': [peer['name']], + 'args': args, + 'cc_name': chaincode_name, + 'cc_version': chaincode_version, + 'fcn': fcn, + 'wait_for_event': sync, + 'wait_for_event_timeout': 45 + } + if cc_pattern: + kwargs['cc_pattern'] = cc_pattern + + response = HLF_LOOP.run_until_complete(CLIENT.chaincode_invoke(**kwargs)) + except TimeoutError as e: + st = status.HTTP_408_REQUEST_TIMEOUT + data = {'message': str(e)} + except Exception as e: + st = status.HTTP_400_BAD_REQUEST + data = {'message': str(e)} + else: + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py + # elif 'access denied' in msg or 'authentication handshake failed' in msg: + # st = status.HTTP_403_FORBIDDEN + + st = status.HTTP_201_CREATED try: - # Async - need loop - kwargs = { - 'requestor': requestor, - 'channel_name': channel_name, - 'peers': [peer['name']], - 'args': args, - 'cc_name': chaincode_name, - 'cc_version': chaincode_version, - 'fcn': fcn, - 'wait_for_event': sync, - 'wait_for_event_timeout': 45 - } - if cc_pattern: - kwargs['cc_pattern'] = cc_pattern - - response = loop.run_until_complete(client.chaincode_invoke(**kwargs)) - except TimeoutError as e: - st = status.HTTP_408_REQUEST_TIMEOUT - data = {'message': str(e)} - except Exception as e: + response = json.loads(response) + pkhash = response.get('key', response.get('keys')) + data = {'pkhash': pkhash} + except json.decoder.JSONDecodeError: st = status.HTTP_400_BAD_REQUEST - data = {'message': str(e)} - else: - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - # elif 'access denied' in msg or 'authentication handshake failed' in msg: - # st = status.HTTP_403_FORBIDDEN - - st = status.HTTP_201_CREATED - try: - response = json.loads(response) - pkhash = response.get('key', response.get('keys')) - data = {'pkhash': pkhash} - except json.decoder.JSONDecodeError: - st = status.HTTP_400_BAD_REQUEST - data = {'message': response} + data = {'message': response} return data, st From ec7e72366af93b528576f69627ddad9cf198f596 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 23 May 2019 15:40:42 +0200 Subject: [PATCH 027/457] Remove useless function in prod settings. --- substrabac/substrabac/settings/prod.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index f8421c582..7d8fb8de8 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -16,18 +16,6 @@ DEBUG = False - - -@contextlib.contextmanager -def get_event_loop(): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - try: - yield loop - finally: - loop.close() - - USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') os.environ['HTTPS'] = "on" From 09e0e937280a31de8c66fa553bb698ba47c33272 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 23 May 2019 16:00:27 +0200 Subject: [PATCH 028/457] Update requirements.txt of fabric-sdk-py --- substrabac/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index f09240373..749a3e07e 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,4 +26,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -git+https://github.com/hyperledger/fabric-sdk-py.git@282b4f0d19409a4686a34f5ace603e7226ef5dd3 +fabric-sdk-py==0.8.0 From c6060159c0abcb41e4f19a56b6921eff55af2f57 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 3 Jun 2019 12:11:03 +0200 Subject: [PATCH 029/457] Fix data sample update test --- substrabac/substrapp/tests/tests_query.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index 0a604e695..78b1baa12 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -863,7 +863,7 @@ def test_bulk_update_data(self): data = { 'data_manager_keys': [datamanager.pkhash, datamanager2.pkhash], - 'data_keys': [d.pkhash], + 'data_sample_keys': [d.pkhash], } extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', From a183c48533a8897f844a0d44d45f8de50340fb93 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 10:21:11 +0200 Subject: [PATCH 030/457] Remove unused docker components. --- docker/README.md | 10 --- docker/docker-compose.yaml | 150 ------------------------------------- docker/start.py | 3 - docker/stop.py | 8 +- 4 files changed, 2 insertions(+), 169 deletions(-) delete mode 100644 docker/README.md delete mode 100644 docker/docker-compose.yaml diff --git a/docker/README.md b/docker/README.md deleted file mode 100644 index a39478f98..000000000 --- a/docker/README.md +++ /dev/null @@ -1,10 +0,0 @@ -First build all the images with the `build-docker-images.sh` in the root directory of this repository - - -Use classical docker-compose command in the root directory of this repository with `-f` and ` --project-directory` options. - -For instance, `up -d`: - -``` docker-compose -f docker/docker-compose.yaml --project-directory . up -d ``` - -To test from scratch, you may have to remove the `/substra/backup/postgres-data/` directory in the root directory of this repository. diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml deleted file mode 100644 index c37b59666..000000000 --- a/docker/docker-compose.yaml +++ /dev/null @@ -1,150 +0,0 @@ -version: '2.3' - -networks: - default: - external: - name: net_substra - -services: - - substrabacowkin: - container_name: owkin.substrabac - hostname: substrabacowkin - image: substra/substrabac - command: /bin/bash -c "while ! { nc -z postgresql 5432 2>&1; }; do sleep 1; done; python manage.py migrate --settings=substrabac.settings.dev; python3 manage.py runserver 0.0.0.0:8000" - volumes: - - /substra:/substra - - /substra/data/orgs/owkin/user/msp:/opt/gopath/src/github.com/hyperledger/fabric/peer/msp - links: - - postgresql - - rabbit - ports: - - "8000:8000" - depends_on: - - postgresql - - rabbit - environment: - - DATABASE_HOST=postgresql - - DJANGO_SETTINGS_MODULE=substrabac.settings.dev - - PYTHONUNBUFFERED=1 - - FABRIC_CFG_PATH=/substra/conf/owkin/peer1/ - - substrabacchunantes: - container_name: chunantes.substrabac - hostname: substrabacchunantes - image: substra/substrabac - command: /bin/bash -c "while ! { nc -z postgresql 5432 2>&1; }; do sleep 1; done; python manage.py migrate --settings=substrabac.settings.dev; python3 manage.py runserver 0.0.0.0:8001" - volumes: - - /substra:/substra - - /substra/data/orgs/chu-nantes/user/msp:/opt/gopath/src/github.com/hyperledger/fabric/peer/msp - links: - - postgresql - - rabbit - ports: - - "8001:8001" - depends_on: - - postgresql - - rabbit - environment: - - DATABASE_HOST=postgresql - - DJANGO_SETTINGS_MODULE=substrabac.settings.dev - - PYTHONUNBUFFERED=1 - - FABRIC_CFG_PATH=/substra/conf/chu-nantes/peer1/ - - # Celery worker - - celerybeat: - container_name: celerybeat - hostname: celerybeat - image: substra/celerybeat - command: /bin/bash -c "while ! { nc -z rabbit 5672 2>&1; }; do sleep 1; done; celery -A substrabac beat -l info -b rabbit" - volumes: - - /substra:/substra - links: - - rabbit - depends_on: - - rabbit - environment: - - PYTHONUNBUFFERED=1 - - DJANGO_SETTINGS_MODULE=substrabac.settings.common - - worker_owkin: - container_name: worker_owkin - hostname: worker_owkin - # runtime: nvidia - image: substra/celeryworker - command: /bin/bash -c "while ! { nc -z rabbit 5672 2>&1; }; do sleep 1; done; celery -A substrabac worker -l info -n owkin -Q owkin,celery -b rabbit" - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - /substra:/substra - - /substra/data/orgs/owkin/user/msp:/opt/gopath/src/github.com/hyperledger/fabric/peer/msp - links: - - rabbit - - substrabacowkin - depends_on: - - rabbit - environment: - - ORG=owkin - - PYTHONUNBUFFERED=1 - - DATABASE_HOST=postgresql - - DJANGO_SETTINGS_MODULE=substrabac.settings.dev - - FABRIC_CFG_PATH=/substra/conf/owkin/peer1/ - - worker_chunantes: - container_name: worker_chunantes - hostname: worker_chunantes - # runtime: nvidia - image: substra/celeryworker - command: /bin/bash -c "while ! { nc -z rabbit 5672 2>&1; }; do sleep 1; done; celery -A substrabac worker -l info -n chunantes -Q chu-nantes,celery -b rabbit" - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - /substra:/substra - - /substra/data/orgs/chu-nantes/user/msp:/opt/gopath/src/github.com/hyperledger/fabric/peer/msp - links: - - rabbit - depends_on: - - rabbit - - substrabacchunantes - environment: - - ORG=chu-nantes - - PYTHONUNBUFFERED=1 - - DATABASE_HOST=postgresql - - DJANGO_SETTINGS_MODULE=substrabac.settings.dev - - FABRIC_CFG_PATH=/substra/conf/chu-nantes/peer1/ - - - rabbit: - container_name: rabbit - hostname: rabbit - image: rabbitmq:3 - environment: - - RABBITMQ_DEFAULT_USER=guest - - RABBITMQ_DEFAULT_PASS=guest - - HOSTNAME=rabbitmq - - RABBITMQ_NODENAME=rabbitmq -# ports: -# - "5672:5672" - - postgresql: - container_name: postgresql - hostname: postgresql - image: substra/postgresql - volumes: - - /substra/backup/postgres-data:/var/lib/postgresql/data -# ports: -# - "5432:5432" - environment: - - POSTGRES_USER=postgres - - USER=postgres - - POSTGRES_PASSWORD=postgrespwd - - POSTGRES_DB=substrabac - -# flower: -# container_name: flower -# image: mher/flower -# ports: -# - "5555:5555" -# depends_on: -# - rabbit -# environment: -# - CELERY_BROKER_URL=amqp://rabbit:5672 diff --git a/docker/start.py b/docker/start.py index 958a67d61..74f927dd4 100644 --- a/docker/start.py +++ b/docker/start.py @@ -230,9 +230,6 @@ def stop(docker_compose=None): if docker_compose is not None: call(['docker-compose', '-f', docker_compose['path'], '--project-directory', os.path.join(dir_path, '../'), 'down', '--remove-orphans']) - else: - call(['docker-compose', '-f', os.path.join(dir_path, './docker-compose.yaml'), '--project-directory', - os.path.join(dir_path, '../'), 'down', '--remove-orphans']) def start(conf, launch_settings, no_backup): diff --git a/docker/stop.py b/docker/stop.py index 14df1feb3..269af7c3f 100644 --- a/docker/stop.py +++ b/docker/stop.py @@ -7,15 +7,11 @@ def stop(): print('stopping container') - docker_compose_path = './docker-compose.yaml' - if os.path.exists(os.path.join(dir_path, './docker-compose-dynamic.yaml')): docker_compose_path = './docker-compose-dynamic.yaml' - call(['docker-compose', '-f', os.path.join(dir_path, docker_compose_path), '--project-directory', - os.path.join(dir_path, '../'), 'down', '--remove-orphans']) - - # call(['rm', '-rf', '/substra/backup/postgres-data']) + call(['docker-compose', '-f', os.path.join(dir_path, docker_compose_path), '--project-directory', + os.path.join(dir_path, '../'), 'down', '--remove-orphans']) if __name__ == "__main__": From a5bdad1bb868cb11541d8ce99fb523bccb0d2f6a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 14:26:45 +0200 Subject: [PATCH 031/457] Move fabric-sdk-py tests and experiments to a repo. --- .../fabric-sdk-py-async-events.py | 30 ----- fabric-sdk-py_tests/fabric-sdk-py-discover.py | 88 -------------- .../fabric-sdk-py-mass-enroll.py | 33 ----- .../fabric-sdk-py-query-invoke.py | 113 ------------------ fabric-sdk-py_tests/fabric-sdk-py.py | 67 ----------- .../fabric-sdk-py_affiliation_service.py | 49 -------- .../fabric-sdk-py_certificate_service.py | 63 ---------- .../fabric-sdk-py_identity_service.py | 63 ---------- 8 files changed, 506 deletions(-) delete mode 100644 fabric-sdk-py_tests/fabric-sdk-py-async-events.py delete mode 100644 fabric-sdk-py_tests/fabric-sdk-py-discover.py delete mode 100644 fabric-sdk-py_tests/fabric-sdk-py-mass-enroll.py delete mode 100644 fabric-sdk-py_tests/fabric-sdk-py-query-invoke.py delete mode 100644 fabric-sdk-py_tests/fabric-sdk-py.py delete mode 100644 fabric-sdk-py_tests/fabric-sdk-py_affiliation_service.py delete mode 100644 fabric-sdk-py_tests/fabric-sdk-py_certificate_service.py delete mode 100644 fabric-sdk-py_tests/fabric-sdk-py_identity_service.py diff --git a/fabric-sdk-py_tests/fabric-sdk-py-async-events.py b/fabric-sdk-py_tests/fabric-sdk-py-async-events.py deleted file mode 100644 index b32092b64..000000000 --- a/fabric-sdk-py_tests/fabric-sdk-py-async-events.py +++ /dev/null @@ -1,30 +0,0 @@ -import os -import sys -import asyncio - -from hfc.fabric import Client -from hfc.fabric.block_decoder import FilteredBlockDecoder -from hfc.util.crypto.crypto import ecies - -from hfc.fabric.transaction.tx_context import TXContext -from hfc.fabric.transaction.tx_proposal_request import TXProposalRequest - - -dir_path = os.path.dirname(os.path.realpath(__file__)) - -async def main(): - cli = Client(net_profile=os.path.join(dir_path, '../network.json')) - admin_owkin = cli.get_user('owkin', 'admin') - - cli.new_channel('mychannel') - peer = cli.get_peer('peer1-owkin') - - events = cli.get_events(admin_owkin, peer, 'mychannel', start=0, filtered=True) - - async for v in cli.getEvents(events): - print(v) - - - -asyncio.run(main(), debug=True) - diff --git a/fabric-sdk-py_tests/fabric-sdk-py-discover.py b/fabric-sdk-py_tests/fabric-sdk-py-discover.py deleted file mode 100644 index 0bf3127d5..000000000 --- a/fabric-sdk-py_tests/fabric-sdk-py-discover.py +++ /dev/null @@ -1,88 +0,0 @@ -from hfc.fabric import Client -from hfc.fabric.channel.channel import Channel -from hfc.fabric.block_decoder import decode_fabric_MSP_config, decode_fabric_peers_info, decode_fabric_endpoints -from hfc.fabric.peer import create_peer -from hfc.fabric.user import create_user -from hfc.util.crypto.crypto import ecies -from hfc.util.keyvaluestore import FileKeyValueStore - -import pprint -import glob - -peer_config = {'clientKey': {'path': '/substra/data/orgs/owkin/tls/peer1/cli-client.key'}, - 'clientServer': {'path': '/substra/data/orgs/owkin/tls/peer1/cli-client.crt'}, - 'eventUrl': 'peer1-owkin:7053', - 'grpcOptions': {'grpc.http2.keepalive_time': 15, - 'grpc.ssl_target_name_override': 'peer1-owkin'}, - 'tlsCACerts': { - 'path': '/substra/data/orgs/owkin/ca-cert.pem'}, - 'url': 'peer1-owkin:7051'} - -peer1_owkin = create_peer(endpoint=peer_config['url'], - tls_cacerts=peer_config['tlsCACerts']['path'], - client_key=peer_config['clientKey']['path'], - client_cert=peer_config['clientServer']['path'], - opts=[(k, v) for k, v in peer_config['grpcOptions'].items()]) - -key_path = glob.glob('/substra/data/orgs/owkin/admin/msp/keystore/*')[0] -cert_path = '/substra/data/orgs/owkin/admin/msp/signcerts/cert.pem' - -admin_owkin = create_user(name='admin', - org='owkin', - state_store=FileKeyValueStore('/tmp/kvs/'), - msp_id='owkinMSP', - key_path=key_path, - cert_path=cert_path) - - -client = Client() - -print(client.query_peers(admin_owkin, peer1_owkin)) -print(client.query_peers(admin_owkin, peer1_owkin, channel='mychannel', local=False)) - -client.init_with_discovery(admin_owkin, peer1_owkin, - 'mychannel') - -response = Channel('', '')._discovery(admin_owkin, peer1_owkin, config=False, local=True) - -response = Channel('mychannel', '')._discovery(admin_owkin, peer1_owkin, config=True, local=False) - - -def process_config_result(config_result): - - results = {'msps': {}, - 'orderers': {}} - - for msp_name in config_result.msps: - results['msps'][msp_name] = decode_fabric_MSP_config(config_result.msps[msp_name].SerializeToString()) - - for orderer_msp in config_result.orderers: - results['orderers'][orderer_msp] = decode_fabric_endpoints(config_result.orderers[orderer_msp].endpoint) - - return results - - -def process_cc_query_res(cc_query_res): - pass - - -def process_members(members): - peers = [] - for msp_name in members.peers_by_org: - peers.append(decode_fabric_peers_info(members.peers_by_org[msp_name].peers)) - return peers - - -results = {} -for res in response.results: - # print(res) - print('-' * 100) - print('Error') - pprint.pprint(res.error) - print('-' * 50) - print('Config result') - pprint.pprint(process_config_result(res.config_result), indent=2) - # print(f'Chaincode Query result : {res.cc_query_res}') - print('Members') - pprint.pprint(process_members(res.members), indent=2) - print('#' * 100) diff --git a/fabric-sdk-py_tests/fabric-sdk-py-mass-enroll.py b/fabric-sdk-py_tests/fabric-sdk-py-mass-enroll.py deleted file mode 100644 index c9810b2e4..000000000 --- a/fabric-sdk-py_tests/fabric-sdk-py-mass-enroll.py +++ /dev/null @@ -1,33 +0,0 @@ -import random -import string - -from hfc.fabric_ca.caservice import ca_service - -cacli = ca_service(target="https://rca-owkin:7054", - ca_certs_path='/substra/data/orgs/owkin/ca-cert.pem', - ca_name='rca-owkin') - -print('Will try to enroll admin') -try: - admin = cacli.enroll('admin-owkin', 'admin-owkinpw') -except ValueError as e: - print(e) -else: - print('Admin successfully enrolled') - with open('/substra/data/orgs/owkin/ca-cert.pem', 'rb') as f: - cert = f.read() - - if cacli._ca_client.get_cainfo() == cert: - print('Distant ca cert is the same as in local filesystem') - - for x in range(0, 200): - username = ''.join( - [random.choice(string.ascii_letters + string.digits) for n in - range(9)]) - print(f'Will try to register user {username}') - try: - secret = admin.register(username, role='client', affiliation='owkin.nantes') - except ValueError as e: - print(e) - else: - print(f'Correctly registered user {username} with secret {secret}') diff --git a/fabric-sdk-py_tests/fabric-sdk-py-query-invoke.py b/fabric-sdk-py_tests/fabric-sdk-py-query-invoke.py deleted file mode 100644 index 5bef66917..000000000 --- a/fabric-sdk-py_tests/fabric-sdk-py-query-invoke.py +++ /dev/null @@ -1,113 +0,0 @@ -import os -import asyncio -import subprocess - -from hfc.fabric import Client - -from substrabac.settings.common import PROJECT_ROOT - -dir_path = os.path.dirname(os.path.realpath(__file__)) - -cli = Client(net_profile=os.path.join(dir_path, '../network.json')) -admin_owkin = cli.get_user('owkin', 'admin') - -cli.new_channel('mychannel') - -loop = asyncio.get_event_loop() - -from hfc.fabric_ca.caservice import ca_service - -cacli = ca_service(target="https://rca-owkin:7054", - ca_certs_path='/substra/data/orgs/owkin/ca-cert.pem', - ca_name='rca-owkin') - -print('Will try to enroll admin') -try: - admin = cacli.enroll('admin-owkin', 'admin-owkinpw') -except ValueError as e: - print(e) -except Exception as e: - print(e) -else: - print('Admin enrolled') - - os.environ['FABRIC_CFG_PATH'] = '/substra/conf/owkin/peer1' - os.environ['CORE_PEER_MSPCONFIGPATH'] = '/substra/data/orgs/owkin/user/msp' - - output = subprocess.run([os.path.join(PROJECT_ROOT, '../bin/peer'), - '--logging-level', 'DEBUG', - 'chaincode', 'query', - '-C', 'mychannel', - '-n', 'mycc', - #'--tls', - #'--clientauth', - '-c', '{"Args":["queryDataManagers"]}' - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - data = output.stdout.decode('utf-8') - if data: - print(data) - else: - try: - msg = output.stderr.decode('utf-8').split('Error')[2].split('\n')[0] - data = {'message': msg} - except: - msg = output.stderr.decode('utf-8') - data = {'message': msg} - finally: - print(data) - - response = loop.run_until_complete(cli.chaincode_query( - requestor=admin_owkin, - channel_name='mychannel', - peers=['peer1-owkin'], - args=[], - cc_name='mycc', - cc_version='1.0', - fcn='queryDataManagers' - )) - print(response) - - response = loop.run_until_complete(cli.query_installed_chaincodes( - requestor=admin_owkin, - peers=['peer1-owkin'] - )) - print(response) - - response = loop.run_until_complete(cli.query_channels( - requestor=admin_owkin, - peers=['peer1-owkin'] - )) - print(response) - - response = loop.run_until_complete(cli.query_info( - requestor=admin_owkin, - channel_name='mychannel', - peers=['peer1-owkin'] - )) - print(response) - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - response = loop.run_until_complete(cli.chaincode_invoke( - requestor=admin_owkin, - channel_name='mychannel', - peers=['peer1-owkin'], - args=['ISIC 2018', - '59300f1fec4f5cdd3a236c7260ed72bdd24691efdec63b7910ea84136123cecd', - 'http://chunantes.substrabac:8001/media/data_managers/59300f1fec4f5cdd3a236c7260ed72bdd24691efdec63b7910ea84136123cecd/opener.py', - 'Images', - '59300f1fec4f5cdd3a236c7260ed72bdd24691efdec63b7910ea84136123cecd', - 'http://chunantes.substrabac:8001/media/data_managers/59300f1fec4f5cdd3a236c7260ed72bdd24691efdec63b7910ea84136123cecd/description.md', - '', - 'all' - ], - cc_name='mycc', - cc_version='1.0', - fcn='registerDataManager', - wait_for_event=True, - wait_for_event_timeout=5 - )) - print(response) diff --git a/fabric-sdk-py_tests/fabric-sdk-py.py b/fabric-sdk-py_tests/fabric-sdk-py.py deleted file mode 100644 index 1e8030e89..000000000 --- a/fabric-sdk-py_tests/fabric-sdk-py.py +++ /dev/null @@ -1,67 +0,0 @@ -import random -import string - -from hfc.fabric_ca.caservice import ca_service - -cacli = ca_service(target="https://rca-owkin:7054", - ca_certs_path='/substra/data/orgs/owkin/ca-cert.pem', - ca_name='rca-owkin') - -print('Will try to enroll admin') -try: - admin = cacli.enroll('admin-owkin', 'admin-owkinpw') -except ValueError as e: - print(e) -else: - print('Admin successfully enrolled') - with open('/substra/data/orgs/owkin/ca-cert.pem', 'rb') as f: - cert = f.read() - - if cacli._ca_client.get_cainfo() == cert: - print('Distant ca cert is the same as in local filesystem') - - username = ''.join( - [random.choice(string.ascii_letters + string.digits) for n in - range(9)]) - print(f'Will try to register user {username}') - try: - secret = admin.register(username) - except ValueError as e: - print(e) - else: - print(f'Correctly registered user {username} with secret {secret}') - - print( - f'Will try to enroll new registered user {username} with secret {secret}') - try: - User = cacli.enroll(username, secret) - except ValueError as e: - print(e) - else: - print(f'User {username} successfully enrolled') - - # reenroll - User = cacli.reenroll(User) - - print( - f'Will try to revoke new registered user {username}') - try: - RevokedCerts, CRL = admin.revoke(username, reason='unspecified') - except ValueError as e: - print(e) - else: - print(f'User {username} successfully revoked') - - print('Will try to enroll bootstrap admin') - try: - bootstrap_admin = cacli.enroll('admin', 'adminpw') - except ValueError as e: - print(e) - else: - try: - newCRL = bootstrap_admin.generateCRL() - except Exception as e: - print('Failed to generate CRL %s', str(e)) - else: - print(newCRL) - diff --git a/fabric-sdk-py_tests/fabric-sdk-py_affiliation_service.py b/fabric-sdk-py_tests/fabric-sdk-py_affiliation_service.py deleted file mode 100644 index 7ef66c4c9..000000000 --- a/fabric-sdk-py_tests/fabric-sdk-py_affiliation_service.py +++ /dev/null @@ -1,49 +0,0 @@ -from pprint import pprint - -from hfc.fabric_ca.caservice import ca_service - -cacli = ca_service(target="https://rca-owkin:7054", - ca_certs_path='/substra/data/orgs/owkin/ca-cert.pem', - ca_name='rca-owkin') - -print('Will try to enroll bootstrap admin') -try: - bootstrap_admin = cacli.enroll('admin', 'adminpw') -except ValueError as e: - print(e) -else: - print('Admin successfully enrolled') - - print('Create affiliation Service') - - affiliationService = cacli.newAffiliationService() - - affiliation = 'department3' - - print(f'Will try to create affiliation {affiliation}') - res = affiliationService.create(bootstrap_admin, affiliation) - pprint(res) - - print(f'Will try to get affiliation {affiliation}') - res = affiliationService.getOne(affiliation, bootstrap_admin) - pprint(res) - - print('Will try to get all affiliations') - res = affiliationService.getAll(bootstrap_admin) - print('number of affiliations: ', len(res['result']['affiliations'])) - - print(f'Will try to update affiliation {affiliation} with name=\'department3bis\'') - res = affiliationService.update(affiliation, bootstrap_admin, name='department3bis') - pprint(res) - - print(f'Will try to get affiliation {affiliation} to see changes') - res = affiliationService.getOne(affiliation, bootstrap_admin) - pprint(res) - - print(f'Will try to delete affiliation {affiliation}') - res = affiliationService.delete('department3bis', bootstrap_admin) - pprint(res) - - print(f'Will try to get deleted affiliation {affiliation}') - res = affiliationService.getOne(affiliation, bootstrap_admin) - pprint(res) diff --git a/fabric-sdk-py_tests/fabric-sdk-py_certificate_service.py b/fabric-sdk-py_tests/fabric-sdk-py_certificate_service.py deleted file mode 100644 index f51571efd..000000000 --- a/fabric-sdk-py_tests/fabric-sdk-py_certificate_service.py +++ /dev/null @@ -1,63 +0,0 @@ -import random -import string - -from hfc.fabric_ca.caservice import ca_service - -cacli = ca_service(target="https://rca-owkin:7054", - ca_certs_path='/substra/data/orgs/owkin/ca-cert.pem', - ca_name='rca-owkin') - -print('Will try to enroll admin') -try: - bootstrap_admin = cacli.enroll('admin', 'adminpw') -except ValueError as e: - print(e) -else: - print('Admin successfully enrolled') - - print('Create affiliation Service') - - certificateService = cacli.newCertificateService() - - print(f'Will try to get certificates') - res = certificateService.getCertificates(bootstrap_admin) - print(len(res['result'])) - - print(f'Will try to get certificates admin') - res = certificateService.getCertificates(bootstrap_admin, 'admin') - print(len(res['result'])) - - print('Will try to enroll admin') - try: - admin = cacli.enroll('admin-owkin', 'admin-owkinpw') - except ValueError as e: - print(e) - else: - print('Admin successfully enrolled') - - print('Create identity Service') - - identityService = cacli.newIdentityService() - - username = ''.join( - [random.choice(string.ascii_letters + string.digits) for n in - range(9)]) - print(f'Will try to register user {username}') - secret = identityService.create(admin, username) - print(f'Correctly registered user {username} with secret {secret}') - - print(f'Will try to get certificates {username} from admin') - res = certificateService.getCertificates(admin, username) - print(len(res['result'])) - - print( - f'Will try to enroll user {username} with original password {secret}') - try: - user = cacli.enroll(username, secret) - except: - print('User cannot enroll with old password') - else: - - print(f'Will try to get certificates {username} from user') - res = certificateService.getCertificates(user) - print(res) diff --git a/fabric-sdk-py_tests/fabric-sdk-py_identity_service.py b/fabric-sdk-py_tests/fabric-sdk-py_identity_service.py deleted file mode 100644 index 6083175a6..000000000 --- a/fabric-sdk-py_tests/fabric-sdk-py_identity_service.py +++ /dev/null @@ -1,63 +0,0 @@ -import random -import string -from pprint import pprint - -from hfc.fabric_ca.caservice import ca_service - -cacli = ca_service(target="https://rca-owkin:7054", - ca_certs_path='/substra/data/orgs/owkin/ca-cert.pem', - ca_name='rca-owkin') - -print('Will try to enroll admin') -try: - admin = cacli.enroll('admin-owkin', 'admin-owkinpw') -except ValueError as e: - print(e) -else: - print('Admin successfully enrolled') - - print('Create identity Service') - - identityService = cacli.newIdentityService() - - username = ''.join( - [random.choice(string.ascii_letters + string.digits) for n in - range(9)]) - print(f'Will try to register user {username}') - secret = identityService.create(admin, username) - print(f'Correctly registered user {username} with secret {secret}') - - print(f'Will try to get user {username}') - res = identityService.getOne(username, admin) - pprint(res) - print('Will try to get all users') - res = identityService.getAll(admin) - print('number of users: ', len(res['result']['identities'])) - - print(f'Will try to update user {username} with maxEnrollments=3, affiliation=\'.\' and secret=bar') - res = identityService.update(username, admin, maxEnrollments=3, - affiliation='.', enrollmentSecret='bar') - pprint(res) - - print(f'Will try to enroll user {username} with original password {secret}') - try: - cacli.enroll(username, secret) - except: - print('User cannot enroll with old password') - else: - print('/!\ User password update did not work correctly as he is able to enroll with old password') - finally: - print(f'Will try to enroll user {username} with modified password bar') - cacli.enroll(username, 'bar') - - print(f'Will try to get user {username} to see changes') - res = identityService.getOne(username, admin) - pprint(res) - - print(f'Will try to delete user {username}') - res = identityService.delete(username, admin) - pprint(res) - - print(f'Will try to get deleted user {username}') - res = identityService.getOne(username, admin) - pprint(res) From 92131884c140a1f8602c87ce520f8188ff2d7408 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 14:41:51 +0200 Subject: [PATCH 032/457] Move and clean fixtures. --- .../chunantes/algos/algo0/algo.tar.gz | Bin .../chunantes/algos/algo0/algo.zip | Bin .../chunantes/algos/algo0/description.md | 0 .../chunantes/algos/algo0/description.md~ | 0 .../chunantes/algos/algo1/algo.tar.gz | Bin .../chunantes/algos/algo1/description.md | 0 .../chunantes/algos/algo2/algo.zip | Bin .../chunantes/algos/algo3/algo.tar.gz | Bin .../chunantes/algos/algo3/description.md | 0 .../chunantes/algos/algo4/algo.tar.gz | Bin .../chunantes/algos/algo4/algo.zip | Bin .../chunantes/algos/algo4/description.md | 0 .../chunantes/algos/algo4/description.md~ | 0 .../datamanagers/datamanager0/description.md | 0 .../datamanagers/datamanager0/opener.py | 0 .../datasamples/datasample0/0024899.tar.gz | Bin .../datasamples/datasample0/0024899.zip | Bin .../datasamples/datasample1/0024700.tar.gz | Bin .../datasamples/datasample1/0024700.zip | Bin .../chunantes/datasamples/train/0024306.zip | Bin .../datasamples/train/0024306/IMG_0024306.jpg | Bin .../train/0024306/LABEL_0024306.csv | 0 .../chunantes/datasamples/train/0024307.zip | Bin .../datasamples/train/0024307/IMG_0024307.jpg | Bin .../train/0024307/LABEL_0024307.csv | 0 .../datasamples/train/0024308/IMG_0024308.jpg | Bin .../train/0024308/LABEL_0024308.csv | 0 .../chunantes/datasamples/train/0024310.zip | Bin .../chunantes/models/model0/model | Bin .../objectives/objective0/description.md | 0 .../objectives/objective0/metrics.py | 0 .../fixtures => fixtures}/dataset.json | 0 .../fixtures => fixtures}/isic_2018.py | 0 .../fixtures => fixtures}/objective.json | 0 .../datamanagers/datamanager0/description.md | 0 .../owkin/datamanagers/datamanager0/opener.py | 0 .../datasamples/datasample0/0024315.tar.gz | Bin .../datasamples/datasample1/0024701.tar.gz | Bin .../datasamples/datasample2/0024318.tar.gz | Bin .../datasamples/datasample3/0024317.tar.gz | Bin .../datasamples/datasample4/0024900.tar.gz | Bin .../owkin/datasamples/datasample4/0024900.zip | Bin .../datasamples/datasample5/0024316.tar.gz | Bin .../owkin/datasamples/test/0024900.zip | Bin .../owkin/datasamples/test/0024901.zip | Bin .../owkin/datasamples/test/0024902.zip | Bin .../owkin/datasamples/test/0024903.zip | Bin .../owkin/datasamples/test/0024904.zip | Bin .../owkin/datasamples/test/0024905.zip | Bin .../objectives/objective0/description.md | 0 .../owkin/objectives/objective0/metrics.py | 0 substrabac/populate.py => populate.py | 0 substrabac/substrapp/fixtures/__init__.py | 0 substrabac/substrapp/fixtures/model.py | 202 ------------------ substrabac/substrapp/tests/common.py | 8 +- .../tests/tests_bulkcreatedatasample.py | 38 ++-- .../tests/tests_createdatamanager.py | 16 +- .../substrapp/tests/tests_createobjective.py | 12 +- substrabac/substrapp/tests/tests_model.py | 2 +- substrabac/substrapp/tests/tests_query.py | 2 +- substrabac/substrapp/tests/tests_views.py | 74 +++---- 61 files changed, 76 insertions(+), 278 deletions(-) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo0/algo.tar.gz (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo0/algo.zip (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo0/description.md (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo0/description.md~ (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo1/algo.tar.gz (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo1/description.md (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo2/algo.zip (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo3/algo.tar.gz (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo3/description.md (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo4/algo.tar.gz (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo4/algo.zip (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo4/description.md (100%) rename {substrabac/fixtures => fixtures}/chunantes/algos/algo4/description.md~ (100%) rename {substrabac/fixtures => fixtures}/chunantes/datamanagers/datamanager0/description.md (100%) rename {substrabac/fixtures => fixtures}/chunantes/datamanagers/datamanager0/opener.py (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/datasample0/0024899.tar.gz (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/datasample0/0024899.zip (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/datasample1/0024700.tar.gz (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/datasample1/0024700.zip (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024306.zip (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024306/IMG_0024306.jpg (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024306/LABEL_0024306.csv (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024307.zip (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024307/IMG_0024307.jpg (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024307/LABEL_0024307.csv (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024308/IMG_0024308.jpg (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024308/LABEL_0024308.csv (100%) rename {substrabac/fixtures => fixtures}/chunantes/datasamples/train/0024310.zip (100%) rename {substrabac/fixtures => fixtures}/chunantes/models/model0/model (100%) rename {substrabac/fixtures => fixtures}/chunantes/objectives/objective0/description.md (100%) rename {substrabac/fixtures => fixtures}/chunantes/objectives/objective0/metrics.py (100%) rename {substrabac/fixtures => fixtures}/dataset.json (100%) rename {substrabac/fixtures => fixtures}/isic_2018.py (100%) rename {substrabac/fixtures => fixtures}/objective.json (100%) rename {substrabac/fixtures => fixtures}/owkin/datamanagers/datamanager0/description.md (100%) rename {substrabac/fixtures => fixtures}/owkin/datamanagers/datamanager0/opener.py (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/datasample0/0024315.tar.gz (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/datasample1/0024701.tar.gz (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/datasample2/0024318.tar.gz (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/datasample3/0024317.tar.gz (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/datasample4/0024900.tar.gz (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/datasample4/0024900.zip (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/datasample5/0024316.tar.gz (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/test/0024900.zip (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/test/0024901.zip (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/test/0024902.zip (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/test/0024903.zip (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/test/0024904.zip (100%) rename {substrabac/fixtures => fixtures}/owkin/datasamples/test/0024905.zip (100%) rename {substrabac/fixtures => fixtures}/owkin/objectives/objective0/description.md (100%) rename {substrabac/fixtures => fixtures}/owkin/objectives/objective0/metrics.py (100%) rename substrabac/populate.py => populate.py (100%) delete mode 100644 substrabac/substrapp/fixtures/__init__.py delete mode 100644 substrabac/substrapp/fixtures/model.py diff --git a/substrabac/fixtures/chunantes/algos/algo0/algo.tar.gz b/fixtures/chunantes/algos/algo0/algo.tar.gz similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo0/algo.tar.gz rename to fixtures/chunantes/algos/algo0/algo.tar.gz diff --git a/substrabac/fixtures/chunantes/algos/algo0/algo.zip b/fixtures/chunantes/algos/algo0/algo.zip similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo0/algo.zip rename to fixtures/chunantes/algos/algo0/algo.zip diff --git a/substrabac/fixtures/chunantes/algos/algo0/description.md b/fixtures/chunantes/algos/algo0/description.md similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo0/description.md rename to fixtures/chunantes/algos/algo0/description.md diff --git a/substrabac/fixtures/chunantes/algos/algo0/description.md~ b/fixtures/chunantes/algos/algo0/description.md~ similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo0/description.md~ rename to fixtures/chunantes/algos/algo0/description.md~ diff --git a/substrabac/fixtures/chunantes/algos/algo1/algo.tar.gz b/fixtures/chunantes/algos/algo1/algo.tar.gz similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo1/algo.tar.gz rename to fixtures/chunantes/algos/algo1/algo.tar.gz diff --git a/substrabac/fixtures/chunantes/algos/algo1/description.md b/fixtures/chunantes/algos/algo1/description.md similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo1/description.md rename to fixtures/chunantes/algos/algo1/description.md diff --git a/substrabac/fixtures/chunantes/algos/algo2/algo.zip b/fixtures/chunantes/algos/algo2/algo.zip similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo2/algo.zip rename to fixtures/chunantes/algos/algo2/algo.zip diff --git a/substrabac/fixtures/chunantes/algos/algo3/algo.tar.gz b/fixtures/chunantes/algos/algo3/algo.tar.gz similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo3/algo.tar.gz rename to fixtures/chunantes/algos/algo3/algo.tar.gz diff --git a/substrabac/fixtures/chunantes/algos/algo3/description.md b/fixtures/chunantes/algos/algo3/description.md similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo3/description.md rename to fixtures/chunantes/algos/algo3/description.md diff --git a/substrabac/fixtures/chunantes/algos/algo4/algo.tar.gz b/fixtures/chunantes/algos/algo4/algo.tar.gz similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo4/algo.tar.gz rename to fixtures/chunantes/algos/algo4/algo.tar.gz diff --git a/substrabac/fixtures/chunantes/algos/algo4/algo.zip b/fixtures/chunantes/algos/algo4/algo.zip similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo4/algo.zip rename to fixtures/chunantes/algos/algo4/algo.zip diff --git a/substrabac/fixtures/chunantes/algos/algo4/description.md b/fixtures/chunantes/algos/algo4/description.md similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo4/description.md rename to fixtures/chunantes/algos/algo4/description.md diff --git a/substrabac/fixtures/chunantes/algos/algo4/description.md~ b/fixtures/chunantes/algos/algo4/description.md~ similarity index 100% rename from substrabac/fixtures/chunantes/algos/algo4/description.md~ rename to fixtures/chunantes/algos/algo4/description.md~ diff --git a/substrabac/fixtures/chunantes/datamanagers/datamanager0/description.md b/fixtures/chunantes/datamanagers/datamanager0/description.md similarity index 100% rename from substrabac/fixtures/chunantes/datamanagers/datamanager0/description.md rename to fixtures/chunantes/datamanagers/datamanager0/description.md diff --git a/substrabac/fixtures/chunantes/datamanagers/datamanager0/opener.py b/fixtures/chunantes/datamanagers/datamanager0/opener.py similarity index 100% rename from substrabac/fixtures/chunantes/datamanagers/datamanager0/opener.py rename to fixtures/chunantes/datamanagers/datamanager0/opener.py diff --git a/substrabac/fixtures/chunantes/datasamples/datasample0/0024899.tar.gz b/fixtures/chunantes/datasamples/datasample0/0024899.tar.gz similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/datasample0/0024899.tar.gz rename to fixtures/chunantes/datasamples/datasample0/0024899.tar.gz diff --git a/substrabac/fixtures/chunantes/datasamples/datasample0/0024899.zip b/fixtures/chunantes/datasamples/datasample0/0024899.zip similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/datasample0/0024899.zip rename to fixtures/chunantes/datasamples/datasample0/0024899.zip diff --git a/substrabac/fixtures/chunantes/datasamples/datasample1/0024700.tar.gz b/fixtures/chunantes/datasamples/datasample1/0024700.tar.gz similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/datasample1/0024700.tar.gz rename to fixtures/chunantes/datasamples/datasample1/0024700.tar.gz diff --git a/substrabac/fixtures/chunantes/datasamples/datasample1/0024700.zip b/fixtures/chunantes/datasamples/datasample1/0024700.zip similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/datasample1/0024700.zip rename to fixtures/chunantes/datasamples/datasample1/0024700.zip diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024306.zip b/fixtures/chunantes/datasamples/train/0024306.zip similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024306.zip rename to fixtures/chunantes/datasamples/train/0024306.zip diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024306/IMG_0024306.jpg b/fixtures/chunantes/datasamples/train/0024306/IMG_0024306.jpg similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024306/IMG_0024306.jpg rename to fixtures/chunantes/datasamples/train/0024306/IMG_0024306.jpg diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024306/LABEL_0024306.csv b/fixtures/chunantes/datasamples/train/0024306/LABEL_0024306.csv similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024306/LABEL_0024306.csv rename to fixtures/chunantes/datasamples/train/0024306/LABEL_0024306.csv diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024307.zip b/fixtures/chunantes/datasamples/train/0024307.zip similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024307.zip rename to fixtures/chunantes/datasamples/train/0024307.zip diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024307/IMG_0024307.jpg b/fixtures/chunantes/datasamples/train/0024307/IMG_0024307.jpg similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024307/IMG_0024307.jpg rename to fixtures/chunantes/datasamples/train/0024307/IMG_0024307.jpg diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024307/LABEL_0024307.csv b/fixtures/chunantes/datasamples/train/0024307/LABEL_0024307.csv similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024307/LABEL_0024307.csv rename to fixtures/chunantes/datasamples/train/0024307/LABEL_0024307.csv diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024308/IMG_0024308.jpg b/fixtures/chunantes/datasamples/train/0024308/IMG_0024308.jpg similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024308/IMG_0024308.jpg rename to fixtures/chunantes/datasamples/train/0024308/IMG_0024308.jpg diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024308/LABEL_0024308.csv b/fixtures/chunantes/datasamples/train/0024308/LABEL_0024308.csv similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024308/LABEL_0024308.csv rename to fixtures/chunantes/datasamples/train/0024308/LABEL_0024308.csv diff --git a/substrabac/fixtures/chunantes/datasamples/train/0024310.zip b/fixtures/chunantes/datasamples/train/0024310.zip similarity index 100% rename from substrabac/fixtures/chunantes/datasamples/train/0024310.zip rename to fixtures/chunantes/datasamples/train/0024310.zip diff --git a/substrabac/fixtures/chunantes/models/model0/model b/fixtures/chunantes/models/model0/model similarity index 100% rename from substrabac/fixtures/chunantes/models/model0/model rename to fixtures/chunantes/models/model0/model diff --git a/substrabac/fixtures/chunantes/objectives/objective0/description.md b/fixtures/chunantes/objectives/objective0/description.md similarity index 100% rename from substrabac/fixtures/chunantes/objectives/objective0/description.md rename to fixtures/chunantes/objectives/objective0/description.md diff --git a/substrabac/fixtures/chunantes/objectives/objective0/metrics.py b/fixtures/chunantes/objectives/objective0/metrics.py similarity index 100% rename from substrabac/fixtures/chunantes/objectives/objective0/metrics.py rename to fixtures/chunantes/objectives/objective0/metrics.py diff --git a/substrabac/fixtures/dataset.json b/fixtures/dataset.json similarity index 100% rename from substrabac/fixtures/dataset.json rename to fixtures/dataset.json diff --git a/substrabac/fixtures/isic_2018.py b/fixtures/isic_2018.py similarity index 100% rename from substrabac/fixtures/isic_2018.py rename to fixtures/isic_2018.py diff --git a/substrabac/fixtures/objective.json b/fixtures/objective.json similarity index 100% rename from substrabac/fixtures/objective.json rename to fixtures/objective.json diff --git a/substrabac/fixtures/owkin/datamanagers/datamanager0/description.md b/fixtures/owkin/datamanagers/datamanager0/description.md similarity index 100% rename from substrabac/fixtures/owkin/datamanagers/datamanager0/description.md rename to fixtures/owkin/datamanagers/datamanager0/description.md diff --git a/substrabac/fixtures/owkin/datamanagers/datamanager0/opener.py b/fixtures/owkin/datamanagers/datamanager0/opener.py similarity index 100% rename from substrabac/fixtures/owkin/datamanagers/datamanager0/opener.py rename to fixtures/owkin/datamanagers/datamanager0/opener.py diff --git a/substrabac/fixtures/owkin/datasamples/datasample0/0024315.tar.gz b/fixtures/owkin/datasamples/datasample0/0024315.tar.gz similarity index 100% rename from substrabac/fixtures/owkin/datasamples/datasample0/0024315.tar.gz rename to fixtures/owkin/datasamples/datasample0/0024315.tar.gz diff --git a/substrabac/fixtures/owkin/datasamples/datasample1/0024701.tar.gz b/fixtures/owkin/datasamples/datasample1/0024701.tar.gz similarity index 100% rename from substrabac/fixtures/owkin/datasamples/datasample1/0024701.tar.gz rename to fixtures/owkin/datasamples/datasample1/0024701.tar.gz diff --git a/substrabac/fixtures/owkin/datasamples/datasample2/0024318.tar.gz b/fixtures/owkin/datasamples/datasample2/0024318.tar.gz similarity index 100% rename from substrabac/fixtures/owkin/datasamples/datasample2/0024318.tar.gz rename to fixtures/owkin/datasamples/datasample2/0024318.tar.gz diff --git a/substrabac/fixtures/owkin/datasamples/datasample3/0024317.tar.gz b/fixtures/owkin/datasamples/datasample3/0024317.tar.gz similarity index 100% rename from substrabac/fixtures/owkin/datasamples/datasample3/0024317.tar.gz rename to fixtures/owkin/datasamples/datasample3/0024317.tar.gz diff --git a/substrabac/fixtures/owkin/datasamples/datasample4/0024900.tar.gz b/fixtures/owkin/datasamples/datasample4/0024900.tar.gz similarity index 100% rename from substrabac/fixtures/owkin/datasamples/datasample4/0024900.tar.gz rename to fixtures/owkin/datasamples/datasample4/0024900.tar.gz diff --git a/substrabac/fixtures/owkin/datasamples/datasample4/0024900.zip b/fixtures/owkin/datasamples/datasample4/0024900.zip similarity index 100% rename from substrabac/fixtures/owkin/datasamples/datasample4/0024900.zip rename to fixtures/owkin/datasamples/datasample4/0024900.zip diff --git a/substrabac/fixtures/owkin/datasamples/datasample5/0024316.tar.gz b/fixtures/owkin/datasamples/datasample5/0024316.tar.gz similarity index 100% rename from substrabac/fixtures/owkin/datasamples/datasample5/0024316.tar.gz rename to fixtures/owkin/datasamples/datasample5/0024316.tar.gz diff --git a/substrabac/fixtures/owkin/datasamples/test/0024900.zip b/fixtures/owkin/datasamples/test/0024900.zip similarity index 100% rename from substrabac/fixtures/owkin/datasamples/test/0024900.zip rename to fixtures/owkin/datasamples/test/0024900.zip diff --git a/substrabac/fixtures/owkin/datasamples/test/0024901.zip b/fixtures/owkin/datasamples/test/0024901.zip similarity index 100% rename from substrabac/fixtures/owkin/datasamples/test/0024901.zip rename to fixtures/owkin/datasamples/test/0024901.zip diff --git a/substrabac/fixtures/owkin/datasamples/test/0024902.zip b/fixtures/owkin/datasamples/test/0024902.zip similarity index 100% rename from substrabac/fixtures/owkin/datasamples/test/0024902.zip rename to fixtures/owkin/datasamples/test/0024902.zip diff --git a/substrabac/fixtures/owkin/datasamples/test/0024903.zip b/fixtures/owkin/datasamples/test/0024903.zip similarity index 100% rename from substrabac/fixtures/owkin/datasamples/test/0024903.zip rename to fixtures/owkin/datasamples/test/0024903.zip diff --git a/substrabac/fixtures/owkin/datasamples/test/0024904.zip b/fixtures/owkin/datasamples/test/0024904.zip similarity index 100% rename from substrabac/fixtures/owkin/datasamples/test/0024904.zip rename to fixtures/owkin/datasamples/test/0024904.zip diff --git a/substrabac/fixtures/owkin/datasamples/test/0024905.zip b/fixtures/owkin/datasamples/test/0024905.zip similarity index 100% rename from substrabac/fixtures/owkin/datasamples/test/0024905.zip rename to fixtures/owkin/datasamples/test/0024905.zip diff --git a/substrabac/fixtures/owkin/objectives/objective0/description.md b/fixtures/owkin/objectives/objective0/description.md similarity index 100% rename from substrabac/fixtures/owkin/objectives/objective0/description.md rename to fixtures/owkin/objectives/objective0/description.md diff --git a/substrabac/fixtures/owkin/objectives/objective0/metrics.py b/fixtures/owkin/objectives/objective0/metrics.py similarity index 100% rename from substrabac/fixtures/owkin/objectives/objective0/metrics.py rename to fixtures/owkin/objectives/objective0/metrics.py diff --git a/substrabac/populate.py b/populate.py similarity index 100% rename from substrabac/populate.py rename to populate.py diff --git a/substrabac/substrapp/fixtures/__init__.py b/substrabac/substrapp/fixtures/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/substrabac/substrapp/fixtures/model.py b/substrabac/substrapp/fixtures/model.py deleted file mode 100644 index 293df3c97..000000000 --- a/substrabac/substrapp/fixtures/model.py +++ /dev/null @@ -1,202 +0,0 @@ -fake_models = [ - { - 'algo': { - 'hash': '76fe474d441b03e8416ab37b4950286014fb329e9317126e144342dd0e2ec895', - 'name': 'Neural Network', - 'storageAddress': 'http://chunantes.substrabac:8001/algo/76fe474d441b03e8416ab37b4950286014fb329e9317126e144342dd0e2ec895/file/', - }, - 'objective': { - 'hash': '3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71', - 'metrics': { - 'hash': '750f622262854341bd44f55c1018949e9c119606ef5068bd7d137040a482a756', - 'storageAddress': 'http://chunantes.substrabac:8001/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/', - }, - }, - 'creator': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - 'outModel': { - 'hash': '30060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/30060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'key': '1bb5c8f42315914909c764545ea44e32b04c773468c439c9eb506176670ee6b8', - 'log': 'no error, ah ah ahstill no error, suprah ah ah', - 'permissions': 'all', - 'inModel': { - 'hash': '20060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/20060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'status': 'done', - 'testDataSample': { - 'keys': ['4b5152871b181d10ee774c10458c064c70710f4ba35938f10c0b7aa51f7dc010'], - 'openerHash': 'a8b7c235abb9a93742e336bd76ff7cd8ecc49f612e5cf6ea506dc10f4fd6b6f0', - 'perf': 0.20, - 'worker': '2d76419f4231cf67bdc53f569201322a4822dff152351fb468db013d484fc762', - }, - 'trainDataSample': { - 'keys': ['62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a', - '42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9'], - 'openerHash': '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7', - 'perf': 0.50, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - }, - { - 'algo': { - 'hash': '76fe474d441b03e8416ab37b4950286014fb329e9317126e144342dd0e2ec895', - 'name': 'Neural Network', - 'storageAddress': 'http://chunantes.substrabac:8001/algo/76fe474d441b03e8416ab37b4950286014fb329e9317126e144342dd0e2ec895/file/', - }, - 'objective': { - 'hash': '3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71', - 'metrics': { - 'hash': '750f622262854341bd44f55c1018949e9c119606ef5068bd7d137040a482a756', - 'storageAddress': 'http://chunantes.substrabac:8001/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/', - }, - }, - 'creator': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - 'outModel': { - 'hash': '40060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/40060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'key': '2bb5c8f42315914909c764545ea44e32b04c773468c439c9eb506176670ee6b8', - 'log': 'no error, ah ah ahstill no error, suprah ah ah', - 'permissions': 'all', - 'inModel': { - 'hash': '30060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/30060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'status': 'done', - 'testDataSample': { - 'keys': ['4b5152871b181d10ee774c10458c064c70710f4ba35938f10c0b7aa51f7dc010'], - 'openerHash': 'a8b7c235abb9a93742e336bd76ff7cd8ecc49f612e5cf6ea506dc10f4fd6b6f0', - 'perf': 0.35, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - 'trainDataSample': { - 'keys': ['62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a', - '42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9'], - 'openerHash': '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7', - 'perf': 0.70, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - }, - { - 'algo': { - 'hash': '76fe474d441b03e8416ab37b4950286014fb329e9317126e144342dd0e2ec895', - 'name': 'Neural Network', - 'storageAddress': 'http://chunantes.substrabac:8001/algo/76fe474d441b03e8416ab37b4950286014fb329e9317126e144342dd0e2ec895/file/', - }, - 'objective': { - 'hash': '3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71', - 'metrics': { - 'hash': '750f622262854341bd44f55c1018949e9c119606ef5068bd7d137040a482a756', - 'storageAddress': 'http://chunantes.substrabac:8001/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/', - }, - }, - 'creator': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - 'outModel': { - 'hash': '50060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/50060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'key': '3bb5c8f42315914909c764545ea44e32b04c773468c439c9eb506176670ee6b8', - 'log': 'no error, ah ah ahstill no error, suprah ah ah', - 'permissions': 'all', - 'inModel': { - 'hash': '40060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/40060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'status': 'done', - 'testDataSample': { - 'keys': ['4b5152871b181d10ee774c10458c064c70710f4ba35938f10c0b7aa51f7dc010'], - 'openerHash': 'a8b7c235abb9a93742e336bd76ff7cd8ecc49f612e5cf6ea506dc10f4fd6b6f0', - 'perf': 0.79, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - 'trainDataSample': { - 'keys': ['62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a', - '42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9'], - 'openerHash': '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7', - 'perf': 0.79, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - }, - { - 'algo': { - 'hash': '56a0e2f7e046ee948cf2ab38136f7b5ff131d0c538f8d75a97850d6fc06131df', - 'name': 'Random Forest', - 'storageAddress': 'http://chunantes.substrabac:8001/56a0e2f7e046ee948cf2ab38136f7b5ff131d0c538f8d75a97850d6fc06131df/file/', - }, - 'objective': { - 'hash': '3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71', - 'metrics': { - 'hash': '750f622262854341bd44f55c1018949e9c119606ef5068bd7d137040a482a756', - 'storageAddress': 'http://chunantes.substrabac:8001/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/', - }, - }, - 'creator': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - 'outModel': { - 'hash': '70060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/70060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'key': '4bb5c8f42315914909c764545ea44e32b04c773468c439c9eb506176670ee6b8', - 'log': 'no error, ah ah ahstill no error, suprah ah ah', - 'permissions': 'all', - 'inModel': { - 'hash': '60060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/60060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'status': 'done', - 'testDataSample': { - 'keys': ['4b5152871b181d10ee774c10458c064c70710f4ba35938f10c0b7aa51f7dc010'], - 'openerHash': 'a8b7c235abb9a93742e336bd76ff7cd8ecc49f612e5cf6ea506dc10f4fd6b6f0', - 'perf': 0.12, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - 'trainDataSample': { - 'keys': ['62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a', - '42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9'], - 'openerHash': '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7', - 'perf': 0.79, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - }, - { - 'algo': { - 'hash': '56a0e2f7e046ee948cf2ab38136f7b5ff131d0c538f8d75a97850d6fc06131df', - 'name': 'Random Forest', - 'storageAddress': 'http://chunantes.substrabac:8001/algo/56a0e2f7e046ee948cf2ab38136f7b5ff131d0c538f8d75a97850d6fc06131df/file/', - }, - 'objective': { - 'hash': '3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71', - 'metrics': { - 'hash': '750f622262854341bd44f55c1018949e9c119606ef5068bd7d137040a482a756', - 'storageAddress': 'http://chunantes.substrabac:8001/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/', - }, - }, - 'creator': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - 'outModel': { - 'hash': '80060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/80060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'key': '5bb5c8f42315914909c764545ea44e32b04c773468c439c9eb506176670ee6b8', - 'log': 'no error, ah ah ahstill no error, suprah ah ah', - 'permissions': 'all', - 'inModel': { - 'hash': '70060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568', - 'storageAddress': 'http://chunantes.substrabac:8001/model/70060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568/file/', - }, - 'status': 'done', - 'testDataSample': { - 'keys': ['4b5152871b181d10ee774c10458c064c70710f4ba35938f10c0b7aa51f7dc010'], - 'openerHash': 'a8b7c235abb9a93742e336bd76ff7cd8ecc49f612e5cf6ea506dc10f4fd6b6f0', - 'perf': 0.66, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - 'trainDataSample': { - 'keys': ['62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a', - '42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9'], - 'openerHash': '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7', - 'perf': 0.79, - 'worker': 'a3119c79a173581425cbe6e06c3034ec396ee805b60d9a34feaa3048beb0e4a9', - }, - }, -] diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 2185d35fc..94e97a30c 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -179,7 +179,7 @@ def get_sample_zip_data_sample(): dir_path = os.path.dirname(os.path.realpath(__file__)) file_filename = "file.zip" f = BytesIO(b'foo') - with open(os.path.join(dir_path, '../../fixtures/owkin/datasamples/datasample4/0024900.zip'), 'rb') as zip_file: + with open(os.path.join(dir_path, '../../../fixtures/owkin/datasamples/datasample4/0024900.zip'), 'rb') as zip_file: flength = f.write(zip_file.read()) file = InMemoryUploadedFile(f, None, file_filename, @@ -193,7 +193,7 @@ def get_sample_zip_data_sample_2(): dir_path = os.path.dirname(os.path.realpath(__file__)) file_filename = "file.zip" f = BytesIO(b'foo') - with open(os.path.join(dir_path, '../../fixtures/owkin/datasamples/test/0024901.zip'), 'rb') as zip_file: + with open(os.path.join(dir_path, '../../../fixtures/owkin/datasamples/test/0024901.zip'), 'rb') as zip_file: flength = f.write(zip_file.read()) file = InMemoryUploadedFile(f, None, file_filename, @@ -207,7 +207,7 @@ def get_sample_tar_data_sample(): dir_path = os.path.dirname(os.path.realpath(__file__)) file_filename = "file.tar.gz" f = BytesIO() - with open(os.path.join(dir_path, '../../fixtures/owkin/datasamples/datasample4/0024900.tar.gz'), 'rb') as tar_file: + with open(os.path.join(dir_path, '../../../fixtures/owkin/datasamples/datasample4/0024900.tar.gz'), 'rb') as tar_file: flength = f.write(tar_file.read()) file = InMemoryUploadedFile(f, None, file_filename, @@ -221,7 +221,7 @@ def get_sample_algo(): dir_path = os.path.dirname(os.path.realpath(__file__)) file_filename = "file.tar.gz" f = BytesIO() - with open(os.path.join(dir_path, '../../fixtures/chunantes/algos/algo3/algo.tar.gz'), 'rb') as tar_file: + with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/algo.tar.gz'), 'rb') as tar_file: flength = f.write(tar_file.read()) file = InMemoryUploadedFile(f, None, file_filename, diff --git a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py b/substrabac/substrapp/tests/tests_bulkcreatedatasample.py index 9b0f49715..be737949d 100644 --- a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py +++ b/substrabac/substrapp/tests/tests_bulkcreatedatasample.py @@ -60,11 +60,11 @@ def test_bulkcreatedatasample(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data_path2 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1, data_path2], 'data_manager_keys': data_manager_keys, @@ -116,9 +116,9 @@ def test_bulkcreatedatasample_path(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/train/0024308')) + '../../../fixtures/chunantes/datasamples/train/0024308')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1], 'data_manager_keys': data_manager_keys, @@ -170,9 +170,9 @@ def test_bulkcreatedatasample_original_path(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/train/0024308')) + '../../../fixtures/chunantes/datasamples/train/0024308')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1], 'data_manager_keys': data_manager_keys, @@ -223,11 +223,11 @@ def test_bulkcreatedatasample_path_and_files(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/train/0024308')) + '../../../fixtures/chunantes/datasamples/train/0024308')) data_path2 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1, data_path2], 'data_manager_keys': data_manager_keys, @@ -285,9 +285,9 @@ def test_bulkcreatedatasample_same_on_file(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1, data_path1], 'data_manager_keys': data_manager_keys, @@ -325,9 +325,9 @@ def test_bulkcreatedatasample_same_on_path(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/train/0024308')) + '../../../fixtures/chunantes/datasamples/train/0024308')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1, data_path1], 'data_manager_keys': data_manager_keys, @@ -439,7 +439,7 @@ def test_bulkcreatedatasample_not_array_datamanager(self): def test_bulkcreatedatasample_datamanager_do_not_exist(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'files': ['./foo'], 'data_manager_keys': data_manager_keys, @@ -473,7 +473,7 @@ def test_bulkcreatedatasample_invalid_file(self): def test_bulkcreatedatasample_invalid_serializer(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data = {'paths': [data_path1], 'data_manager_keys': [self.datamanager.pk], @@ -507,7 +507,7 @@ def test_bulkcreatedatasample_invalid_serializer(self): def test_bulkcreatedatasample_408(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data = {'paths': [data_path1], 'data_manager_keys': [self.datamanager.pk], @@ -546,7 +546,7 @@ def test_bulkcreatedatasample_408(self): def test_bulkcreatedatasample_ledger_400(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data = {'paths': [data_path1], 'data_manager_keys': [self.datamanager.pk], @@ -585,7 +585,7 @@ def test_bulkcreatedatasample_ledger_400(self): def test_bulkcreatedatasample_400(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data = {'paths': [data_path1], 'data_manager_keys': [self.datamanager.pk], diff --git a/substrabac/substrapp/tests/tests_createdatamanager.py b/substrabac/substrapp/tests/tests_createdatamanager.py index 5592b9131..13d083038 100644 --- a/substrabac/substrapp/tests/tests_createdatamanager.py +++ b/substrabac/substrapp/tests/tests_createdatamanager.py @@ -36,14 +36,14 @@ def test_createdatamanager(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data_path2 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) datamanager_opener_path = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) + '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) datamanager_description_path = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datamanagers/datamanager0/description.md')) + '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) data = { 'data_manager': { @@ -119,14 +119,14 @@ def test_createdatamanager_ko_409(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data_path2 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) datamanager_opener_path = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) + '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) datamanager_description_path = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datamanagers/datamanager0/description.md')) + '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) data = { 'data_manager': { diff --git a/substrabac/substrapp/tests/tests_createobjective.py b/substrabac/substrapp/tests/tests_createobjective.py index 1005011f5..de3297e17 100644 --- a/substrabac/substrapp/tests/tests_createobjective.py +++ b/substrabac/substrapp/tests/tests_createobjective.py @@ -36,18 +36,18 @@ def test_createobjective(self): dir_path = os.path.dirname(os.path.realpath(__file__)) data_path1 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data_path2 = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) datamanager_opener_path = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) + '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) datamanager_description_path = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/datamanagers/datamanager0/description.md')) + '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) objective_metrics_path = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/objectives/objective0/metrics.py')) + '../../../fixtures/chunantes/objectives/objective0/metrics.py')) objective_description_path = os.path.normpath(os.path.join(dir_path, - '../../fixtures/chunantes/objectives/objective0/description.md')) + '../../../fixtures/chunantes/objectives/objective0/description.md')) data = { 'objective': { diff --git a/substrabac/substrapp/tests/tests_model.py b/substrabac/substrapp/tests/tests_model.py index a8442aac8..7efebc419 100644 --- a/substrabac/substrapp/tests/tests_model.py +++ b/substrabac/substrapp/tests/tests_model.py @@ -44,7 +44,7 @@ def test_create_datamanager(self): def test_create_data(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - path = os.path.join(dir_path, '../../fixtures/chunantes/datasamples/train/0024308') + path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/train/0024308') data_sample = DataSample.objects.create(path=path) self.assertEqual(data_sample.pkhash, dirhash(path, 'sha256')) self.assertFalse(data_sample.validated) diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index 78b1baa12..e9504af28 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -904,7 +904,7 @@ def tearDown(self): def test_add_algo_sync_ok(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - with open(os.path.join(dir_path, '../../fixtures/chunantes/algos/algo3/algo.tar.gz'), 'rb') as tar_file: + with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/algo.tar.gz'), 'rb') as tar_file: algo_content = tar_file.read() # add associated objective diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py index 76d418adb..cb009d10f 100644 --- a/substrabac/substrapp/tests/tests_views.py +++ b/substrabac/substrapp/tests/tests_views.py @@ -178,7 +178,7 @@ def test_objective_retrieve(self): mgetObjectFromLedger.return_value = objective[0] with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), - '../../fixtures/owkin/objectives/objective0/description.md'), 'rb') as f: + '../../../fixtures/owkin/objectives/objective0/description.md'), 'rb') as f: content = f.read() mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, @@ -208,7 +208,7 @@ def test_objective_retrieve_fail(self): with mock.patch('substrapp.views.objective.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../fixtures/owkin/objectives/objective0/description.md"))}/' + search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -218,12 +218,12 @@ def test_objective_create(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - description_path = os.path.join(dir_path, '../../fixtures/owkin/objectives/objective0/description.md') - metrics_path = os.path.join(dir_path, '../../fixtures/owkin/objectives/objective0/metrics.py') + description_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/description.md') + metrics_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/metrics.py') pkhash = get_hash(description_path) - test_data_manager_key = get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py')) + test_data_manager_key = get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) data = { 'name': 'Simplified skin lesion classification', @@ -257,10 +257,10 @@ def test_objective_create_dryrun(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - description_path = os.path.join(dir_path, '../../fixtures/owkin/objectives/objective0/description.md') - metrics_path = os.path.join(dir_path, '../../fixtures/owkin/objectives/objective0/metrics.py') + description_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/description.md') + metrics_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/metrics.py') - test_data_manager_key = get_hash(os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py')) + test_data_manager_key = get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) data = { 'name': 'Simplified skin lesion classification', @@ -292,11 +292,11 @@ def test_objective_compute_dryrun(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - metrics_path = os.path.join(dir_path, '../../fixtures/owkin/objectives/objective0/metrics.py') - description_path = os.path.join(dir_path, '../../fixtures/owkin/objectives/objective0/description.md') + metrics_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/metrics.py') + description_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/description.md') shutil.copy(metrics_path, os.path.join(MEDIA_ROOT, 'metrics.py')) - opener_path = os.path.join(dir_path, '../../fixtures/owkin/datamanagers/datamanager0/opener.py') + opener_path = os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py') with open(opener_path, 'rb') as f: opener_content = f.read() @@ -415,14 +415,14 @@ def test_algo_list_filter_model(self): def test_algo_retrieve(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - algo_hash = get_hash(os.path.join(dir_path, '../../fixtures/chunantes/algos/algo4/algo.tar.gz')) + algo_hash = get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo4/algo.tar.gz')) url = reverse('substrapp:algo-list') algo_response = [a for a in algo if a['key'] == algo_hash][0] with mock.patch('substrapp.views.algo.getObjectFromLedger') as mgetObjectFromLedger, \ mock.patch('substrapp.views.algo.requests.get') as mrequestsget: with open(os.path.join(dir_path, - '../../fixtures/chunantes/algos/algo4/description.md'), 'rb') as f: + '../../../fixtures/chunantes/algos/algo4/description.md'), 'rb') as f: content = f.read() mgetObjectFromLedger.return_value = algo_response @@ -453,7 +453,7 @@ def test_algo_retrieve_fail(self): with mock.patch('substrapp.views.algo.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../fixtures/owkin/objectives/objective0/description.md"))}/' + search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -462,15 +462,15 @@ def test_algo_create(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - algo_path = os.path.join(dir_path, '../../fixtures/chunantes/algos/algo3/algo.tar.gz') - description_path = os.path.join(dir_path, '../../fixtures/chunantes/algos/algo3/description.md') + algo_path = os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/algo.tar.gz') + description_path = os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/description.md') pkhash = get_hash(algo_path) data = {'name': 'Logistic regression', 'file': open(algo_path, 'rb'), 'description': open(description_path, 'rb'), - 'objective_key': get_hash(os.path.join(dir_path, '../../fixtures/chunantes/objectives/objective0/description.md')), + 'objective_key': get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/objectives/objective0/description.md')), 'permissions': 'all'} with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: @@ -624,7 +624,7 @@ def test_model_retrieve_fail(self): with mock.patch('substrapp.views.model.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../fixtures/owkin/objectives/objective0/description.md"))}/' + search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -726,11 +726,11 @@ def test_datamanager_retrieve(self): mgetObjectFromLedger.return_value = datamanager_response with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), - '../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), 'rb') as f: + '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), 'rb') as f: opener_content = f.read() with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), - '../../fixtures/chunantes/datamanagers/datamanager0/description.md'), 'rb') as f: + '../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), 'rb') as f: description_content = f.read() mrequestsget.side_effect = [FakeRequest(status=status.HTTP_200_OK, @@ -762,7 +762,7 @@ def test_datamanager_retrieve_fail(self): with mock.patch.object(DataManagerViewSet, 'getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../fixtures/owkin/objectives/objective0/description.md"))}/' + search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -771,10 +771,10 @@ def test_datamanager_create_dryrun(self): dir_path = os.path.dirname(os.path.realpath(__file__)) files = {'data_opener': open(os.path.join(dir_path, - '../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), + '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), 'rb'), 'description': open(os.path.join(dir_path, - '../../fixtures/chunantes/datamanagers/datamanager0/description.md'), + '../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), 'rb')} data = { @@ -858,7 +858,7 @@ def test_traintuple_retrieve_fail(self): with mock.patch.object(TrainTupleViewSet, 'getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../fixtures/owkin/objectives/objective0/description.md"))}/' + search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -930,7 +930,7 @@ def test_testtuple_retrieve_fail(self): with mock.patch('substrapp.views.testtuple.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../fixtures/owkin/objectives/objective0/description.md"))}/' + search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -1023,13 +1023,13 @@ def test_data_create_bulk(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path1 = os.path.join(dir_path, '../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - data_path2 = os.path.join(dir_path, '../../fixtures/chunantes/datasamples/datasample0/0024899.zip') + data_path1 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_path2 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') pkhash1 = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' pkhash2 = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] data = { 'files': [path_leaf(data_path1), path_leaf(data_path2)], @@ -1057,10 +1057,10 @@ def test_data_create_bulk_dryrun(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path1 = os.path.join(dir_path, '../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - data_path2 = os.path.join(dir_path, '../../fixtures/chunantes/datasamples/datasample0/0024899.zip') + data_path1 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_path2 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] data = { 'files': [path_leaf(data_path1), path_leaf(data_path2)], @@ -1090,11 +1090,11 @@ def test_data_create(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path = os.path.join(dir_path, '../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') pkhash = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] data = { 'file': open(data_path, 'rb'), @@ -1121,9 +1121,9 @@ def test_data_create_dryrun(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path = os.path.join(dir_path, '../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - data_manager_keys = [get_hash(os.path.join(dir_path, '../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] data = { 'file': open(data_path, 'rb'), @@ -1149,11 +1149,11 @@ def test_data_sample_compute_dryrun(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path = os.path.join(dir_path, '../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') shutil.copy(data_path, os.path.join(MEDIA_ROOT, '0024700.zip')) - opener_path = os.path.join(dir_path, '../../fixtures/chunantes/datamanagers/datamanager0/opener.py') + opener_path = os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') pkhash = '62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a' From 15a1feb633bad6a055664fe34d4e9fdfbe1a5da9 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 14:42:23 +0200 Subject: [PATCH 033/457] Remove boostrap.sh --- README.md | 3 -- bootstrap.sh | 101 --------------------------------------------------- 2 files changed, 104 deletions(-) delete mode 100755 bootstrap.sh diff --git a/README.md b/README.md index 7ef72dd27..540eace83 100644 --- a/README.md +++ b/README.md @@ -122,9 +122,6 @@ docker build -t substra-model . ## Getting started 2: Linking the app with Hyperledger Fabric -### Get Fabric binaries - -Run `./boostrap.sh` ### Make the subtra-network available to the app diff --git a/bootstrap.sh b/bootstrap.sh deleted file mode 100755 index c622836bc..000000000 --- a/bootstrap.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash - -BASEDIR=$(dirname "$0") - -# if version not passed in, default to latest released version -export VERSION=1.4.1 -# if ca version not passed in, default to latest released version -export CA_VERSION=$VERSION -# current version of thirdparty images (couchdb, kafka and zookeeper) released -export THIRDPARTY_IMAGE_VERSION=0.4.15 -export ARCH=$(echo "$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')") -export MARCH=$(uname -m) - -# starting with 1.2.0, multi-arch images will be default -: ${CA_TAG:="$CA_VERSION"} -: ${FABRIC_TAG:="$VERSION"} - -BINARY_FILE=hyperledger-fabric-${ARCH}-${VERSION}.tar.gz -CA_BINARY_FILE=hyperledger-fabric-ca-${ARCH}-${CA_VERSION}.tar.gz - -# Incrementally downloads the .tar.gz file locally first, only decompressing it -# after the download is complete. This is slower than binaryDownload() but -# allows the download to be resumed. -binaryIncrementalDownload() { - local BINARY_FILE=$1 - local URL=$2 - curl -f -s -C - ${URL} -o ${BINARY_FILE} || rc=$? - # Due to limitations in the current Nexus repo: - # curl returns 33 when there's a resume attempt with no more bytes to download - # curl returns 2 after finishing a resumed download - # with -f curl returns 22 on a 404 - if [ "$rc" = 22 ]; then - # looks like the requested file doesn't actually exist so stop here - return 22 - fi - if [ -z "$rc" ] || [ $rc -eq 33 ] || [ $rc -eq 2 ]; then - # The checksum validates that RC 33 or 2 are not real failures - echo "==> File downloaded. Verifying the md5sum..." - localMd5sum=$(md5sum ${BINARY_FILE} | awk '{print $1}') - remoteMd5sum=$(curl -s ${URL}.md5) - if [ "$localMd5sum" == "$remoteMd5sum" ]; then - echo "==> Extracting ${BINARY_FILE}..." - tar xzf ./${BINARY_FILE} --overwrite - echo "==> Done." - rm -f ${BINARY_FILE} ${BINARY_FILE}.md5 - else - echo "Download failed: the local md5sum is different from the remote md5sum. Please try again." - rm -f ${BINARY_FILE} ${BINARY_FILE}.md5 - exit 1 - fi - else - echo "Failure downloading binaries (curl RC=$rc). Please try again and the download will resume from where it stopped." - exit 1 - fi -} - -# This will attempt to download the .tar.gz all at once, but will trigger the -# binaryIncrementalDownload() function upon a failure, allowing for resume -# if there are network failures. -binaryDownload() { - local BINARY_FILE=$1 - local URL=$2 - echo "===> Downloading: " ${URL} - # Check if a previous failure occurred and the file was partially downloaded - if [ -e ${BINARY_FILE} ]; then - echo "==> Partial binary file found. Resuming download..." - binaryIncrementalDownload ${BINARY_FILE} ${URL} - else - curl ${URL} | tar xz || rc=$? - if [ ! -z "$rc" ]; then - echo "==> There was an error downloading the binary file. Switching to incremental download." - echo "==> Downloading file..." - binaryIncrementalDownload ${BINARY_FILE} ${URL} - else - echo "==> Done." - fi - fi -} - -binariesInstall() { - echo "===> Downloading version ${FABRIC_TAG} platform specific fabric binaries" - binaryDownload ${BINARY_FILE} https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric/hyperledger-fabric/${ARCH}-${VERSION}/${BINARY_FILE} - if [ $? -eq 22 ]; then - echo - echo "------> ${FABRIC_TAG} platform specific fabric binary is not available to download <----" - echo - fi - - echo "===> Downloading version ${CA_TAG} platform specific fabric-ca-client binary" - binaryDownload ${CA_BINARY_FILE} https://nexus.hyperledger.org/content/repositories/releases/org/hyperledger/fabric-ca/hyperledger-fabric-ca/${ARCH}-${CA_VERSION}/${CA_BINARY_FILE} - if [ $? -eq 22 ]; then - echo - echo "------> ${CA_TAG} fabric-ca-client binary is not available to download (Available from 1.1.0-rc1) <----" - echo - fi -} - -binariesInstall - -# remove config directory -rm -r config From 3fb1b59976bdd3666214ada2c67a75ee0b1af17a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 14:43:08 +0200 Subject: [PATCH 034/457] Move generate network file to fabric-sdk-py-tests repo. --- generateNetworkFile.py | 124 ----------------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 generateNetworkFile.py diff --git a/generateNetworkFile.py b/generateNetworkFile.py deleted file mode 100644 index f97e4fcff..000000000 --- a/generateNetworkFile.py +++ /dev/null @@ -1,124 +0,0 @@ -import json -import os - -dir_path = '.' - - -def generate_network_file(conf): - network_conf = {'name': 'substra', - 'description': 'Substra network', - 'version': '0.1', - 'client': {'organization': 'owkin', - 'credentialStore': {'path': '/tmp/hfc-kvs', - 'cryptoStore': { - 'path': '/tmp/hfc-cvs'}, - 'wallet': 'wallet-name'} - }, - 'organizations': {}, - 'orderers': {}, - 'peers': {}, - 'certificateAuthorities': {} - - } - for orderer in conf['orderers']: - # print(orderer) - admin_private_key = \ - os.listdir('%s/msp/keystore/' % orderer['admin_home'])[0] - network_conf['organizations'][orderer['name']] = { - 'mspid': orderer['msp_id'], - 'orderers': [orderer['host']], - 'certificateAuthorities': [orderer['ca']['name']], - 'users': {'admin': { - 'cert': '%s/msp/signcerts/cert.pem' % orderer['admin_home'], - 'private_key': '%s/msp/keystore/%s' % ( - orderer['admin_home'], admin_private_key)} - } - } - network_conf['orderers'][orderer['name']] = { - 'url': '%s:%s' % (orderer['host'], orderer['port']), - 'grpcOptions': {'grpc.ssl_target_name_override': orderer['host'], - 'grpc-max-send-message-length': 15 - }, - 'tlsCACerts': {'path': orderer['ca']['certfile']}, - 'clientKey': {'path': orderer['tls']['key']}, - 'clientCert': {'path': orderer['tls']['cert']}, - } - - network_conf['certificateAuthorities'][orderer['ca']['name']] = { - 'url': '%s:%s' % ( - orderer['ca']['host'], orderer['ca']['host_port']), - 'grpcOptions': {'verify': True}, - 'tlsCACerts': {'path': orderer['ca']['certfile']}, - 'registrar': [{'enrollId': orderer['users']['admin']['name'], - 'enrollSecret': orderer['users']['admin']['pass'] - }] - } - - for org in conf['orgs']: - # print(org) - admin_private_key = \ - os.listdir('%s/msp/keystore/' % org['users']['admin']['home'])[0] - user_private_key = \ - os.listdir('%s/msp/keystore/' % org['users']['user']['home'])[0] - network_conf['organizations'][org['name']] = {'mspid': org['msp_id'], - 'peers': [peer['host'] - for peer in - org['peers']], - 'certificateAuthorities': [ - org['ca']['name']], - 'users': {'admin': { - 'cert': '%s/msp/signcerts/cert.pem' % - org['users'][ - 'admin'][ - 'home'], - 'private_key': '%s/msp/keystore/%s' % ( - org['users'][ - 'admin'][ - 'home'], - admin_private_key)}, - 'user': { - 'cert': '%s/msp/signcerts/cert.pem' % - org[ - 'users'][ - 'user'][ - 'home'], - 'private_key': '%s/msp/keystore/%s' % ( - org['users'][ - 'user'][ - 'home'], - user_private_key)} - } - } - - network_conf['certificateAuthorities'][org['ca']['name']] = { - 'url': '%s:%s' % (org['ca']['host'], org['ca']['host_port']), - 'grpcOptions': {'verify': True}, - 'tlsCACerts': {'path': org['ca']['certfile']}, - 'registrar': [{'enrollId': org['users']['admin']['name'], - 'enrollSecret': org['users']['admin']['pass'] - }] - } - - for peer in org['peers']: - network_conf['peers'][peer['host']] = { - 'url': '%s:%s' % (peer['host'], peer['host_port']), - 'eventUrl': '%s:%s' % (peer['host'], peer['host_event_port']), - 'grpcOptions': { - 'grpc.ssl_target_name_override': peer['host'], - 'grpc.http2.keepalive_time': 15, - }, - 'tlsCACerts': {'path': org['ca']['certfile']}, - 'clientKey': {'path': peer['tls']['clientKey']}, - 'clientCert': {'path': peer['tls']['clientCert']}, - } - - with open(os.path.join(dir_path, 'network.json'), 'w') as outfile: - json.dump(network_conf, outfile, indent=4, sort_keys=True) - - return network_conf - - -if __name__ == "__main__": - conf_path = '/substra/conf/conf.json' - conf = json.load(open(conf_path, 'r')) - generate_network_file(conf) From bae99624109aa2ce014eb656ded7729e55cb40ce Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 14:55:50 +0200 Subject: [PATCH 035/457] Move substrabac docker materials in containers dir. --- docker/celeryworker/Dockerfile | 4 +--- .../dryrun_data_sample}/Dockerfile | 0 .../dryrun_data_sample}/open_data_sample.py | 0 .../{fake_metrics => containers/dryrun_metrics}/Dockerfile | 0 substrabac/{base_metrics => containers/metrics}/Dockerfile | 0 substrabac/substrapp/tasks.py | 2 +- substrabac/substrapp/views/datasample.py | 2 +- substrabac/substrapp/views/objective.py | 2 +- 8 files changed, 4 insertions(+), 6 deletions(-) rename substrabac/{fake_data_sample => containers/dryrun_data_sample}/Dockerfile (100%) rename substrabac/{fake_data_sample => containers/dryrun_data_sample}/open_data_sample.py (100%) rename substrabac/{fake_metrics => containers/dryrun_metrics}/Dockerfile (100%) rename substrabac/{base_metrics => containers/metrics}/Dockerfile (100%) diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index af5740534..678ac6e68 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -12,8 +12,6 @@ COPY ./substrabac/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt COPY ./substrabac/libs /usr/src/app/libs -COPY ./substrabac/base_metrics /usr/src/app/base_metrics -COPY ./substrabac/fake_metrics /usr/src/app/fake_metrics -COPY ./substrabac/fake_data_sample /usr/src/app/fake_data_sample +COPY ./substrabac/containers /usr/src/app/containers COPY ./substrabac/substrapp /usr/src/app/substrapp COPY ./substrabac/substrabac /usr/src/app/substrabac diff --git a/substrabac/fake_data_sample/Dockerfile b/substrabac/containers/dryrun_data_sample/Dockerfile similarity index 100% rename from substrabac/fake_data_sample/Dockerfile rename to substrabac/containers/dryrun_data_sample/Dockerfile diff --git a/substrabac/fake_data_sample/open_data_sample.py b/substrabac/containers/dryrun_data_sample/open_data_sample.py similarity index 100% rename from substrabac/fake_data_sample/open_data_sample.py rename to substrabac/containers/dryrun_data_sample/open_data_sample.py diff --git a/substrabac/fake_metrics/Dockerfile b/substrabac/containers/dryrun_metrics/Dockerfile similarity index 100% rename from substrabac/fake_metrics/Dockerfile rename to substrabac/containers/dryrun_metrics/Dockerfile diff --git a/substrabac/base_metrics/Dockerfile b/substrabac/containers/metrics/Dockerfile similarity index 100% rename from substrabac/base_metrics/Dockerfile rename to substrabac/containers/metrics/Dockerfile diff --git a/substrabac/substrapp/tasks.py b/substrabac/substrapp/tasks.py index d0c65963f..222c948c2 100644 --- a/substrabac/substrapp/tasks.py +++ b/substrabac/substrapp/tasks.py @@ -476,7 +476,7 @@ def doTask(subtuple, tuple_type): end_model_file = f'{current_site}{reverse("substrapp:model-file", args=[end_model_file_hash])}' # compute metric task - metrics_path = path.join(getattr(settings, 'PROJECT_ROOT'), 'base_metrics') # base metrics comes with substrabac + metrics_path = path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/metrics') # comes with substrabac metrics_docker = f'metrics_{tuple_type}'.lower() # tag must be lowercase for docker metrics_docker_name = f'{metrics_docker}_{subtuple["key"]}' compute_docker(client=client, diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 288f5baea..2b790e504 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -84,7 +84,7 @@ def compute_dryrun(self, data, data_manager_keys): # Launch verification opener_file = os.path.join(subtuple_directory, 'opener/opener.py') - data_sample_docker_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'fake_data_sample') # fake_data comes with substrabac + data_sample_docker_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/dryrun_data_sample') data_docker = 'data_dry_run' # tag must be lowercase for docker data_docker_name = f'{data_docker}_{dryrun_uuid}' diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 0a963ce1d..5a5eaf6f7 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -56,7 +56,7 @@ def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): pred_path = os.path.join(subtuple_directory, 'pred') opener_file = os.path.join(subtuple_directory, 'opener/opener.py') metrics_file = os.path.join(subtuple_directory, 'metrics/metrics.py') - metrics_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'fake_metrics') # base metrics comes with substrabac + metrics_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/dryrun_metrics') metrics_docker = 'metrics_dry_run' # tag must be lowercase for docker metrics_docker_name = f'{metrics_docker}_{dryrun_uuid}' From ddae489617adc711845ce93885850a536b3ebe36 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 15:17:53 +0200 Subject: [PATCH 036/457] Clean lib --- substrabac/libs/SQLPrintingMiddleware.py | 1 - substrabac/libs/__init__.py | 1 - substrabac/libs/pagination.py | 2 -- substrabac/libs/serializers.py | 2 -- 4 files changed, 6 deletions(-) diff --git a/substrabac/libs/SQLPrintingMiddleware.py b/substrabac/libs/SQLPrintingMiddleware.py index 6944596da..1293e2625 100644 --- a/substrabac/libs/SQLPrintingMiddleware.py +++ b/substrabac/libs/SQLPrintingMiddleware.py @@ -4,7 +4,6 @@ from django.conf import settings from django.db import connection -__author__ = 'guillaume' """ Originally code was taken from http://djangosnippets.org/snippets/290/ diff --git a/substrabac/libs/__init__.py b/substrabac/libs/__init__.py index ca5d1ad2d..e69de29bb 100644 --- a/substrabac/libs/__init__.py +++ b/substrabac/libs/__init__.py @@ -1 +0,0 @@ -__author__ = 'guillaume' diff --git a/substrabac/libs/pagination.py b/substrabac/libs/pagination.py index 397bc6b10..0e342a6c5 100644 --- a/substrabac/libs/pagination.py +++ b/substrabac/libs/pagination.py @@ -3,8 +3,6 @@ from __future__ import unicode_literals, absolute_import from rest_framework.pagination import PageNumberPagination -__author__ = 'guillaume' - class LimitedPagination(PageNumberPagination): page_size = 30 diff --git a/substrabac/libs/serializers.py b/substrabac/libs/serializers.py index 9223dbf1a..35d815adf 100644 --- a/substrabac/libs/serializers.py +++ b/substrabac/libs/serializers.py @@ -3,8 +3,6 @@ from __future__ import unicode_literals, absolute_import from rest_framework import serializers -__author__ = 'guillaume' - class DynamicFieldsModelSerializer(serializers.ModelSerializer): """ From d2a3ebfb69f147c1b5421f8b2a3ce6ea70dbc59d Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 15:18:19 +0200 Subject: [PATCH 037/457] Move scripts to root dir. --- .../scripts => scripts}/clean_media.sh | 0 .../scripts => scripts}/clean_media_local.sh | 2 +- .../scripts => scripts}/load_fixtures.sh | 0 .../scripts => scripts}/populate_db.sh | 0 .../scripts => scripts}/recreate_db.sh | 0 substrabac/scripts/generate_assets.py | 38 ------------------- 6 files changed, 1 insertion(+), 39 deletions(-) rename {substrabac/scripts => scripts}/clean_media.sh (100%) rename {substrabac/scripts => scripts}/clean_media_local.sh (67%) mode change 100644 => 100755 rename {substrabac/scripts => scripts}/load_fixtures.sh (100%) rename {substrabac/scripts => scripts}/populate_db.sh (100%) rename {substrabac/scripts => scripts}/recreate_db.sh (100%) delete mode 100644 substrabac/scripts/generate_assets.py diff --git a/substrabac/scripts/clean_media.sh b/scripts/clean_media.sh similarity index 100% rename from substrabac/scripts/clean_media.sh rename to scripts/clean_media.sh diff --git a/substrabac/scripts/clean_media_local.sh b/scripts/clean_media_local.sh old mode 100644 new mode 100755 similarity index 67% rename from substrabac/scripts/clean_media_local.sh rename to scripts/clean_media_local.sh index d2015af2d..c510a598d --- a/substrabac/scripts/clean_media_local.sh +++ b/scripts/clean_media_local.sh @@ -4,4 +4,4 @@ BASEDIR="$(dirname $(dirname $0))" echo $BASEDIR # clean medias -rm -rf ${BASEDIR}/medias/* +rm -rf ${BASEDIR}/substrabac/medias/* diff --git a/substrabac/scripts/load_fixtures.sh b/scripts/load_fixtures.sh similarity index 100% rename from substrabac/scripts/load_fixtures.sh rename to scripts/load_fixtures.sh diff --git a/substrabac/scripts/populate_db.sh b/scripts/populate_db.sh similarity index 100% rename from substrabac/scripts/populate_db.sh rename to scripts/populate_db.sh diff --git a/substrabac/scripts/recreate_db.sh b/scripts/recreate_db.sh similarity index 100% rename from substrabac/scripts/recreate_db.sh rename to scripts/recreate_db.sh diff --git a/substrabac/scripts/generate_assets.py b/substrabac/scripts/generate_assets.py deleted file mode 100644 index ea0447a02..000000000 --- a/substrabac/scripts/generate_assets.py +++ /dev/null @@ -1,38 +0,0 @@ -import os -import json -from substra_sdk_py import Client - - -dir_path = os.path.dirname(os.path.realpath(__file__)) - - -def main(): - - client = Client() - client.create_config('owkin', 'http://owkin.substrabac:8000', '0.0') - - client.set_config('owkin') - - assets = {} - assets['objective'] = json.dumps(client.list('objective'), indent=4) - assets['datamanager'] = json.dumps(client.list('data_manager'), indent=4) - assets['algo'] = json.dumps(client.list('algo'), indent=4) - assets['traintuple'] = json.dumps(client.list('traintuple'), indent=4) - assets['testtuple'] = json.dumps(client.list('testtuple'), indent=4) - - assets['model'] = json.dumps([res for res in client.list('model') - if ('traintuple' in res and 'testtuple' in res)], indent=4) - - with open(os.path.join(dir_path, '../substrapp/tests/assets.py'), 'w') as f: - for k, v in assets.items(): - v = v.replace('owkin.substrabac:8000', 'testserver') - v = v.replace('chunantes.substrabac:8001', 'testserver') - v = v.replace('true', 'True') - v = v.replace('false', 'False') - v = v.replace('null', 'None') - f.write(f'{k} = {v}') - f.write('\n\n') - - -if __name__ == '__main__': - main() From 38e781b7223a6637acab454a4cadbd3de66e7359 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 15:18:41 +0200 Subject: [PATCH 038/457] Move generate assets to tests --- substrabac/substrapp/tests/generate_assets.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 substrabac/substrapp/tests/generate_assets.py diff --git a/substrabac/substrapp/tests/generate_assets.py b/substrabac/substrapp/tests/generate_assets.py new file mode 100644 index 000000000..ea0447a02 --- /dev/null +++ b/substrabac/substrapp/tests/generate_assets.py @@ -0,0 +1,38 @@ +import os +import json +from substra_sdk_py import Client + + +dir_path = os.path.dirname(os.path.realpath(__file__)) + + +def main(): + + client = Client() + client.create_config('owkin', 'http://owkin.substrabac:8000', '0.0') + + client.set_config('owkin') + + assets = {} + assets['objective'] = json.dumps(client.list('objective'), indent=4) + assets['datamanager'] = json.dumps(client.list('data_manager'), indent=4) + assets['algo'] = json.dumps(client.list('algo'), indent=4) + assets['traintuple'] = json.dumps(client.list('traintuple'), indent=4) + assets['testtuple'] = json.dumps(client.list('testtuple'), indent=4) + + assets['model'] = json.dumps([res for res in client.list('model') + if ('traintuple' in res and 'testtuple' in res)], indent=4) + + with open(os.path.join(dir_path, '../substrapp/tests/assets.py'), 'w') as f: + for k, v in assets.items(): + v = v.replace('owkin.substrabac:8000', 'testserver') + v = v.replace('chunantes.substrabac:8001', 'testserver') + v = v.replace('true', 'True') + v = v.replace('false', 'False') + v = v.replace('null', 'None') + f.write(f'{k} = {v}') + f.write('\n\n') + + +if __name__ == '__main__': + main() From 6801d8bb4b822cc03328117e52696f1e14c7c5af Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 15:19:13 +0200 Subject: [PATCH 039/457] Update and clean settings --- substrabac/substrabac/__init__.py | 2 +- substrabac/substrabac/celery.py | 5 ----- substrabac/substrabac/settings/common.py | 2 +- substrabac/substrabac/settings/deps/restframework.py | 2 +- substrabac/substrabac/settings/events/dev.py | 2 -- substrabac/substrabac/settings/events/prod.py | 2 -- substrabac/substrabac/settings/test.py | 2 -- substrabac/substrabac/urls.py | 3 ++- 8 files changed, 5 insertions(+), 15 deletions(-) diff --git a/substrabac/substrabac/__init__.py b/substrabac/substrabac/__init__.py index d128d39cd..070e835d0 100644 --- a/substrabac/substrabac/__init__.py +++ b/substrabac/substrabac/__init__.py @@ -4,4 +4,4 @@ # Django starts so that shared_task will use this app. from .celery import app as celery_app -__all__ = ('celery_app',) \ No newline at end of file +__all__ = ('celery_app',) diff --git a/substrabac/substrabac/celery.py b/substrabac/substrabac/celery.py index e6b614f54..7c7bf8b96 100644 --- a/substrabac/substrabac/celery.py +++ b/substrabac/substrabac/celery.py @@ -18,11 +18,6 @@ app.autodiscover_tasks() -@app.task(bind=True) -def debug_task(self): - print('Request: {0!r}'.format(self.request)) - - @app.on_after_configure.connect def setup_periodic_tasks(sender, **kwargs): from substrapp.tasks import prepareTrainingTask, prepareTestingTask diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 6598755b5..36fbf1dbf 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -10,7 +10,7 @@ https://docs.djangoproject.com/en/2.0/ref/settings/ """ -import os, sys, json +import os, sys from libs.gen_secret_key import write_secret_key # Build paths inside the project like this: os.path.join(BASE_DIR, ...) diff --git a/substrabac/substrabac/settings/deps/restframework.py b/substrabac/substrabac/settings/deps/restframework.py index 44b021d45..e79ae083b 100644 --- a/substrabac/substrabac/settings/deps/restframework.py +++ b/substrabac/substrabac/settings/deps/restframework.py @@ -2,7 +2,7 @@ 'TEST_REQUEST_DEFAULT_FORMAT': 'json', 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', - #'rest_framework.renderers.AdminRenderer', + # 'rest_framework.renderers.AdminRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ), 'DEFAULT_AUTHENTICATION_CLASSES': ( diff --git a/substrabac/substrabac/settings/events/dev.py b/substrabac/substrabac/settings/events/dev.py index d90cec828..1035c6381 100644 --- a/substrabac/substrabac/settings/events/dev.py +++ b/substrabac/substrabac/settings/events/dev.py @@ -1,5 +1,3 @@ -import os - from ..dev import * INSTALLED_APPS += ['events'] diff --git a/substrabac/substrabac/settings/events/prod.py b/substrabac/substrabac/settings/events/prod.py index 1d6058bf5..5c54afdd7 100644 --- a/substrabac/substrabac/settings/events/prod.py +++ b/substrabac/substrabac/settings/events/prod.py @@ -1,5 +1,3 @@ -import os - from ..prod import * INSTALLED_APPS += ['events'] diff --git a/substrabac/substrabac/settings/test.py b/substrabac/substrabac/settings/test.py index 262350ce2..b81d8db16 100644 --- a/substrabac/substrabac/settings/test.py +++ b/substrabac/substrabac/settings/test.py @@ -1,5 +1,3 @@ -import os - from .common import * from .deps.restframework import * diff --git a/substrabac/substrabac/urls.py b/substrabac/substrabac/urls.py index 26aadf7fa..1395fbc0d 100644 --- a/substrabac/substrabac/urls.py +++ b/substrabac/substrabac/urls.py @@ -29,4 +29,5 @@ url(r'^doc/', schema_view), url(r'^', include((router.urls, 'substrapp'))), ])), -] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ + + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) From f99e0219a0f52836c8f970403b3488813f8bf657 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 15:58:51 +0200 Subject: [PATCH 040/457] Fix clean media call. --- docker/start.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/start.py b/docker/start.py index 74f927dd4..a5e6e89ac 100644 --- a/docker/start.py +++ b/docker/start.py @@ -240,7 +240,7 @@ def start(conf, launch_settings, no_backup): if no_backup: print('Clean medias directory\n') - call(['sh', os.path.join(dir_path, '../substrabac/scripts/clean_media.sh')]) + call(['sh', os.path.join(dir_path, '../scripts/clean_media.sh')]) print('Remove postgresql database\n') call(['rm', '-rf', '/substra/backup/postgres-data']) print('Remove rabbit database\n') From 19aa9c684752f8add4a23ce4136c319d9d80ba22 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 27 May 2019 15:59:21 +0200 Subject: [PATCH 041/457] Restructure substrapp. --- substrabac/events/apps.py | 2 +- substrabac/substrabac/celery.py | 2 +- substrabac/substrabac/settings/dev.py | 92 +++++++++---------- substrabac/substrabac/settings/prod.py | 92 +++++++++---------- substrabac/substrapp/admin.py | 8 +- substrabac/substrapp/apps.py | 7 +- substrabac/substrapp/tasks/__init__.py | 0 .../{ => tasks}/exception_handler.py | 0 .../substrapp/{ => tasks}/exceptions.json | 0 .../{ => tasks}/generate_exceptions_map.py | 0 substrabac/substrapp/{ => tasks}/tasks.py | 6 +- .../{task_utils.py => tasks/utils.py} | 0 substrabac/substrapp/tests/tests_exception.py | 6 +- substrabac/substrapp/tests/tests_misc.py | 3 +- substrabac/substrapp/tests/tests_tasks.py | 68 +++++++------- substrabac/substrapp/views/datasample.py | 2 +- substrabac/substrapp/views/objective.py | 2 +- 17 files changed, 144 insertions(+), 146 deletions(-) create mode 100644 substrabac/substrapp/tasks/__init__.py rename substrabac/substrapp/{ => tasks}/exception_handler.py (100%) rename substrabac/substrapp/{ => tasks}/exceptions.json (100%) rename substrabac/substrapp/{ => tasks}/generate_exceptions_map.py (100%) rename substrabac/substrapp/{ => tasks}/tasks.py (99%) rename substrabac/substrapp/{task_utils.py => tasks/utils.py} (100%) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index d2b47eeb3..0938d402a 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -16,7 +16,7 @@ from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore -from substrapp.tasks import prepareTuple +from substrapp.tasks.tasks import prepareTuple from substrapp.utils import get_hash LEDGER = getattr(settings, 'LEDGER', None) diff --git a/substrabac/substrabac/celery.py b/substrabac/substrabac/celery.py index 7c7bf8b96..7eccee6d4 100644 --- a/substrabac/substrabac/celery.py +++ b/substrabac/substrabac/celery.py @@ -20,7 +20,7 @@ @app.on_after_configure.connect def setup_periodic_tasks(sender, **kwargs): - from substrapp.tasks import prepareTrainingTask, prepareTestingTask + from substrapp.tasks.tasks import prepareTrainingTask, prepareTestingTask period = 3 * 3600 sender.add_periodic_task(period, prepareTrainingTask.s(), queue='scheduler', diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 04830fa88..a7549cae8 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -1,6 +1,7 @@ import os import asyncio import glob +import json from .common import * @@ -22,53 +23,50 @@ ORG_NAME = ORG.replace('-', '') ORG_DB_NAME = ORG.replace('-', '_').upper() -try: - LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) -except: - pass -else: - HLF_LOOP = asyncio.new_event_loop() - asyncio.set_event_loop(HLF_LOOP) - - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] - orderer = LEDGER['orderer'] - - requestor_config = LEDGER['client'] - - CLIENT = Client() - CLIENT.new_channel(channel_name) - - REQUESTOR = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - - target_peer = Peer(name=peer['name']) - - # Need loop - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) - CLIENT._peers[peer['name']] = target_peer - - target_orderer = Orderer(name=orderer['name']) - - # Need loop - target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', - 'grpcOptions': orderer['grpcOptions'], - 'tlsCACerts': {'path': orderer['ca']}, - 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) - 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) - }) - CLIENT._orderers[orderer['name']] = target_orderer +LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) + +HLF_LOOP = asyncio.new_event_loop() +asyncio.set_event_loop(HLF_LOOP) + +channel_name = LEDGER['channel_name'] +chaincode_name = LEDGER['chaincode_name'] +peer = LEDGER['peer'] +peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] +orderer = LEDGER['orderer'] + +requestor_config = LEDGER['client'] + +CLIENT = Client() +CLIENT.new_channel(channel_name) + +REQUESTOR = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + +target_peer = Peer(name=peer['name']) + +# Need loop +target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) +CLIENT._peers[peer['name']] = target_peer + +target_orderer = Orderer(name=orderer['name']) + +# Need loop +target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', + 'grpcOptions': orderer['grpcOptions'], + 'tlsCACerts': {'path': orderer['ca']}, + 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) + }) +CLIENT._orderers[orderer['name']] = target_orderer # Database diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 7d8fb8de8..5ff9f166a 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -1,6 +1,7 @@ import os import asyncio import glob +import json from .common import * @@ -29,53 +30,50 @@ ORG_NAME = ORG.replace('-', '') ORG_DB_NAME = ORG.replace('-', '_').upper() -try: - LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) -except: - pass -else: - HLF_LOOP = asyncio.new_event_loop() - asyncio.set_event_loop(HLF_LOOP) - - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] - orderer = LEDGER['orderer'] - - requestor_config = LEDGER['client'] - - CLIENT = Client() - CLIENT.new_channel(channel_name) - - REQUESTOR = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - - target_peer = Peer(name=peer['name']) - - # Need loop - target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) - CLIENT._peers[peer['name']] = target_peer - - target_orderer = Orderer(name=orderer['name']) - - # Need loop - target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', - 'grpcOptions': orderer['grpcOptions'], - 'tlsCACerts': {'path': orderer['ca']}, - 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) - 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) - }) - CLIENT._orderers[orderer['name']] = target_orderer +LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) + +HLF_LOOP = asyncio.new_event_loop() +asyncio.set_event_loop(HLF_LOOP) + +channel_name = LEDGER['channel_name'] +chaincode_name = LEDGER['chaincode_name'] +peer = LEDGER['peer'] +peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] +orderer = LEDGER['orderer'] + +requestor_config = LEDGER['client'] + +CLIENT = Client() +CLIENT.new_channel(channel_name) + +REQUESTOR = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + +target_peer = Peer(name=peer['name']) + +# Need loop +target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) +CLIENT._peers[peer['name']] = target_peer + +target_orderer = Orderer(name=orderer['name']) + +# Need loop +target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', + 'grpcOptions': orderer['grpcOptions'], + 'tlsCACerts': {'path': orderer['ca']}, + 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) + }) +CLIENT._orderers[orderer['name']] = target_orderer # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases diff --git a/substrabac/substrapp/admin.py b/substrabac/substrapp/admin.py index 59380d882..0eb5e50bb 100644 --- a/substrabac/substrapp/admin.py +++ b/substrabac/substrapp/admin.py @@ -2,8 +2,8 @@ from substrapp.models import Objective, Model, DataSample, DataManager, Algo -admin.site.register(Objective) -admin.site.register(Model) -admin.site.register(DataSample) -admin.site.register(DataManager) admin.site.register(Algo) +admin.site.register(DataManager) +admin.site.register(DataSample) +admin.site.register(Model) +admin.site.register(Objective) diff --git a/substrabac/substrapp/apps.py b/substrabac/substrapp/apps.py index c8cb6c42c..b967860d1 100644 --- a/substrabac/substrapp/apps.py +++ b/substrabac/substrapp/apps.py @@ -6,20 +6,21 @@ class SubstrappConfig(AppConfig): name = 'substrapp' def ready(self): + from .signals.datasample.pre_save import data_sample_pre_save + from .signals.algo.post_delete import algo_post_delete from .signals.objective.post_delete import objective_post_delete from .signals.datasample.post_delete import data_sample_post_delete from .signals.datamanager.post_delete import datamanager_post_delete from .signals.model.post_delete import model_post_delete - from .signals.datasample.pre_save import data_sample_pre_save # registering signals with the model's string label from substrapp.models import Algo, Objective, DataSample, DataManager, Model + pre_save.connect(data_sample_pre_save, sender=DataSample) + post_delete.connect(algo_post_delete, sender=Algo) post_delete.connect(objective_post_delete, sender=Objective) post_delete.connect(data_sample_post_delete, sender=DataSample) post_delete.connect(datamanager_post_delete, sender=DataManager) post_delete.connect(model_post_delete, sender=Model) - - pre_save.connect(data_sample_pre_save, sender=DataSample) diff --git a/substrabac/substrapp/tasks/__init__.py b/substrabac/substrapp/tasks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/substrapp/exception_handler.py b/substrabac/substrapp/tasks/exception_handler.py similarity index 100% rename from substrabac/substrapp/exception_handler.py rename to substrabac/substrapp/tasks/exception_handler.py diff --git a/substrabac/substrapp/exceptions.json b/substrabac/substrapp/tasks/exceptions.json similarity index 100% rename from substrabac/substrapp/exceptions.json rename to substrabac/substrapp/tasks/exceptions.json diff --git a/substrabac/substrapp/generate_exceptions_map.py b/substrabac/substrapp/tasks/generate_exceptions_map.py similarity index 100% rename from substrabac/substrapp/generate_exceptions_map.py rename to substrabac/substrapp/tasks/generate_exceptions_map.py diff --git a/substrabac/substrapp/tasks.py b/substrabac/substrapp/tasks/tasks.py similarity index 99% rename from substrabac/substrapp/tasks.py rename to substrabac/substrapp/tasks/tasks.py index 222c948c2..a0944d2dd 100644 --- a/substrabac/substrapp/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -12,8 +12,8 @@ from substrabac.celery import app from substrapp.utils import queryLedger, invokeLedger, get_hash, create_directory, get_remote_file, uncompress_content -from substrapp.task_utils import ResourcesManager, compute_docker -from substrapp.exception_handler import compute_error_code +from substrapp.tasks.utils import ResourcesManager, compute_docker +from substrapp.tasks.exception_handler import compute_error_code import docker import json @@ -227,7 +227,7 @@ def prepareTuple(subtuple, tuple_type, model_type): if 'fltask' in subtuple and subtuple['fltask']: fltask = subtuple['fltask'] flresults = TaskResult.objects.filter( - task_name='substrapp.tasks.computeTask', + task_name='substrapp.tasks.tasks.computeTask', result__icontains=f'"fltask": "{fltask}"') if flresults and flresults.count() > 0: diff --git a/substrabac/substrapp/task_utils.py b/substrabac/substrapp/tasks/utils.py similarity index 100% rename from substrabac/substrapp/task_utils.py rename to substrabac/substrapp/tasks/utils.py diff --git a/substrabac/substrapp/tests/tests_exception.py b/substrabac/substrapp/tests/tests_exception.py index f8ea10b3f..3d40a9ea5 100644 --- a/substrabac/substrapp/tests/tests_exception.py +++ b/substrabac/substrapp/tests/tests_exception.py @@ -2,8 +2,8 @@ import json import docker from django.test import TestCase -from substrapp.generate_exceptions_map import exception_tree, find_exception, MODULES -from substrapp.exception_handler import compute_error_code, get_exception_code +from substrapp.tasks.generate_exceptions_map import exception_tree, find_exception, MODULES +from substrapp.tasks.exception_handler import compute_error_code, get_exception_code class ExceptionTests(TestCase): @@ -32,7 +32,7 @@ def test_exception_map(self): exception_map[exception_name] = f'{code_exception:04d}' # Exception map reference - EXCEPTION_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../exceptions.json') + EXCEPTION_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../tasks/exceptions.json') reference_exception_map = json.load(open(EXCEPTION_PATH)) self.assertTrue(set(reference_exception_map.keys()).issubset(set(exception_map.keys()))) diff --git a/substrabac/substrapp/tests/tests_misc.py b/substrabac/substrapp/tests/tests_misc.py index 8ee372c0d..95a52a529 100644 --- a/substrabac/substrapp/tests/tests_misc.py +++ b/substrabac/substrapp/tests/tests_misc.py @@ -1,11 +1,12 @@ from django.test import TestCase from mock import patch -from substrapp.task_utils import get_cpu_sets, get_gpu_sets, ExceptionThread, \ +from substrapp.tasks.utils import get_cpu_sets, get_gpu_sets, ExceptionThread, \ update_statistics from substrapp.tests.common import JobStats, Stats, gpu + class MockDevice(): """A mock device to temporarily suppress output to stdout Similar to UNIX /dev/null. diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index c289be5ea..cd2af0d4c 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -11,8 +11,8 @@ from substrapp.models import DataSample from substrapp.utils import compute_hash, get_computed_hash, get_remote_file, get_hash, create_directory -from substrapp.task_utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread -from substrapp.tasks import build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, put_model, put_models, put_algo, put_metric, put_data_sample, prepareTask, doTask, computeTask +from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread +from substrapp.tasks.tasks import build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, put_model, put_models, put_algo, put_metric, put_data_sample, prepareTask, doTask, computeTask from .common import get_sample_algo, get_sample_script, get_sample_zip_data_sample, get_sample_tar_data_sample, get_sample_model from .common import FakeClient, FakeObjective, FakeDataManager, FakeModel @@ -115,7 +115,7 @@ def test_put_algo_tar(self): subtuple = {'key': subtuple_key, 'algo': 'testalgo'} - with mock.patch('substrapp.tasks.get_hash') as mget_hash: + with mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash: mget_hash.return_value = subtuple_key put_algo(os.path.join(self.subtuple_path, f'subtuple/{subtuple["key"]}/'), algo_content) @@ -145,7 +145,7 @@ def test_put_algo_zip(self): subtuple_key = 'testkey' subtuple = {'key': subtuple_key, 'algo': 'testalgo'} - with mock.patch('substrapp.tasks.get_hash') as mget_hash: + with mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash: with open(zippath, 'rb') as content: mget_hash.return_value = get_hash(zippath) put_algo(os.path.join(self.subtuple_path, f'subtuple/{subtuple["key"]}/'), content.read()) @@ -320,7 +320,7 @@ def test_get_model(self): model_type = 'model' subtuple = {model_type: {'hash': model_hash, 'traintupleKey': traintupleKey}} - with mock.patch('substrapp.tasks.get_remote_file') as mget_remote_file: + with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: mget_remote_file.return_value = model_content, model_hash model_content, model_hash = get_model(subtuple) @@ -342,7 +342,7 @@ def test_get_models(self): subtuple = {model_type: [{'hash': model_hash, 'traintupleKey': traintupleKey}, {'hash': model_hash2, 'traintupleKey': traintupleKey2}]} - with mock.patch('substrapp.tasks.get_remote_file') as mget_remote_file: + with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: mget_remote_file.side_effect = [[models_content[0], models_hash[0]], [models_content[1], models_hash[1]]] models_content_res, models_hash_res = get_models(subtuple) @@ -354,7 +354,7 @@ def test_get_algo(self): algo_content = self.algo.read() algo_hash = get_hash(self.algo) - with mock.patch('substrapp.tasks.get_remote_file') as mget_remote_file: + with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: mget_remote_file.return_value = algo_content, algo_hash self.assertEqual((algo_content, algo_hash), get_algo({'algo': ''})) @@ -363,7 +363,7 @@ def test_get_objective(self): objective_hash = get_hash(self.script) with mock.patch('substrapp.models.Objective.objects.get') as mget, \ - mock.patch('substrapp.tasks.get_remote_file') as mget_remote_file, \ + mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: mget.return_value = FakeObjective() @@ -396,7 +396,7 @@ def test_compute_docker(self): self.assertIn('GPU Mem', result) def test_build_subtuple_folders(self): - with mock.patch('substrapp.tasks.getattr') as getattr: + with mock.patch('substrapp.tasks.tasks.getattr') as getattr: getattr.return_value = self.subtuple_path subtuple_key = 'test1234' @@ -423,18 +423,18 @@ def __init__(self): subtuple = [{'key': 'subtuple_test'}] - with mock.patch('substrapp.tasks.settings') as msettings, \ - mock.patch('substrapp.tasks.get_hash') as mget_hash, \ - mock.patch('substrapp.tasks.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.tasks.get_objective') as mget_objective, \ - mock.patch('substrapp.tasks.get_algo') as mget_algo, \ - mock.patch('substrapp.tasks.get_model') as mget_model, \ - mock.patch('substrapp.tasks.build_subtuple_folders') as mbuild_subtuple_folders, \ - mock.patch('substrapp.tasks.put_opener') as mput_opener, \ - mock.patch('substrapp.tasks.put_data_sample') as mput_data_sample, \ - mock.patch('substrapp.tasks.put_metric') as mput_metric, \ - mock.patch('substrapp.tasks.put_algo') as mput_algo, \ - mock.patch('substrapp.tasks.put_model') as mput_model: + with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ + mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash, \ + mock.patch('substrapp.tasks.tasks.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.tasks.tasks.get_objective') as mget_objective, \ + mock.patch('substrapp.tasks.tasks.get_algo') as mget_algo, \ + mock.patch('substrapp.tasks.tasks.get_model') as mget_model, \ + mock.patch('substrapp.tasks.tasks.build_subtuple_folders') as mbuild_subtuple_folders, \ + mock.patch('substrapp.tasks.tasks.put_opener') as mput_opener, \ + mock.patch('substrapp.tasks.tasks.put_data_sample') as mput_data_sample, \ + mock.patch('substrapp.tasks.tasks.put_metric') as mput_metric, \ + mock.patch('substrapp.tasks.tasks.put_algo') as mput_algo, \ + mock.patch('substrapp.tasks.tasks.put_model') as mput_model: msettings.return_value = FakeSettings() mget_hash.return_value = 'owkinhash' @@ -449,12 +449,12 @@ def __init__(self): mput_algo.return_value = 'algo' mput_model.return_value = 'model' - with mock.patch('substrapp.tasks.queryLedger') as mqueryLedger: + with mock.patch('substrapp.tasks.tasks.queryLedger') as mqueryLedger: mqueryLedger.return_value = 'data', 404 prepareTask('traintuple', 'inModels') - with mock.patch('substrapp.tasks.invokeLedger') as minvokeLedger, \ - mock.patch('substrapp.tasks.computeTask.apply_async') as mapply_async: + with mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger, \ + mock.patch('substrapp.tasks.tasks.computeTask.apply_async') as mapply_async: minvokeLedger.return_value = 'data', 201 mapply_async.return_value = 'doTask' prepareTask('traintuple', 'inModels') @@ -473,9 +473,9 @@ def __init__(self): subtuple = {'key': subtuple_key, 'inModels': None} subtuple_directory = build_subtuple_folders(subtuple) - with mock.patch('substrapp.tasks.settings') as msettings, \ - mock.patch('substrapp.tasks.getattr') as mgetattr, \ - mock.patch('substrapp.tasks.invokeLedger') as minvokeLedger: + with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ + mock.patch('substrapp.tasks.tasks.getattr') as mgetattr, \ + mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger: msettings.return_value = FakeSettings() mgetattr.return_value = self.subtuple_path minvokeLedger.return_value = 'data', 200 @@ -491,7 +491,7 @@ def __init__(self): with open(os.path.join(subtuple_directory, 'model/model'), 'w') as f: f.write("MODEL") - with mock.patch('substrapp.tasks.compute_docker') as mcompute_docker: + with mock.patch('substrapp.tasks.tasks.compute_docker') as mcompute_docker: mcompute_docker.return_value = 'DONE' doTask(subtuple, 'traintuple') @@ -509,9 +509,9 @@ def __init__(self): subtuple = {'key': subtuple_key, 'inModels': None} subtuple_directory = build_subtuple_folders(subtuple) - with mock.patch('substrapp.tasks.settings') as msettings, \ - mock.patch('substrapp.tasks.getattr') as mgetattr, \ - mock.patch('substrapp.tasks.invokeLedger') as minvokeLedger: + with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ + mock.patch('substrapp.tasks.tasks.getattr') as mgetattr, \ + mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger: msettings.return_value = FakeSettings() mgetattr.return_value = self.subtuple_path minvokeLedger.return_value = 'data', 200 @@ -527,9 +527,9 @@ def __init__(self): with open(os.path.join(subtuple_directory, 'model/model'), 'w') as f: f.write("MODEL") - with mock.patch('substrapp.tasks.compute_docker') as mcompute_docker, \ - mock.patch('substrapp.tasks.prepareMaterials') as mprepareMaterials, \ - mock.patch('substrapp.tasks.invokeLedger') as minvokeLedger: + with mock.patch('substrapp.tasks.tasks.compute_docker') as mcompute_docker, \ + mock.patch('substrapp.tasks.tasks.prepareMaterials') as mprepareMaterials, \ + mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger: mcompute_docker.return_value = 'DONE' mprepareMaterials.return_value = 'DONE' diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 2b790e504..9f09d80e4 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -23,7 +23,7 @@ from substrapp.serializers.ledger.datasample.util import updateLedgerDataSample from substrapp.serializers.ledger.datasample.tasks import updateLedgerDataSampleAsync from substrapp.utils import uncompress_path, get_dir_hash -from substrapp.tasks import build_subtuple_folders, remove_subtuple_materials +from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import find_primary_key_error logger = logging.getLogger('django.request') diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 5a5eaf6f7..18e5eb69e 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -27,7 +27,7 @@ from substrapp.utils import queryLedger, get_hash, get_computed_hash -from substrapp.tasks import build_subtuple_folders, remove_subtuple_materials +from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import get_filters, getObjectFromLedger, ComputeHashMixin, ManageFileMixin, JsonException, find_primary_key_error From 793c0675c566aad4b85f2d3b13f3cd11f88fbc94 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 28 May 2019 15:24:03 +0200 Subject: [PATCH 042/457] apply flake8 --- .flake8 | 6 + Jenkinsfile | 2 + docker/start.py | 204 ++++++++++-------- fixtures/isic_2018.py | 15 +- populate.py | 2 - substrabac/events/apps.py | 2 +- substrabac/substrabac/settings/common.py | 3 +- substrabac/substrabac/settings/deps/raven.py | 2 +- substrabac/substrabac/settings/test.py | 6 +- substrabac/substrabac/views.py | 2 +- .../commands/bulkcreatedatasample.py | 12 +- .../management/commands/createdataset.py | 11 +- .../management/commands/createobjective.py | 24 ++- substrabac/substrapp/models/objective.py | 4 +- substrabac/substrapp/serializers/algo.py | 10 +- .../substrapp/serializers/datasample.py | 3 +- .../serializers/ledger/algo/serializer.py | 5 +- .../substrapp/serializers/ledger/algo/util.py | 2 +- .../ledger/datamanager/serializer.py | 7 +- .../serializers/ledger/datamanager/tasks.py | 1 + .../serializers/ledger/datamanager/util.py | 2 +- .../ledger/datasample/serializer.py | 3 +- .../serializers/ledger/datasample/tasks.py | 1 + .../serializers/ledger/datasample/util.py | 2 +- .../ledger/objective/serializer.py | 7 +- .../serializers/ledger/objective/util.py | 2 +- .../ledger/testtuple/serializer.py | 4 +- .../ledger/traintuple/serializer.py | 6 +- .../substrapp/signals/datasample/pre_save.py | 4 +- .../substrapp/tasks/exception_handler.py | 2 +- .../tasks/generate_exceptions_map.py | 13 +- substrabac/substrapp/tasks/tasks.py | 20 +- substrabac/substrapp/tasks/utils.py | 6 +- substrabac/substrapp/tests/common.py | 4 +- .../tests/tests_bulkcreatedatasample.py | 71 +++--- .../tests/tests_createdatamanager.py | 80 +++---- .../substrapp/tests/tests_createobjective.py | 66 +++--- substrabac/substrapp/tests/tests_query.py | 122 ++++++----- substrabac/substrapp/tests/tests_tasks.py | 87 ++++---- substrabac/substrapp/tests/tests_views.py | 74 ++++--- substrabac/substrapp/utils.py | 5 +- substrabac/substrapp/views/algo.py | 31 +-- substrabac/substrapp/views/datamanager.py | 61 +++--- substrabac/substrapp/views/datasample.py | 15 +- substrabac/substrapp/views/model.py | 35 +-- substrabac/substrapp/views/objective.py | 44 ++-- substrabac/substrapp/views/task.py | 5 +- substrabac/substrapp/views/testtuple.py | 24 +-- substrabac/substrapp/views/traintuple.py | 29 +-- substrabac/substrapp/views/utils.py | 12 +- 50 files changed, 640 insertions(+), 520 deletions(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 000000000..e20e69f23 --- /dev/null +++ b/.flake8 @@ -0,0 +1,6 @@ +[flake8] +max-line-length = 120 +ignore = E402, W504, F403, F405 +exclude = substrabac/substrapp/migrations/*, + substrabac/substrapp/tests/assets.py, + .env, .venv diff --git a/Jenkinsfile b/Jenkinsfile index b177c9826..d770ac244 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -33,6 +33,8 @@ pipeline { sh "apt install -y python3-pip python3-dev build-essential gfortran musl-dev postgresql-contrib git curl netcat" dir("substrabac") { + sh "pip install flake8" + sh "flake8" sh "pip install -r requirements.txt" sh "DJANGO_SETTINGS_MODULE=substrabac.settings.test coverage run manage.py test" sh "coverage report" diff --git a/docker/start.py b/docker/start.py index a5e6e89ac..cc0679944 100644 --- a/docker/start.py +++ b/docker/start.py @@ -45,43 +45,53 @@ def generate_docker_compose_file(conf, launch_settings): import yaml # Docker compose config - docker_compose = {'substrabac_services': {}, - 'substrabac_tools': {'postgresql': {'container_name': 'postgresql', - 'image': 'library/postgres:10.5', - 'restart': 'unless-stopped', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': [f'POSTGRES_USER={POSTGRES_USER}', - f'USER={USER}', - f'POSTGRES_PASSWORD={POSTGRES_PASSWORD}', - f'POSTGRES_DB={POSTGRES_DB}'], - 'volumes': [ - '/substra/backup/postgres-data:/var/lib/postgresql/data', - f'{dir_path}/postgresql/init.sh:/docker-entrypoint-initdb.d/init.sh'], - }, - 'celerybeat': {'container_name': 'celerybeat', - 'hostname': 'celerybeat', - 'image': 'substra/celerybeat', - 'restart': 'unless-stopped', - 'command': '/bin/bash -c "while ! { nc -z rabbit 5672 2>&1; }; do sleep 1; done; while ! { nc -z postgresql 5432 2>&1; }; do sleep 1; done; celery -A substrabac beat -l info"', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': ['PYTHONUNBUFFERED=1', - f'CELERY_BROKER_URL={CELERY_BROKER_URL}', - f'DJANGO_SETTINGS_MODULE=substrabac.settings.common'], - 'depends_on': ['postgresql', 'rabbit'] - }, - 'rabbit': {'container_name': 'rabbit', - 'hostname': 'rabbitmq', # Must be set to be able to recover from volume - 'restart': 'unless-stopped', - 'image': 'rabbitmq:3', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': [f'RABBITMQ_DEFAULT_USER={RABBITMQ_DEFAULT_USER}', - f'RABBITMQ_DEFAULT_PASS={RABBITMQ_DEFAULT_PASS}', - f'HOSTNAME={RABBITMQ_HOSTNAME}', - f'RABBITMQ_NODENAME={RABBITMQ_NODENAME}'], - 'volumes': ['/substra/backup/rabbit-data:/var/lib/rabbitmq'] - }, - }, - 'path': os.path.join(dir_path, './docker-compose-dynamic.yaml')} + docker_compose = { + 'substrabac_services': {}, + 'substrabac_tools': { + 'postgresql': { + 'container_name': 'postgresql', + 'image': 'library/postgres:10.5', + 'restart': 'unless-stopped', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': [ + f'POSTGRES_USER={POSTGRES_USER}', + f'USER={USER}', + f'POSTGRES_PASSWORD={POSTGRES_PASSWORD}', + f'POSTGRES_DB={POSTGRES_DB}'], + 'volumes': [ + '/substra/backup/postgres-data:/var/lib/postgresql/data', + f'{dir_path}/postgresql/init.sh:/docker-entrypoint-initdb.d/init.sh'], + }, + 'celerybeat': { + 'container_name': 'celerybeat', + 'hostname': 'celerybeat', + 'image': 'substra/celerybeat', + 'restart': 'unless-stopped', + 'command': '/bin/bash -c "while ! { nc -z rabbit 5672 2>&1; }; do sleep 1; done; ' + 'while ! { nc -z postgresql 5432 2>&1; }; do sleep 1; done; ' + 'celery -A substrabac beat -l info"', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': [ + 'PYTHONUNBUFFERED=1', + f'CELERY_BROKER_URL={CELERY_BROKER_URL}', + f'DJANGO_SETTINGS_MODULE=substrabac.settings.common'], + 'depends_on': ['postgresql', 'rabbit'] + }, + 'rabbit': { + 'container_name': 'rabbit', + 'hostname': 'rabbitmq', # Must be set to be able to recover from volume + 'restart': 'unless-stopped', + 'image': 'rabbitmq:3', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': [ + f'RABBITMQ_DEFAULT_USER={RABBITMQ_DEFAULT_USER}', + f'RABBITMQ_DEFAULT_PASS={RABBITMQ_DEFAULT_PASS}', + f'HOSTNAME={RABBITMQ_HOSTNAME}', + f'RABBITMQ_NODENAME={RABBITMQ_NODENAME}'], + 'volumes': ['/substra/backup/rabbit-data:/var/lib/rabbitmq'] + }, + }, + 'path': os.path.join(dir_path, './docker-compose-dynamic.yaml')} for org in conf: org_name = org['name'] @@ -97,10 +107,13 @@ def generate_docker_compose_file(conf, launch_settings): processes = 2 * int(cpu_count) + 1 if launch_settings == 'prod': - django_server = f'python3 manage.py collectstatic --noinput; DJANGO_SETTINGS_MODULE=substrabac.settings.events.prod uwsgi --http :{port} --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes {processes} --threads 2' + django_server = f'python3 manage.py collectstatic --noinput; '\ + f'DJANGO_SETTINGS_MODULE=substrabac.settings.events.prod uwsgi --http :{port} ' \ + f'--module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics ' \ + f'--master --processes {processes} --threads 2' else: - - django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.events.dev python3 manage.py runserver 0.0.0.0:{port}' + django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.events.dev ' \ + f'python3 manage.py runserver 0.0.0.0:{port}' backend_global_env = [ f'ORG={org_name_stripped}', @@ -131,53 +144,70 @@ def generate_docker_compose_file(conf, launch_settings): f'{org["core_peer_mspconfigpath"]}:{org["core_peer_mspconfigpath"]}:ro', ] - backend = {'container_name': f'{org_name_stripped}.substrabac', - 'image': 'substra/substrabac', - 'restart': 'unless-stopped', - 'ports': [f'{port}:{port}'], - 'command': f'/bin/bash -c "while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; yes | python manage.py migrate; {django_server}"', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': backend_global_env.copy(), - 'volumes': ['/substra/medias:/substra/medias', - '/substra/dryrun:/substra/dryrun', - '/substra/servermedias:/substra/servermedias', - '/substra/static:/usr/src/app/substrabac/statics'] + hlf_volumes, - 'depends_on': ['postgresql', 'rabbit']} - - scheduler = {'container_name': f'{org_name_stripped}.scheduler', - 'hostname': f'{org_name}.scheduler', - 'image': 'substra/celeryworker', - 'restart': 'unless-stopped', - 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; celery -A substrabac worker -l info -n {org_name_stripped} -Q {org_name},scheduler,celery --hostname {org_name}.scheduler"', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': backend_global_env.copy(), - 'volumes': hlf_volumes, - 'depends_on': [f'substrabac{org_name_stripped}', 'postgresql', 'rabbit']} - - worker = {'container_name': f'{org_name_stripped}.worker', - 'hostname': f'{org_name}.worker', - 'image': 'substra/celeryworker', - 'restart': 'unless-stopped', - 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; celery -A substrabac worker -l info -n {org_name_stripped} -Q {org_name},{org_name}.worker,celery --hostname {org_name}.worker"', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': backend_global_env.copy(), - 'volumes': ['/var/run/docker.sock:/var/run/docker.sock', - '/substra/medias:/substra/medias', - '/substra/servermedias:/substra/servermedias'] + hlf_volumes, - 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} - - dryrunner = {'container_name': f'{org_name_stripped}.dryrunner', - 'hostname': f'{org_name}.dryrunner', - 'image': 'substra/celeryworker', - 'restart': 'unless-stopped', - 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; celery -A substrabac worker -l info -n {org_name_stripped} -Q {org_name},{org_name}.dryrunner,celery --hostname {org_name}.dryrunner"', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': backend_global_env.copy(), - 'volumes': ['/var/run/docker.sock:/var/run/docker.sock', - '/substra/dryrun:/substra/dryrun', - '/substra/medias:/substra/medias', - '/substra/servermedias:/substra/servermedias'] + hlf_volumes, - 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} + backend = { + 'container_name': f'{org_name_stripped}.substrabac', + 'image': 'substra/substrabac', + 'restart': 'unless-stopped', + 'ports': [f'{port}:{port}'], + 'command': f'/bin/bash -c "while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; ' + f'yes | python manage.py migrate; {django_server}"', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': backend_global_env.copy(), + 'volumes': [ + '/substra/medias:/substra/medias', + '/substra/dryrun:/substra/dryrun', + '/substra/servermedias:/substra/servermedias', + '/substra/static:/usr/src/app/substrabac/statics'] + hlf_volumes, + 'depends_on': ['postgresql', 'rabbit']} + + scheduler = { + 'container_name': f'{org_name_stripped}.scheduler', + 'hostname': f'{org_name}.scheduler', + 'image': 'substra/celeryworker', + 'restart': 'unless-stopped', + 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; ' + f'while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; ' + f'celery -A substrabac worker -l info -n {org_name_stripped} ' + f'-Q {org_name},scheduler,celery --hostname {org_name}.scheduler"', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': backend_global_env.copy(), + 'volumes': hlf_volumes, + 'depends_on': [f'substrabac{org_name_stripped}', 'postgresql', 'rabbit']} + + worker = { + 'container_name': f'{org_name_stripped}.worker', + 'hostname': f'{org_name}.worker', + 'image': 'substra/celeryworker', + 'restart': 'unless-stopped', + 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; ' + f'while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; ' + f'celery -A substrabac worker -l info -n {org_name_stripped} ' + f'-Q {org_name},{org_name}.worker,celery --hostname {org_name}.worker"', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': backend_global_env.copy(), + 'volumes': [ + '/var/run/docker.sock:/var/run/docker.sock', + '/substra/medias:/substra/medias', + '/substra/servermedias:/substra/servermedias'] + hlf_volumes, + 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} + + dryrunner = { + 'container_name': f'{org_name_stripped}.dryrunner', + 'hostname': f'{org_name}.dryrunner', + 'image': 'substra/celeryworker', + 'restart': 'unless-stopped', + 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; ' + f'while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; ' + f'celery -A substrabac worker -l info -n {org_name_stripped} ' + f'-Q {org_name},{org_name}.dryrunner,celery --hostname {org_name}.dryrunner"', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': backend_global_env.copy(), + 'volumes': [ + '/var/run/docker.sock:/var/run/docker.sock', + '/substra/dryrun:/substra/dryrun', + '/substra/medias:/substra/medias', + '/substra/servermedias:/substra/servermedias'] + hlf_volumes, + 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} # Check if we have nvidia docker if 'nvidia' in check_output(['docker', 'system', 'info', '-f', '"{{.Runtimes}}"']).decode('utf-8'): diff --git a/fixtures/isic_2018.py b/fixtures/isic_2018.py index e76b84bf3..1b1a923fc 100644 --- a/fixtures/isic_2018.py +++ b/fixtures/isic_2018.py @@ -3,15 +3,14 @@ from subprocess import PIPE, Popen as popen import time -from django.conf import settings - dir_path = os.path.dirname(os.path.realpath(__file__)) # Use substra shell SDK try: popen(['substra'], stdout=PIPE).communicate()[0] -except: - print('Substrabac SDK is not installed, please run pip install git+https://github.com/SubstraFoundation/substrabacSDK.git@master') +except BaseException: + print('Substrabac SDK is not installed, please run pip install ' + 'git+https://github.com/SubstraFoundation/substrabacSDK.git@master') else: print('Init config in /tmp/.substrabac for owkin and chunantes') username = "owkestra" @@ -19,7 +18,9 @@ auth = [] if username is not None and password is not None: auth = [username, password] - res = popen(['substra', 'config', 'https://substra.owkin.com:9000', '0.0', '--profile=owkin', '--config=/tmp/.substrabac'] + auth, stdout=PIPE).communicate()[0] + res = popen(['substra', 'config', 'https://substra.owkin.com:9000', '0.0', + '--profile=owkin', '--config=/tmp/.substrabac'] + auth, + stdout=PIPE).communicate()[0] print('create data manager with owkin org') # create data manager with owkin org @@ -27,7 +28,8 @@ "name": "ISIC 2018", "data_opener": "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/dataset/isic2018/opener.py", "type": "Images", - "description": "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/dataset/isic2018/description.md", + "description": + "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/dataset/isic2018/description.md", "permissions": "all", "challenge_keys": [] }) @@ -39,7 +41,6 @@ print(json.dumps(res_data, indent=2)) # Register Data on substrabac docker - # python3 manage.py bulkcreatedata /substra/datasets/isic2018/train_data.json; python3 manage.py bulkcreatedata /substra/datasets/isic2018/test_data.json print('You have to register data manually') input("When it is done, press Enter to continue...") diff --git a/populate.py b/populate.py index 6e5bffe70..20cb01706 100644 --- a/populate.py +++ b/populate.py @@ -298,8 +298,6 @@ def do_populate(): testtuple_key = get_or_create(data, org_1, 'testtuple') - - client.set_config(org_1) res_t = client.get('testtuple', testtuple_key) print(colored(json.dumps(res_t, indent=2), 'yellow')) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 0938d402a..d49068bca 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -92,7 +92,7 @@ def wait(): key_path=glob.glob(requestor_config['key_path'])[0], cert_path=requestor_config['cert_path'] ) - except: + except BaseException: pass else: channel_event_hub = channel.newChannelEventHub(target_peer, diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 36fbf1dbf..35f49ce0d 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -10,7 +10,8 @@ https://docs.djangoproject.com/en/2.0/ref/settings/ """ -import os, sys +import os +import sys from libs.gen_secret_key import write_secret_key # Build paths inside the project like this: os.path.join(BASE_DIR, ...) diff --git a/substrabac/substrabac/settings/deps/raven.py b/substrabac/substrabac/settings/deps/raven.py index 74d4479f1..a3f847886 100644 --- a/substrabac/substrabac/settings/deps/raven.py +++ b/substrabac/substrabac/settings/deps/raven.py @@ -3,6 +3,6 @@ from sentry_sdk.integrations.django import DjangoIntegration sentry_sdk.init( - dsn=os.environ.get('RAVEN_URL', "https://cff352ba26fc49f19e01692db93bf951@sentry.io/1317743"), # Default to substrabac raven + dsn=os.environ.get("RAVEN_URL", "https://cff352ba26fc49f19e01692db93bf951@sentry.io/1317743"), integrations=[DjangoIntegration()] ) diff --git a/substrabac/substrabac/settings/test.py b/substrabac/substrabac/settings/test.py index b81d8db16..5456b2ff0 100644 --- a/substrabac/substrabac/settings/test.py +++ b/substrabac/substrabac/settings/test.py @@ -1,4 +1,4 @@ -from .common import * +from .common import * # noqa -from .deps.restframework import * -from .deps.cors import * +from .deps.restframework import * # noqa +from .deps.cors import * # noqa diff --git a/substrabac/substrabac/views.py b/substrabac/substrabac/views.py index 6fecb285b..727060cf7 100644 --- a/substrabac/substrabac/views.py +++ b/substrabac/substrabac/views.py @@ -49,7 +49,7 @@ def get_link(self, path, method, view): if len(a) == 2: try: yaml_doc = yaml.load(a[1]) - except: + except BaseException: pass else: if 'desc' in yaml_doc: diff --git a/substrabac/substrapp/management/commands/bulkcreatedatasample.py b/substrabac/substrapp/management/commands/bulkcreatedatasample.py index d1dd6d2fb..ff43f6b60 100644 --- a/substrabac/substrapp/management/commands/bulkcreatedatasample.py +++ b/substrabac/substrapp/management/commands/bulkcreatedatasample.py @@ -28,7 +28,8 @@ def __init__(self, msg, data): # check if not already in data sample list def check(file_or_path, pkhash, data_sample): - err_msg = 'Your data sample archives/paths contain same files leading to same pkhash, please review the content of your achives/paths. %s and %s are the same' + err_msg = 'Your data sample archives/paths contain same files leading to same pkhash, ' \ + 'please review the content of your achives/paths. %s and %s are the same' for x in data_sample: if pkhash == x['pkhash']: if 'file' in x: @@ -101,7 +102,7 @@ def bulk_create_data_sample(data): class Command(BaseCommand): - help = ''' + help = ''' # noqa Bulk create data sample paths is a list of archives or paths to directories python ./manage.py bulkcreatedatasample '{"paths": ["./data1.zip", "./data2.zip", "./train/data", "./train/data2"], "data_manager_keys": ["9a832ed6cee6acf7e33c3acffbc89cebf10ef503b690711bdee048b873daf528"], "test_only": false}' @@ -119,11 +120,11 @@ def handle(self, *args, **options): args = options['data'] try: data = json.loads(args) - except: + except Exception: try: with open(args, 'r') as f: data = json.load(f) - except: + except Exception: raise CommandError('Invalid args. Please review help') else: if not isinstance(data, dict): @@ -145,5 +146,6 @@ def handle(self, *args, **options): except Exception as e: self.stderr.write(str(e)) else: - msg = f'Successfully added data samples via bulk with status code {st} and data: {json.dumps(res, indent=4)}' + msg = f'Successfully added data samples via bulk with status code {st} and data: ' \ + f'{json.dumps(res, indent=4)}' self.stdout.write(self.style.SUCCESS(msg)) diff --git a/substrabac/substrapp/management/commands/createdataset.py b/substrabac/substrapp/management/commands/createdataset.py index c159dcf2d..a18a8cfdb 100644 --- a/substrabac/substrapp/management/commands/createdataset.py +++ b/substrabac/substrapp/management/commands/createdataset.py @@ -19,7 +19,7 @@ def path_leaf(path): class Command(BaseCommand): - help = ''' + help = ''' # noqa create dataset python ./manage.py createdataset '{"data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo", "objective_keys": []}, "data_samples": {"paths": ["./data.zip", "./train/data"], "test_only": false}}' python ./manage.py createdataset dataset.json @@ -37,11 +37,11 @@ def handle(self, *args, **options): args = options['data_input'] try: data_input = json.loads(args) - except: + except Exception: try: with open(args, 'r') as f: data_input = json.load(f) - except: + except Exception: raise CommandError('Invalid args. Please review help') else: if not isinstance(data_input, dict): @@ -98,7 +98,7 @@ def handle(self, *args, **options): # init ledger serializer ledger_serializer = LedgerDataManagerSerializer( data={'name': data_manager['name'], - 'permissions': 'all', # forced, TODO changed when permissions are available + 'permissions': 'all', # forced, TODO changed when permissions are available 'type': data_manager['type'], 'objective_keys': data_manager.get('objective_keys', []), 'instance': instance}, @@ -120,7 +120,8 @@ def handle(self, *args, **options): else: d = dict(serializer.data) d.update(res) - msg = f'Successfully added datamanager with status code {st} and result: {json.dumps(res, indent=4)}' + msg = f'Successfully added datamanager with status code {st} and result: ' \ + f'{json.dumps(res, indent=4)}' self.stdout.write(self.style.SUCCESS(msg)) # Try to add data even if datamanager creation failed diff --git a/substrabac/substrapp/management/commands/createobjective.py b/substrabac/substrapp/management/commands/createobjective.py index b50f62353..f5b2e8ea0 100644 --- a/substrabac/substrapp/management/commands/createobjective.py +++ b/substrabac/substrapp/management/commands/createobjective.py @@ -5,11 +5,10 @@ from django.core.management.base import BaseCommand, CommandError from rest_framework import status -from substrapp.management.commands.bulkcreatedatasample import \ - bulk_create_data_sample, InvalidException +from substrapp.management.commands.bulkcreatedatasample import bulk_create_data_sample, InvalidException from substrapp.management.utils.localRequest import LocalRequest -from substrapp.serializers import DataManagerSerializer, LedgerDataManagerSerializer, \ - LedgerObjectiveSerializer, ObjectiveSerializer +from substrapp.serializers import (DataManagerSerializer, LedgerDataManagerSerializer, + LedgerObjectiveSerializer, ObjectiveSerializer) from substrapp.utils import get_hash from substrapp.views.datasample import LedgerException @@ -20,7 +19,7 @@ def path_leaf(path): class Command(BaseCommand): - help = ''' + help = ''' # noqa create objective python ./manage.py createobjective '{"objective": {"name": "foo", "metrics_name": "accuracy", "metrics": "./metrics.py", "description": "./description.md"}, "data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo"}, "data_samples": {"paths": ["./data.zip", "./train/data"]}}' python ./manage.py createobjective objective.json @@ -37,11 +36,11 @@ def handle(self, *args, **options): args = options['data_input'] try: data_input = json.loads(args) - except: + except Exception: try: with open(args, 'r') as f: data_input = json.load(f) - except: + except Exception: raise CommandError('Invalid args. Please review help') else: if not isinstance(data_input, dict): @@ -120,7 +119,7 @@ def handle(self, *args, **options): # init ledger serializer ledger_serializer = LedgerDataManagerSerializer( data={'name': data_manager['name'], - 'permissions': 'all', # forced, TODO changed when permissions are available + 'permissions': 'all', 'type': data_manager['type'], 'instance': instance}, context={'request': LocalRequest()}) @@ -140,7 +139,8 @@ def handle(self, *args, **options): else: d = dict(serializer.data) d.update(res) - msg = f'Successfully added datamanager with status code {st} and result: {json.dumps(res, indent=4)}' + msg = f'Successfully added datamanager with status code {st} and result: ' \ + f'{json.dumps(res, indent=4)}' self.stdout.write(self.style.SUCCESS(msg)) # Try to add data even if datamanager creation failed @@ -162,7 +162,8 @@ def handle(self, *args, **options): except Exception as e: self.stderr.write(str(e)) else: - msg = f'Successfully bulk added data samples with status code {st} and result: {json.dumps(res_data, indent=4)}' + msg = f'Successfully bulk added data samples with status code {st} and result: ' \ + f'{json.dumps(res_data, indent=4)}' self.stdout.write(self.style.SUCCESS(msg)) data_sample_pkhashes = [x['pkhash'] for x in res_data] @@ -228,5 +229,6 @@ def handle(self, *args, **options): else: d = dict(serializer.data) d.update(res) - msg = f'Successfully added objective with status code {st} and result: {json.dumps(res, indent=4)}' + msg = f'Successfully added objective with status code {st} and result: ' \ + f'{json.dumps(res, indent=4)}' self.stdout.write(self.style.SUCCESS(msg)) diff --git a/substrabac/substrapp/models/objective.py b/substrabac/substrapp/models/objective.py index fd4685539..69c6dcc5d 100644 --- a/substrabac/substrapp/models/objective.py +++ b/substrabac/substrapp/models/objective.py @@ -12,8 +12,8 @@ class Objective(TimeStamped): """Storage Objective table""" pkhash = models.CharField(primary_key=True, max_length=64, blank=True) validated = models.BooleanField(default=False, blank=True) - description = models.FileField(upload_to=upload_to, max_length=500, blank=True, null=True) # path max length to 500 instead of default 100 - metrics = models.FileField(upload_to=upload_to, max_length=500, blank=True, null=True) # path max length to 500 instead of default 100 + description = models.FileField(upload_to=upload_to, max_length=500, blank=True, null=True) + metrics = models.FileField(upload_to=upload_to, max_length=500, blank=True, null=True) def save(self, *args, **kwargs): """Use hash of description file as primary key""" diff --git a/substrabac/substrapp/serializers/algo.py b/substrabac/substrapp/serializers/algo.py index 19b1cc02c..e4a2e82d0 100644 --- a/substrabac/substrapp/serializers/algo.py +++ b/substrabac/substrapp/serializers/algo.py @@ -13,10 +13,10 @@ @deconstructible class FileValidator(object): error_messages = { - 'open': ("Cannot handle this file object."), - 'compressed': ("Ensure this file is an archive (zip or tar.* compressed file)."), - 'docker': ("Ensure your archive contains a Dockerfile."), - 'file': ("Ensure your archive contains at least one algo file (for instance algo.py)."), + 'open': ("Cannot handle this file object."), + 'compressed': ("Ensure this file is an archive (zip or tar.* compressed file)."), + 'docker': ("Ensure your archive contains a Dockerfile."), + 'file': ("Ensure your archive contains at least one algo file (for instance algo.py)."), } def validate_archive(self, files): @@ -31,7 +31,7 @@ def __call__(self, data): archive = None try: data.file.seek(0) - except: + except Exception: raise ValidationError(self.error_messages['open']) else: try: diff --git a/substrabac/substrapp/serializers/datasample.py b/substrabac/substrapp/serializers/datasample.py index 5a99d84e1..1f3b974d6 100644 --- a/substrabac/substrapp/serializers/datasample.py +++ b/substrabac/substrapp/serializers/datasample.py @@ -4,7 +4,6 @@ from django.core.exceptions import ValidationError from django.core.files import File -from django.core.files.uploadedfile import InMemoryUploadedFile from rest_framework import serializers from rest_framework.serializers import raise_errors_on_nested_writes from rest_framework.utils import model_meta @@ -26,7 +25,7 @@ def __call__(self, data): try: data.file.seek(0) - except: + except Exception: raise ValidationError(self.error_messages['open']) else: try: diff --git a/substrabac/substrapp/serializers/ledger/algo/serializer.py b/substrabac/substrapp/serializers/ledger/algo/serializer.py index 1d3ad8962..456c28168 100644 --- a/substrabac/substrapp/serializers/ledger/algo/serializer.py +++ b/substrabac/substrapp/serializers/ledger/algo/serializer.py @@ -23,7 +23,7 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = '' if request is None else request.get_host() - # args = '"%(name)s", "%(algoHash)s", "%(storageAddress)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(permissions)s"' % { + # args = '"%(name)s", "%(algoHash)s", "%(storageAddress)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(permissions)s"' % { # noqa # 'name': name, # 'algoHash': get_hash(instance.file), # 'storageAddress': protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), @@ -45,7 +45,8 @@ def create(self, validated_data): # use a celery task, as we are in an http request transaction createLedgerAlgoAsync.delay(args, instance.pkhash) data = { - 'message': 'Algo added in local db waiting for validation. The substra network has been notified for adding this Algo' + 'message': 'Algo added in local db waiting for validation. ' + 'The substra network has been notified for adding this Algo' } st = status.HTTP_202_ACCEPTED return data, st diff --git a/substrabac/substrapp/serializers/ledger/algo/util.py b/substrabac/substrapp/serializers/ledger/algo/util.py index 486f86343..7add6d6aa 100644 --- a/substrabac/substrapp/serializers/ledger/algo/util.py +++ b/substrabac/substrapp/serializers/ledger/algo/util.py @@ -12,7 +12,7 @@ def createLedgerAlgo(args, pkhash, sync=False): # if not created on ledger, delete from local db, else pass to validated true try: instance = Algo.objects.get(pk=pkhash) - except: + except Exception: pass else: if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py index 9d7417f87..b89280264 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py @@ -27,13 +27,13 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = '' if request is None else request.get_host() - # args = '"%(name)s", "%(openerHash)s", "%(openerStorageAddress)s", "%(type)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(objectiveKey)s", "%(permissions)s"' % { + # args = '"%(name)s", "%(openerHash)s", "%(openerStorageAddress)s", "%(type)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(objectiveKey)s", "%(permissions)s"' % { # noqa # 'name': name, # 'openerHash': get_hash(instance.data_opener), # 'openerStorageAddress': protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), # 'type': type, # 'descriptionHash': get_hash(instance.description), - # 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), + # 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), # noqa # 'objectiveKey': objective_key, # 'permissions': permissions # } @@ -56,7 +56,8 @@ def create(self, validated_data): createLedgerDataManagerAsync.delay(args, instance.pkhash) data = { - 'message': 'DataManager added in local db waiting for validation. The substra network has been notified for adding this DataManager' + 'message': 'DataManager added in local db waiting for validation. ' + 'The substra network has been notified for adding this DataManager' } st = status.HTTP_202_ACCEPTED return data, st diff --git a/substrabac/substrapp/serializers/ledger/datamanager/tasks.py b/substrabac/substrapp/serializers/ledger/datamanager/tasks.py index 87ff92843..d808c0083 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/tasks.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/tasks.py @@ -8,6 +8,7 @@ def createLedgerDataManagerAsync(args, pkhash): return createLedgerDataManager(args, pkhash) + @shared_task def updateLedgerDataManagerAsync(args): return updateLedgerDataManager(args) diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substrabac/substrapp/serializers/ledger/datamanager/util.py index a607cbaed..8ee5ffc5c 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/util.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/util.py @@ -12,7 +12,7 @@ def createLedgerDataManager(args, pkhash, sync=False): # if not created on ledger, delete from local db, else pass to validated true try: instance = DataManager.objects.get(pk=pkhash) - except: + except Exception: pass else: if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): diff --git a/substrabac/substrapp/serializers/ledger/datasample/serializer.py b/substrabac/substrapp/serializers/ledger/datasample/serializer.py index 23fb6c56b..f92dd6e47 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datasample/serializer.py @@ -36,7 +36,8 @@ def create(self, validated_data): # use a celery task, as we are in an http request transaction createLedgerDataSampleAsync.delay(args, [x.pk for x in instances]) data = { - 'message': 'Data samples added in local db waiting for validation. The substra network has been notified for adding this Data' + 'message': 'Data samples added in local db waiting for validation. ' + 'The substra network has been notified for adding this Data' } st = status.HTTP_202_ACCEPTED return data, st diff --git a/substrabac/substrapp/serializers/ledger/datasample/tasks.py b/substrabac/substrapp/serializers/ledger/datasample/tasks.py index 51dfe0f52..f82a2b7ea 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/tasks.py +++ b/substrabac/substrapp/serializers/ledger/datasample/tasks.py @@ -8,6 +8,7 @@ def createLedgerDataSampleAsync(args, pkhashes): return createLedgerDataSample(args, pkhashes) + @shared_task def updateLedgerDataSampleAsync(args): return updateLedgerDataSample(args) diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substrabac/substrapp/serializers/ledger/datasample/util.py index 1d6a776f4..9725aa985 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/util.py +++ b/substrabac/substrapp/serializers/ledger/datasample/util.py @@ -11,7 +11,7 @@ def createLedgerDataSample(args, pkhashes, sync=False): # if not created on ledger, delete from local db, else pass to validated true try: instances = DataSample.objects.filter(pk__in=pkhashes) - except: + except Exception: pass else: diff --git a/substrabac/substrapp/serializers/ledger/objective/serializer.py b/substrabac/substrapp/serializers/ledger/objective/serializer.py index 02cbd6eba..73c31757e 100644 --- a/substrabac/substrapp/serializers/ledger/objective/serializer.py +++ b/substrabac/substrapp/serializers/ledger/objective/serializer.py @@ -31,10 +31,10 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = '' if request is None else request.get_host() - # args = '"%(name)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(metricsName)s", "%(metricsHash)s", "%(metricsStorageAddress)s", "%(testDataSample)s", "%(permissions)s"' % { + # args = '"%(name)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(metricsName)s", "%(metricsHash)s", "%(metricsStorageAddress)s", "%(testDataSample)s", "%(permissions)s"' % { # noqa # 'name': name, # 'descriptionHash': get_hash(instance.description), - # 'descriptionStorageAddress': protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), + # 'descriptionStorageAddress': protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), # noqa # 'metricsName': metrics_name, # 'metricsHash': get_hash(instance.metrics), # 'metricsStorageAddress': protocol + host + reverse('substrapp:objective-metrics', args=[instance.pk]), @@ -59,7 +59,8 @@ def create(self, validated_data): # use a celery task, as we are in an http request transaction createLedgerObjectiveAsync.delay(args, instance.pkhash) data = { - 'message': 'Objective added in local db waiting for validation. The substra network has been notified for adding this Objective' + 'message': 'Objective added in local db waiting for validation. ' + 'The substra network has been notified for adding this Objective' } st = status.HTTP_202_ACCEPTED return data, st diff --git a/substrabac/substrapp/serializers/ledger/objective/util.py b/substrabac/substrapp/serializers/ledger/objective/util.py index e7a1111e4..cf4f191ef 100644 --- a/substrabac/substrapp/serializers/ledger/objective/util.py +++ b/substrabac/substrapp/serializers/ledger/objective/util.py @@ -12,7 +12,7 @@ def createLedgerObjective(args, pkhash, sync=False): # if not created on ledger, delete from local db, else pass to validated true try: instance = Objective.objects.get(pk=pkhash) - except: + except Exception: pass else: if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): diff --git a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py index 56e94e7d3..7a0e4ac93 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py @@ -46,7 +46,9 @@ def create(self, validated_data): createLedgerTesttupleAsync.delay(args) data = { - 'message': 'The substra network has been notified for adding this Testtuple. Please be aware you won\'t get return values from the ledger. You will need to check manually' + 'message': 'The substra network has been notified for adding this Testtuple. ' + 'Please be aware you won\'t get return values from the ledger. ' + 'You will need to check manually' } st = status.HTTP_202_ACCEPTED return data, st diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index 5f351c082..4cd372f7b 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -31,7 +31,7 @@ def get_args(self, validated_data): in_models_keys = validated_data.get('in_models_keys') tag = validated_data.get('tag', '') - # args = '"%(algoKey)s", "%(associatedObjective)s", "%(inModels)s", "%(dataManagerKey)s", "%(dataSampleKeys)s", "%(FLtask)s", "%(rank)s", "%(tag)s"' % { + # args = '"%(algoKey)s", "%(associatedObjective)s", "%(inModels)s", "%(dataManagerKey)s", "%(dataSampleKeys)s", "%(FLtask)s", "%(rank)s", "%(tag)s"' % { # noqa # 'algoKey': algo_key, # 'associatedObjective': objective_key, # 'inModels': ','.join(in_models_keys), @@ -65,7 +65,9 @@ def create(self, validated_data): createLedgerTraintupleAsync.delay(args) data = { - 'message': 'The substra network has been notified for adding this Traintuple. Please be aware you won\'t get return values from the ledger. You will need to check manually' + 'message': 'The substra network has been notified for adding this Traintuple. ' + 'Please be aware you won\'t get return values from the ledger. ' + 'You will need to check manually' } st = status.HTTP_202_ACCEPTED return data, st diff --git a/substrabac/substrapp/signals/datasample/pre_save.py b/substrabac/substrapp/signals/datasample/pre_save.py index 92d4bee10..5ef1df5ab 100644 --- a/substrabac/substrapp/signals/datasample/pre_save.py +++ b/substrabac/substrapp/signals/datasample/pre_save.py @@ -7,7 +7,7 @@ from django.conf import settings from django.core.files import File -from substrapp.utils import uncompress_content, create_directory +from substrapp.utils import uncompress_content def create_hard_links(base_dir, directory): @@ -53,7 +53,7 @@ def data_sample_pre_save(sender, instance, **kwargs): try: p = normpath(instance.path) create_hard_links(p, directory) - except Exception as e: + except Exception: pass else: # override path for getting our hardlink diff --git a/substrabac/substrapp/tasks/exception_handler.py b/substrabac/substrapp/tasks/exception_handler.py index d1d59c9b1..888a572a6 100644 --- a/substrabac/substrapp/tasks/exception_handler.py +++ b/substrabac/substrapp/tasks/exception_handler.py @@ -22,7 +22,7 @@ if os.path.exists(EXCEPTION_PATH): try: EXCEPTIONS_MAP = json.load(open(EXCEPTION_PATH)) - except: + except Exception: # The json may be corrupted EXCEPTIONS_MAP = dict() else: diff --git a/substrabac/substrapp/tasks/generate_exceptions_map.py b/substrabac/substrapp/tasks/generate_exceptions_map.py index e80438b90..3775d8cac 100644 --- a/substrabac/substrapp/tasks/generate_exceptions_map.py +++ b/substrabac/substrapp/tasks/generate_exceptions_map.py @@ -6,9 +6,16 @@ # Modules to inspect os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabac.settings.prod' -import docker.errors, requests.exceptions, celery.exceptions, tarfile, \ - django.core.exceptions, django.urls, django.db, django.http, django.db.transaction,\ - rest_framework.exceptions +import docker.errors +import requests.exceptions +import celery.exceptions +import tarfile +import django.core.exceptions +import django.urls +import django.db +import django.http +import django.db.transaction +import rest_framework.exceptions MODULES = [docker.errors, requests.exceptions, celery.exceptions, tarfile, django.core.exceptions, django.urls, django.db, django.http, django.db.transaction, diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index a0944d2dd..9b372fab4 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -31,7 +31,7 @@ def get_objective(subtuple): try: # get objective from local db objective = Objective.objects.get(pk=objectiveHash) - except: + except Exception: objective = None finally: if objective is None or not objective.metrics: @@ -88,7 +88,7 @@ def put_model(subtuple, subtuple_directory, model_content): try: model = Model.objects.get(pk=subtuple['model']['hash']) - except: # write it to local disk + except Exception: # write it to local disk with open(model_dst_path, 'wb') as f: f.write(model_content) else: @@ -111,7 +111,7 @@ def put_models(subtuple, subtuple_directory, models_content): try: model = Model.objects.get(pk=subtuple_model['hash']) - except: # write it to local disk + except Exception: # write it to local disk with open(model_dst_path, 'wb') as f: f.write(model_content) else: @@ -235,7 +235,13 @@ def prepareTuple(subtuple, tuple_type, model_type): try: # Log Start of the Subtuple - start_type = 'logStartTrain' if tuple_type == 'traintuple' else 'logStartTest' if tuple_type == 'testtuple' else None + + start_type = None + if tuple_type == 'traintuple': + start_type = 'logStartTrain' + elif tuple_type == 'testtuple': + start_type = 'logStartTest' + data, st = invokeLedger(fcn=start_type, args=[f'{subtuple["key"]}'], sync=True) @@ -255,8 +261,6 @@ def prepareTuple(subtuple, tuple_type, model_type): def prepareTask(tuple_type, model_type): - from django_celery_results.models import TaskResult - try: data_owner = get_hash(settings.LEDGER['signcert']) except Exception as e: @@ -288,7 +292,7 @@ def computeTask(self, tuple_type, subtuple, model_type, fltask): try: worker = self.request.hostname.split('@')[1] queue = self.request.delivery_info['routing_key'] - except: + except Exception: worker = f"{settings.LEDGER['name']}.worker" queue = f"{settings.LEDGER['name']}" @@ -517,7 +521,7 @@ def doTask(subtuple, tuple_type): local_volume = client.volumes.get(volume_id=flvolume) try: local_volume.remove(force=True) - except: + except Exception: logging.error(f'Cannot remove local volume {flvolume}', exc_info=True) return result diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index f4568cccc..b8bf4682f 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -89,7 +89,8 @@ def update_statistics(task_statistics, stats, gpu_stats): if 'cpu_stats' in stats and stats['cpu_stats']['cpu_usage'].get('total_usage', None): # Compute CPU usage in % - delta_total_usage = (stats['cpu_stats']['cpu_usage']['total_usage'] - stats['precpu_stats']['cpu_usage']['total_usage']) + delta_total_usage = (stats['cpu_stats']['cpu_usage']['total_usage'] - + stats['precpu_stats']['cpu_usage']['total_usage']) delta_system_usage = (stats['cpu_stats']['system_cpu_usage'] - stats['precpu_stats']['system_cpu_usage']) total_usage = (delta_total_usage / delta_system_usage) * stats['cpu_stats']['online_cpus'] * 100.0 @@ -177,7 +178,8 @@ def monitoring_task(client, task_args): t._result += f" GB - GPU:{t._stats['gpu']['max']:.2f} % - GPU Mem:{t._stats['gpu_memory']['max']:.2f} GB" -def compute_docker(client, resources_manager, dockerfile_path, image_name, container_name, volumes, command, remove_image=True): +def compute_docker(client, resources_manager, dockerfile_path, image_name, container_name, volumes, command, + remove_image=True): dockerfile_fullpath = os.path.join(dockerfile_path, 'Dockerfile') if not os.path.exists(dockerfile_fullpath): diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 94e97a30c..1ce7838b9 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -3,6 +3,7 @@ from django.core.files.uploadedfile import InMemoryUploadedFile + class gpu(): """Fake gpu""" @@ -207,7 +208,8 @@ def get_sample_tar_data_sample(): dir_path = os.path.dirname(os.path.realpath(__file__)) file_filename = "file.tar.gz" f = BytesIO() - with open(os.path.join(dir_path, '../../../fixtures/owkin/datasamples/datasample4/0024900.tar.gz'), 'rb') as tar_file: + with open(os.path.join( + dir_path, '../../../fixtures/owkin/datasamples/datasample4/0024900.tar.gz'), 'rb') as tar_file: flength = f.write(tar_file.read()) file = InMemoryUploadedFile(f, None, file_filename, diff --git a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py b/substrabac/substrapp/tests/tests_bulkcreatedatasample.py index be737949d..4772774fb 100644 --- a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py +++ b/substrabac/substrapp/tests/tests_bulkcreatedatasample.py @@ -59,12 +59,13 @@ def test_bulkcreatedatasample(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path1 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) - data_path2 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + data_path1 = os.path.normpath( + os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + data_path2 = os.path.normpath( + os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1, data_path2], 'data_manager_keys': data_manager_keys, @@ -106,7 +107,8 @@ def test_bulkcreatedatasample(self): } ] data = json.dumps(out_data, indent=4) - wanted_output = f'Successfully added data samples via bulk with status code {status.HTTP_201_CREATED} and data: {data}' + wanted_output = f'Successfully added data samples via bulk with status code ' \ + f'{status.HTTP_201_CREATED} and data: {data}' self.assertEqual(wanted_output, output) finally: sys.stdout = saved_stdout @@ -115,10 +117,11 @@ def test_bulkcreatedatasample_path(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path1 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/train/0024308')) + data_path1 = os.path.normpath( + os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/train/0024308')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1], 'data_manager_keys': data_manager_keys, @@ -160,7 +163,8 @@ def test_bulkcreatedatasample_path(self): }, ] data = json.dumps(out_data, indent=4) - wanted_output = f'Successfully added data samples via bulk with status code {status.HTTP_201_CREATED} and data: {data}' + wanted_output = f'Successfully added data samples via bulk with status code ' \ + f'{status.HTTP_201_CREATED} and data: {data}' self.assertEqual(wanted_output, output) finally: sys.stdout = saved_stdout @@ -172,7 +176,8 @@ def test_bulkcreatedatasample_original_path(self): data_path1 = os.path.normpath(os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/train/0024308')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1], 'data_manager_keys': data_manager_keys, @@ -213,7 +218,8 @@ def test_bulkcreatedatasample_original_path(self): }, ] data = json.dumps(out_data, indent=4) - wanted_output = f'Successfully added data samples via bulk with status code {status.HTTP_201_CREATED} and data: {data}' + wanted_output = f'Successfully added data samples via bulk with status code ' \ + f'{status.HTTP_201_CREATED} and data: {data}' self.assertEqual(wanted_output, output) finally: sys.stdout = saved_stdout @@ -227,7 +233,8 @@ def test_bulkcreatedatasample_path_and_files(self): data_path2 = os.path.normpath(os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1, data_path2], 'data_manager_keys': data_manager_keys, @@ -275,7 +282,8 @@ def test_bulkcreatedatasample_path_and_files(self): }, ] data = json.dumps(out_data, indent=4) - wanted_output = f'Successfully added data samples via bulk with status code {status.HTTP_201_CREATED} and data: {data}' + wanted_output = f'Successfully added data samples via bulk with status code ' \ + f'{status.HTTP_201_CREATED} and data: {data}' self.assertEqual(wanted_output, output) finally: sys.stdout = saved_stdout @@ -287,7 +295,8 @@ def test_bulkcreatedatasample_same_on_file(self): data_path1 = os.path.normpath(os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1, data_path1], 'data_manager_keys': data_manager_keys, @@ -315,7 +324,9 @@ def test_bulkcreatedatasample_same_on_file(self): output = err.getvalue().strip() - wanted_output = f'Your data sample archives/paths contain same files leading to same pkhash, please review the content of your achives/paths. {data_path1} and 0024700.zip are the same' + wanted_output = f'Your data sample archives/paths contain same files leading to same pkhash, ' \ + f'please review the content of your achives/paths. ' \ + f'{data_path1} and 0024700.zip are the same' self.assertEqual(wanted_output, output) finally: sys.stdout = saved_stdout @@ -327,7 +338,8 @@ def test_bulkcreatedatasample_same_on_path(self): data_path1 = os.path.normpath(os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/train/0024308')) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'paths': [data_path1, data_path1], 'data_manager_keys': data_manager_keys, @@ -355,7 +367,9 @@ def test_bulkcreatedatasample_same_on_path(self): output = err.getvalue().strip() - wanted_output = f'Your data sample archives/paths contain same files leading to same pkhash, please review the content of your achives/paths. {data_path1} and {data_path1} are the same' + wanted_output = f'Your data sample archives/paths contain same files leading to same pkhash, ' \ + f'please review the content of your achives/paths. ' \ + f'{data_path1} and {data_path1} are the same' self.assertEqual(wanted_output, output) finally: sys.stdout = saved_stdout @@ -416,7 +430,8 @@ def test_bulkcreatedatasample_invalid_datamanager(self): output = err.getvalue().strip() - wanted_output = "One or more datamanager keys provided do not exist in local substrabac database. Please create them before. DataManager keys: ['bar']" + wanted_output = "One or more datamanager keys provided do not exist in local substrabac database. "\ + "Please create them before. DataManager keys: ['bar']" self.assertEqual(wanted_output, output) @@ -439,7 +454,8 @@ def test_bulkcreatedatasample_not_array_datamanager(self): def test_bulkcreatedatasample_datamanager_do_not_exist(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py'))] data = {'files': ['./foo'], 'data_manager_keys': data_manager_keys, @@ -451,7 +467,8 @@ def test_bulkcreatedatasample_datamanager_do_not_exist(self): output = err.getvalue().strip() - wanted_output = f"One or more datamanager keys provided do not exist in local substrabac database. Please create them before. DataManager keys: {data_manager_keys}" + wanted_output = f"One or more datamanager keys provided do not exist in local substrabac database. " \ + f"Please create them before. DataManager keys: {data_manager_keys}" self.assertEqual(wanted_output, output) @@ -472,8 +489,8 @@ def test_bulkcreatedatasample_invalid_file(self): def test_bulkcreatedatasample_invalid_serializer(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path1 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + data_path1 = os.path.normpath( + os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) data = {'paths': [data_path1], 'data_manager_keys': [self.datamanager.pk], @@ -485,7 +502,7 @@ def test_bulkcreatedatasample_invalid_serializer(self): with patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ patch.object(os.path, 'exists') as mexists, \ patch('substrapp.management.commands.bulkcreatedatasample.open', - mock_open(read_data=self.data_sample_file.read())) as mopen, \ + mock_open(read_data=self.data_sample_file.read())), \ patch( 'substrapp.management.commands.bulkcreatedatasample.DataSampleSerializer', spec=True) as mDataSampleSerializer: @@ -519,7 +536,7 @@ def test_bulkcreatedatasample_408(self): with patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ patch.object(os.path, 'exists') as mexists, \ patch('substrapp.management.commands.bulkcreatedatasample.open', - mock_open(read_data=self.data_sample_file.read())) as mopen, \ + mock_open(read_data=self.data_sample_file.read())), \ patch( 'substrapp.management.commands.bulkcreatedatasample.DataSampleSerializer', spec=True) as mDataSampleSerializer, \ @@ -558,7 +575,7 @@ def test_bulkcreatedatasample_ledger_400(self): with patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ patch.object(os.path, 'exists') as mexists, \ patch('substrapp.management.commands.bulkcreatedatasample.open', - mock_open(read_data=self.data_sample_file.read())) as mopen, \ + mock_open(read_data=self.data_sample_file.read())), \ patch( 'substrapp.management.commands.bulkcreatedatasample.DataSampleSerializer', spec=True) as mDataSampleSerializer, \ @@ -597,7 +614,7 @@ def test_bulkcreatedatasample_400(self): with patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ patch.object(os.path, 'exists') as mexists, \ patch('substrapp.management.commands.bulkcreatedatasample.open', - mock_open(read_data=self.data_sample_file.read())) as mopen, \ + mock_open(read_data=self.data_sample_file.read())), \ patch( 'substrapp.management.commands.bulkcreatedatasample.DataSampleSerializer', spec=True) as mDataSampleSerializer, \ diff --git a/substrabac/substrapp/tests/tests_createdatamanager.py b/substrabac/substrapp/tests/tests_createdatamanager.py index 13d083038..d6f4cc1bf 100644 --- a/substrabac/substrapp/tests/tests_createdatamanager.py +++ b/substrabac/substrapp/tests/tests_createdatamanager.py @@ -35,15 +35,15 @@ def test_createdatamanager(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path1 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) - data_path2 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + data_path1 = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + data_path2 = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) - datamanager_opener_path = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) - datamanager_description_path = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) + datamanager_opener_path = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) + datamanager_description_path = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) data = { 'data_manager': { @@ -68,15 +68,13 @@ def test_createdatamanager(self): 'substrapp.views.datasample.DataSampleViewSet.check_datamanagers') as mcheck_datamanagers: mdatamanagercreate.return_value = ({ - 'pkhash': datamanager_pk, - 'validated': True - }, - status.HTTP_201_CREATED) + 'pkhash': datamanager_pk, + 'validated': True + }, status.HTTP_201_CREATED) mdatacreate.return_value = ({ - 'pkhash': [pkhash1, pkhash2], - 'validated': True - }, - status.HTTP_201_CREATED) + 'pkhash': [pkhash1, pkhash2], + 'validated': True + }, status.HTTP_201_CREATED) mcheck_datamanagers.return_value = True saved_stdout = sys.stdout @@ -89,9 +87,9 @@ def test_createdatamanager(self): output = out.getvalue().strip() datamanager_out = { - "pkhash": datamanager_pk, - "validated": True - } + "pkhash": datamanager_pk, + "validated": True + } data_out = [ { @@ -108,9 +106,12 @@ def test_createdatamanager(self): datamanager = json.dumps(datamanager_out, indent=4) data = json.dumps(data_out, indent=4) - datamanager_wanted_output = f'Successfully added datamanager with status code {status.HTTP_201_CREATED} and result: {datamanager}' - data_wanted_output = f'Successfully bulk added data samples with status code {status.HTTP_201_CREATED} and result: {data}' - self.assertEqual(output, f'{datamanager_wanted_output}\nWill add data to this datamanager now\n{data_wanted_output}') + datamanager_wanted_output = f'Successfully added datamanager with status code ' \ + f'{status.HTTP_201_CREATED} and result: {datamanager}' + data_wanted_output = f'Successfully bulk added data samples with status code ' \ + f'{status.HTTP_201_CREATED} and result: {data}' + self.assertEqual(output, f'{datamanager_wanted_output}\nWill add data to this datamanager now' + f'\n{data_wanted_output}') finally: sys.stdout = saved_stdout @@ -118,15 +119,15 @@ def test_createdatamanager_ko_409(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path1 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) - data_path2 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + data_path1 = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + data_path2 = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) - datamanager_opener_path = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) - datamanager_description_path = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) + datamanager_opener_path = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) + datamanager_description_path = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) data = { 'data_manager': { @@ -150,14 +151,12 @@ def test_createdatamanager_ko_409(self): 'substrapp.views.datasample.DataSampleViewSet.check_datamanagers') as mcheck_datamanagers: mdatamanagercreate.return_value = ({ - 'message': 'datamanager already exists', - }, - status.HTTP_409_CONFLICT) + 'message': 'datamanager already exists', + }, status.HTTP_409_CONFLICT) mdatacreate.return_value = ({ - 'pkhash': [pkhash1, pkhash2], - 'validated': True - }, - status.HTTP_201_CREATED) + 'pkhash': [pkhash1, pkhash2], + 'validated': True + }, status.HTTP_201_CREATED) mcheck_datamanagers.return_value = True saved_stdout = sys.stdout @@ -173,8 +172,8 @@ def test_createdatamanager_ko_409(self): err_output = err.getvalue().strip() datamanager_out = { - "message": 'datamanager already exists', - } + "message": 'datamanager already exists', + } data_out = [ { @@ -191,7 +190,8 @@ def test_createdatamanager_ko_409(self): datamanager = json.dumps(datamanager_out, indent=2) data = json.dumps(data_out, indent=4) - data_wanted_output = f'Successfully bulk added data samples with status code {status.HTTP_201_CREATED} and result: {data}' + data_wanted_output = f'Successfully bulk added data samples with status code ' \ + f'{status.HTTP_201_CREATED} and result: {data}' self.assertEqual(output, f'Will add data to this datamanager now\n{data_wanted_output}') self.assertEqual(err_output, datamanager) finally: diff --git a/substrabac/substrapp/tests/tests_createobjective.py b/substrabac/substrapp/tests/tests_createobjective.py index de3297e17..be2b38a28 100644 --- a/substrabac/substrapp/tests/tests_createobjective.py +++ b/substrabac/substrapp/tests/tests_createobjective.py @@ -35,19 +35,19 @@ def test_createobjective(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path1 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) - data_path2 = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) - - datamanager_opener_path = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) - datamanager_description_path = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) - objective_metrics_path = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/objectives/objective0/metrics.py')) - objective_description_path = os.path.normpath(os.path.join(dir_path, - '../../../fixtures/chunantes/objectives/objective0/description.md')) + data_path1 = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip')) + data_path2 = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip')) + + datamanager_opener_path = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py')) + datamanager_description_path = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/description.md')) + objective_metrics_path = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/objectives/objective0/metrics.py')) + objective_description_path = os.path.normpath(os.path.join( + dir_path, '../../../fixtures/chunantes/objectives/objective0/description.md')) data = { 'objective': { @@ -79,20 +79,17 @@ def test_createobjective(self): patch('substrapp.views.datasample.DataSampleViewSet.check_datamanagers') as mcheck_datamanagers: mobjectivecreate.return_value = ({ - 'pkhash': objective_pk, - 'validated': True - }, - status.HTTP_201_CREATED) + 'pkhash': objective_pk, + 'validated': True + }, status.HTTP_201_CREATED) mdatamanagercreate.return_value = ({ - 'pkhash': datamanager_pk, - 'validated': True - }, - status.HTTP_201_CREATED) + 'pkhash': datamanager_pk, + 'validated': True + }, status.HTTP_201_CREATED) mdatacreate.return_value = ({ - 'pkhash': [pkhash1, pkhash2], - 'validated': True - }, - status.HTTP_201_CREATED) + 'pkhash': [pkhash1, pkhash2], + 'validated': True + }, status.HTTP_201_CREATED) mcheck_datamanagers.return_value = True @@ -111,9 +108,9 @@ def test_createobjective(self): } datamanager_out = { - "pkhash": datamanager_pk, - "validated": True - } + "pkhash": datamanager_pk, + "validated": True + } data_out = [ { @@ -131,9 +128,14 @@ def test_createobjective(self): datamanager = json.dumps(datamanager_out, indent=4) data = json.dumps(data_out, indent=4) objective = json.dumps(objective_out, indent=4) - datamanager_wanted_output = f'Successfully added datamanager with status code {status.HTTP_201_CREATED} and result: {datamanager}' - data_wanted_output = f'Successfully bulk added data samples with status code {status.HTTP_201_CREATED} and result: {data}' - objective_wanted_output = f'Successfully added objective with status code {status.HTTP_201_CREATED} and result: {objective}' - self.assertEqual(output, f'{datamanager_wanted_output}\nWill add data samples to this datamanager now\n{data_wanted_output}\nWill add objective to this datamanager now\n{objective_wanted_output}') + datamanager_wanted_output = f'Successfully added datamanager with status code ' \ + f'{status.HTTP_201_CREATED} and result: {datamanager}' + data_wanted_output = f'Successfully bulk added data samples with status code ' \ + f'{status.HTTP_201_CREATED} and result: {data}' + objective_wanted_output = f'Successfully added objective with status code ' \ + f'{status.HTTP_201_CREATED} and result: {objective}' + self.assertEqual(output, f'{datamanager_wanted_output}\nWill add data samples to this datamanager now' + f'\n{data_wanted_output}\nWill add objective to this datamanager now' + f'\n{objective_wanted_output}') finally: sys.stdout = saved_stdout diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index e9504af28..e48595895 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -152,8 +152,10 @@ def test_add_objective_no_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } with mock.patch.object(LedgerObjectiveSerializer, 'create') as mcreate: - mcreate.return_value = {'message': 'Objective added in local db waiting for validation. \ - The substra network has been notified for adding this Objective'}, status.HTTP_202_ACCEPTED + mcreate.return_value = ({ + 'message': 'Objective added in local db waiting for validation.' + 'The substra network has been notified for adding this Objective' + }, status.HTTP_202_ACCEPTED) response = self.client.post(url, data, format='multipart', **extra) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) @@ -243,7 +245,6 @@ def test_get_objective_metrics(self): compute_hash(response.getvalue())) self.assertEqual(self.objective_metrics_filename, response.filename) - # self.assertEqual(r, f'http://testserver/media/objectives/{objective.pkhash}/{self.objective_metrics_filename}') def test_get_objective_metrics_no_version(self): objective = Objective.objects.create( @@ -276,7 +277,7 @@ def setUp(self): os.makedirs(MEDIA_ROOT) self.data_description, self.data_description_filename, self.data_data_opener, \ - self.data_opener_filename = get_sample_datamanager() + self.data_opener_filename = get_sample_datamanager() def tearDown(self): try: @@ -300,8 +301,9 @@ def test_add_datamanager_sync_ok(self): } with mock.patch.object(LedgerDataManagerSerializer, 'create') as mcreate: - mcreate.return_value = { - 'pkhash': 'da920c804c4724f1ce7bd0484edcf4aafa209d5bd54e2e89972c087a487cbe02'}, status.HTTP_201_CREATED + mcreate.return_value = ({ + 'pkhash': 'da920c804c4724f1ce7bd0484edcf4aafa209d5bd54e2e89972c087a487cbe02' + }, status.HTTP_201_CREATED) response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -327,8 +329,10 @@ def test_add_datamanager_no_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } with mock.patch.object(LedgerDataManagerSerializer, 'create') as mcreate: - mcreate.return_value = {'message': 'DataManager added in local db waiting for validation. \ - The substra network has been notified for adding this DataManager'}, status.HTTP_202_ACCEPTED + mcreate.return_value = ({ + 'message': 'DataManager added in local db waiting for validation.' + 'The substra network has been notified for adding this DataManager' + }, status.HTTP_202_ACCEPTED) response = self.client.post(url, data, format='multipart', **extra) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) @@ -391,10 +395,10 @@ def setUp(self): self.data_tar_file, self.data_tar_file_filename = get_sample_tar_data_sample() self.data_description, self.data_description_filename, self.data_data_opener, \ - self.data_opener_filename = get_sample_datamanager() + self.data_opener_filename = get_sample_datamanager() self.data_description2, self.data_description_filename2, self.data_data_opener2, \ - self.data_opener_filename2 = get_sample_datamanager2() + self.data_opener_filename2 = get_sample_datamanager2() def tearDown(self): try: @@ -422,9 +426,10 @@ def test_add_data_sample_sync_ok(self): } with mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mcreate.return_value = { - 'pkhash': '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553', - 'validated': True}, status.HTTP_201_CREATED + mcreate.return_value = ({ + 'pkhash': '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553', + 'validated': True + }, status.HTTP_201_CREATED) response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -491,8 +496,10 @@ def test_add_data_sample_no_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } with mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mcreate.return_value = {'message': 'Data added in local db waiting for validation. \ - The substra network has been notified for adding this Data'}, status.HTTP_202_ACCEPTED + mcreate.return_value = ({ + 'message': 'Data added in local db waiting for validation.' + 'The substra network has been notified for adding this Data' + }, status.HTTP_202_ACCEPTED) response = self.client.post(url, data, format='multipart', **extra) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) @@ -508,8 +515,10 @@ def test_add_data_sample_ko(self): response = self.client.post(url, data, format='multipart', **extra) r = response.json() - self.assertEqual(r['message'], - "One or more datamanager keys provided do not exist in local substrabac database. Please create them before. DataManager keys: ['toto']") + self.assertEqual( + r['message'], + "One or more datamanager keys provided do not exist in local substrabac database. " + "Please create them before. DataManager keys: ['toto']") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) datamanager_name = 'slide opener' @@ -612,7 +621,7 @@ def test_add_data_sample_ko_408(self): } with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: mcreate.return_value = {'pkhash': get_hash(file_mock), 'validated': False}, status.HTTP_408_REQUEST_TIMEOUT mis_zipfile.return_value = True response = self.client.post(url, data, format='multipart', **extra) @@ -699,7 +708,11 @@ def test_bulk_add_data_sample_ko_same_pkhash(self): response = self.client.post(url, data, format='multipart', **extra) r = response.json() self.assertEqual(DataSample.objects.count(), 0) - self.assertEqual(r['message'], f'Your data sample archives contain same files leading to same pkhash, please review the content of your achives. Archives {file_mock2.name} and {file_mock.name} are the same') + self.assertEqual( + r['message'], + f'Your data sample archives contain same files leading to same pkhash, ' + f'please review the content of your achives. ' + f'Archives {file_mock2.name} and {file_mock.name} are the same') self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_add_data_sample_ko_400(self): @@ -724,7 +737,7 @@ def test_add_data_sample_ko_400(self): } with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: mcreate.return_value = 'Failed', status.HTTP_400_BAD_REQUEST mis_zipfile.return_value = True response = self.client.post(url, data, format='multipart', **extra) @@ -754,7 +767,7 @@ def test_add_data_sample_ko_serializer_invalid(self): } with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ - mock.patch.object(DataSampleViewSet, 'get_serializer') as mget_serializer: + mock.patch.object(DataSampleViewSet, 'get_serializer') as mget_serializer: mocked_serializer = MagicMock(DataSampleSerializer) mocked_serializer.is_valid.return_value = True mocked_serializer.save.side_effect = Exception('Failed') @@ -789,7 +802,8 @@ def test_add_data_sample_ko_ledger_invalid(self): } with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ - mock.patch('substrapp.views.datasample.LedgerDataSampleSerializer', spec=True) as mLedgerDataSampleSerializer: + mock.patch('substrapp.views.datasample.LedgerDataSampleSerializer', + spec=True) as mLedgerDataSampleSerializer: mocked_LedgerDataSampleSerializer = MagicMock() mocked_LedgerDataSampleSerializer.is_valid.return_value = False mocked_LedgerDataSampleSerializer.errors = 'Failed' @@ -888,12 +902,12 @@ def setUp(self): os.makedirs(MEDIA_ROOT) self.objective_description, self.objective_description_filename, \ - self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + self.objective_metrics, self.objective_metrics_filename = get_sample_objective() self.algo, self.algo_filename = get_sample_algo() self.data_description, self.data_description_filename, self.data_data_opener, \ - self.data_opener_filename = get_sample_datamanager() + self.data_opener_filename = get_sample_datamanager() def tearDown(self): try: @@ -949,8 +963,10 @@ def test_add_algo_no_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: - mcreate.return_value = {'message': 'Algo added in local db waiting for validation. \ - The substra network has been notified for adding this Algo'}, status.HTTP_202_ACCEPTED + mcreate.return_value = ({ + 'message': 'Algo added in local db waiting for validation.' + 'The substra network has been notified for adding this Algo' + }, status.HTTP_202_ACCEPTED) response = self.client.post(url, data, format='multipart', **extra) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) @@ -972,7 +988,7 @@ def test_add_algo_ko(self): with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: mcreate.return_value = { - 'message': 'Fail to add algo. Objective does not exist'}, status.HTTP_400_BAD_REQUEST + 'message': 'Fail to add algo. Objective does not exist'}, status.HTTP_400_BAD_REQUEST response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -1084,7 +1100,7 @@ def setUp(self): os.makedirs(MEDIA_ROOT) self.objective_description, self.objective_description_filename, \ - self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + self.objective_metrics, self.objective_metrics_filename = get_sample_objective() def tearDown(self): try: @@ -1100,15 +1116,14 @@ def test_add_traintuple_ok(self): # post data url = reverse('substrapp:traintuple-list') - data = {'train_data_sample_keys': [ - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], - 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'data_manager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'objective_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'rank': -1, - 'FLtask_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'in_models_keys': [ - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422']} + data = { + 'train_data_sample_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], + 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'data_manager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'objective_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'rank': -1, + 'FLtask_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'in_models_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422']} extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } @@ -1118,8 +1133,10 @@ def test_add_traintuple_ok(self): raw_pkhash = 'traintuple_pkhash'.encode('utf-8').hex() mqueryLedger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) - mcreate.return_value = {'message': 'Traintuple added in local db waiting for validation. \ - The substra network has been notified for adding this Traintuple'}, status.HTTP_202_ACCEPTED + mcreate.return_value = ({ + 'message': 'Traintuple added in local db waiting for validation.' + 'The substra network has been notified for adding this Traintuple' + }, status.HTTP_202_ACCEPTED) response = self.client.post(url, data, format='multipart', **extra) @@ -1129,9 +1146,10 @@ def test_add_traintuple_ok(self): def test_add_traintuple_ko(self): url = reverse('substrapp:traintuple-list') - data = {'train_data_sample_keys': [ - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], - 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088'} + data = { + 'train_data_sample_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], + 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088' + } extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', @@ -1156,11 +1174,11 @@ def test_add_traintuple_no_version(self): # post data url = reverse('substrapp:traintuple-list') - data = {'train_data_sample_keys': [ - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], - 'datamanager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088'} + data = { + 'train_data_sample_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], + 'datamanager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088'} response = self.client.post(url, data, format='multipart') r = response.json() @@ -1175,11 +1193,11 @@ def test_add_traintuple_wrong_version(self): # post data url = reverse('substrapp:traintuple-list') - data = {'train_data_sample_keys': [ - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], - 'datamanager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088'} + data = { + 'train_data_sample_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], + 'datamanager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088'} extra = { 'HTTP_ACCEPT': 'application/json;version=-1.0', } diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index cd2af0d4c..e813e79c7 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -12,9 +12,12 @@ from substrapp.models import DataSample from substrapp.utils import compute_hash, get_computed_hash, get_remote_file, get_hash, create_directory from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread -from substrapp.tasks.tasks import build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, put_model, put_models, put_algo, put_metric, put_data_sample, prepareTask, doTask, computeTask +from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, + put_model, put_models, put_algo, put_metric, put_data_sample, prepareTask, doTask, + computeTask) -from .common import get_sample_algo, get_sample_script, get_sample_zip_data_sample, get_sample_tar_data_sample, get_sample_model +from .common import (get_sample_algo, get_sample_script, get_sample_zip_data_sample, get_sample_tar_data_sample, + get_sample_model) from .common import FakeClient, FakeObjective, FakeDataManager, FakeModel import zipfile @@ -212,10 +215,14 @@ def test_put_data_sample_zip(self): os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', dir_pkhash))) # check subtuple folder has been created and sym links exists - self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk))) - self.assertTrue(os.path.islink(os.path.join(MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk))) - self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'LABEL_0024900.csv'))) - self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'IMG_0024900.jpg'))) + self.assertTrue(os.path.exists(os.path.join( + MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk))) + self.assertTrue(os.path.islink(os.path.join( + MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk))) + self.assertTrue(os.path.exists(os.path.join( + MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'LABEL_0024900.csv'))) + self.assertTrue(os.path.exists(os.path.join( + MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'IMG_0024900.jpg'))) def test_put_data_tar(self): @@ -240,10 +247,14 @@ def test_put_data_tar(self): self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', dir_pkhash))) # check subtuple folder has been created and sym links exists - self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk))) - self.assertTrue(os.path.islink(os.path.join(MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk))) - self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'LABEL_0024900.csv'))) - self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'IMG_0024900.jpg'))) + self.assertTrue(os.path.exists(os.path.join( + MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk))) + self.assertTrue(os.path.islink(os.path.join( + MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk))) + self.assertTrue(os.path.exists(os.path.join( + MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'LABEL_0024900.csv'))) + self.assertTrue(os.path.exists(os.path.join( + MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'IMG_0024900.jpg'))) def test_put_model(self): @@ -366,13 +377,13 @@ def test_get_objective(self): mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: - mget.return_value = FakeObjective() - mget_remote_file.return_value = metrics_content, objective_hash - mupdate_or_create.return_value = FakeObjective(), True + mget.return_value = FakeObjective() + mget_remote_file.return_value = metrics_content, objective_hash + mupdate_or_create.return_value = FakeObjective(), True - objective = get_objective({'objective': {'hash': objective_hash, - 'metrics': ''}}) - self.assertTrue(isinstance(objective, FakeObjective)) + objective = get_objective({'objective': {'hash': objective_hash, + 'metrics': ''}}) + self.assertTrue(isinstance(objective, FakeObjective)) def test_compute_docker(self): cpu_set, gpu_set = None, None @@ -436,28 +447,28 @@ def __init__(self): mock.patch('substrapp.tasks.tasks.put_algo') as mput_algo, \ mock.patch('substrapp.tasks.tasks.put_model') as mput_model: - msettings.return_value = FakeSettings() - mget_hash.return_value = 'owkinhash' - mqueryLedger.return_value = subtuple, 200 - mget_objective.return_value = 'objective' - mget_algo.return_value = 'algo', 'algo_hash' - mget_model.return_value = 'model', 'model_hash' - mbuild_subtuple_folders.return_value = MEDIA_ROOT - mput_opener.return_value = 'opener' - mput_data_sample.return_value = 'data' - mput_metric.return_value = 'metric' - mput_algo.return_value = 'algo' - mput_model.return_value = 'model' - - with mock.patch('substrapp.tasks.tasks.queryLedger') as mqueryLedger: - mqueryLedger.return_value = 'data', 404 - prepareTask('traintuple', 'inModels') - - with mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger, \ - mock.patch('substrapp.tasks.tasks.computeTask.apply_async') as mapply_async: - minvokeLedger.return_value = 'data', 201 - mapply_async.return_value = 'doTask' - prepareTask('traintuple', 'inModels') + msettings.return_value = FakeSettings() + mget_hash.return_value = 'owkinhash' + mqueryLedger.return_value = subtuple, 200 + mget_objective.return_value = 'objective' + mget_algo.return_value = 'algo', 'algo_hash' + mget_model.return_value = 'model', 'model_hash' + mbuild_subtuple_folders.return_value = MEDIA_ROOT + mput_opener.return_value = 'opener' + mput_data_sample.return_value = 'data' + mput_metric.return_value = 'metric' + mput_algo.return_value = 'algo' + mput_model.return_value = 'model' + + with mock.patch('substrapp.tasks.tasks.queryLedger') as mqueryLedger: + mqueryLedger.return_value = 'data', 404 + prepareTask('traintuple', 'inModels') + + with mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger, \ + mock.patch('substrapp.tasks.tasks.computeTask.apply_async') as mapply_async: + minvokeLedger.return_value = 'data', 201 + mapply_async.return_value = 'doTask' + prepareTask('traintuple', 'inModels') def test_doTask(self): diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py index cb009d10f..9a2e5abbd 100644 --- a/substrabac/substrapp/tests/tests_views.py +++ b/substrabac/substrapp/tests/tests_views.py @@ -208,7 +208,8 @@ def test_objective_retrieve_fail(self): with mock.patch('substrapp.views.objective.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' + file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -223,7 +224,8 @@ def test_objective_create(self): pkhash = get_hash(description_path) - test_data_manager_key = get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) + test_data_manager_key = get_hash(os.path.join( + dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) data = { 'name': 'Simplified skin lesion classification', @@ -260,7 +262,8 @@ def test_objective_create_dryrun(self): description_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/description.md') metrics_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/metrics.py') - test_data_manager_key = get_hash(os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) + test_data_manager_key = get_hash(os.path.join( + dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) data = { 'name': 'Simplified skin lesion classification', @@ -282,7 +285,9 @@ def test_objective_create_dryrun(self): response = self.client.post(url, data=data, format='multipart', **self.extra) self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], 'Your dry-run has been taken in account. You can follow the task execution on https://localhost/task/42/') + self.assertEqual(response.data['message'], + 'Your dry-run has been taken in account. ' + 'You can follow the task execution on https://localhost/task/42/') self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) data['description'].close() @@ -453,7 +458,8 @@ def test_algo_retrieve_fail(self): with mock.patch('substrapp.views.algo.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' + file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -470,7 +476,8 @@ def test_algo_create(self): data = {'name': 'Logistic regression', 'file': open(algo_path, 'rb'), 'description': open(description_path, 'rb'), - 'objective_key': get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/objectives/objective0/description.md')), + 'objective_key': get_hash(os.path.join( + dir_path, '../../../fixtures/chunantes/objectives/objective0/description.md')), 'permissions': 'all'} with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: @@ -624,7 +631,8 @@ def test_model_retrieve_fail(self): with mock.patch('substrapp.views.model.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' + file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -720,7 +728,8 @@ def test_datamanager_list_filter_model(self): def test_datamanager_retrieve(self): url = reverse('substrapp:data_manager-list') - datamanager_response = [d for d in datamanager if d['key'] == '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7'][0] + datamanager_response = [d for d in datamanager + if d['key'] == '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7'][0] with mock.patch.object(DataManagerViewSet, 'getObjectFromLedger') as mgetObjectFromLedger, \ mock.patch('substrapp.views.datamanager.requests.get') as mrequestsget: mgetObjectFromLedger.return_value = datamanager_response @@ -762,7 +771,8 @@ def test_datamanager_retrieve_fail(self): with mock.patch.object(DataManagerViewSet, 'getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' + file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -770,12 +780,14 @@ def test_datamanager_create_dryrun(self): url = reverse('substrapp:data_manager-list') dir_path = os.path.dirname(os.path.realpath(__file__)) - files = {'data_opener': open(os.path.join(dir_path, - '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), - 'rb'), - 'description': open(os.path.join(dir_path, - '../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), - 'rb')} + files = { + 'data_opener': open( + os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), + 'rb'), + + 'description': open( + os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), + 'rb')} data = { 'name': 'ISIC 2018', @@ -858,7 +870,8 @@ def test_traintuple_retrieve_fail(self): with mock.patch.object(TrainTupleViewSet, 'getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' + file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -930,7 +943,8 @@ def test_testtuple_retrieve_fail(self): with mock.patch('substrapp.views.testtuple.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') - search_params = f'{get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md"))}/' + file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -1029,7 +1043,8 @@ def test_data_create_bulk(self): pkhash1 = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' pkhash2 = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] data = { 'files': [path_leaf(data_path1), path_leaf(data_path2)], @@ -1060,7 +1075,8 @@ def test_data_create_bulk_dryrun(self): data_path1 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') data_path2 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] data = { 'files': [path_leaf(data_path1), path_leaf(data_path2)], @@ -1075,11 +1091,14 @@ def test_data_create_bulk_dryrun(self): mock.patch.object(DataSampleViewSet, 'dryrun_task') as mdryrun_task: mdatamanager.return_value = FakeFilterDataManager(1) - mdryrun_task.return_value = (FakeTask('42'), 'Your dry-run has been taken in account. You can follow the task execution on localhost') + mdryrun_task.return_value = ( + FakeTask('42'), + 'Your dry-run has been taken in account. You can follow the task execution on localhost') response = self.client.post(url, data=data, format='multipart', **self.extra) self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], 'Your dry-run has been taken in account. You can follow the task execution on localhost') + self.assertEqual(response.data['message'], + 'Your dry-run has been taken in account. You can follow the task execution on localhost') self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) for x in data['files']: @@ -1094,7 +1113,8 @@ def test_data_create(self): pkhash = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] data = { 'file': open(data_path, 'rb'), @@ -1123,7 +1143,8 @@ def test_data_create_dryrun(self): data_path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - data_manager_keys = [get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] data = { 'file': open(data_path, 'rb'), @@ -1136,11 +1157,14 @@ def test_data_create_dryrun(self): mock.patch.object(DataSampleViewSet, 'dryrun_task') as mdryrun_task: mdatamanager.return_value = FakeFilterDataManager(1) - mdryrun_task.return_value = (FakeTask('42'), 'Your dry-run has been taken in account. You can follow the task execution on localhost') + mdryrun_task.return_value = ( + FakeTask('42'), + 'Your dry-run has been taken in account. You can follow the task execution on localhost') response = self.client.post(url, data=data, format='multipart', **self.extra) self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], 'Your dry-run has been taken in account. You can follow the task execution on localhost') + self.assertEqual(response.data['message'], + 'Your dry-run has been taken in account. You can follow the task execution on localhost') self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) data['file'].close() diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 150afa113..0457b0de3 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -209,7 +209,7 @@ def get_computed_hash(url, key=None): try: r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}, **kwargs) - except: + except Exception: raise Exception(f'Failed to check hash due to failed file fetching {url}') else: if r.status_code != 200: @@ -225,7 +225,8 @@ def get_remote_file(object, key=None): content, computed_hash = get_computed_hash(object['storageAddress'], key) if computed_hash != object['hash']: - msg = 'computed hash is not the same as the hosted file. Please investigate for default of synchronization, corruption, or hacked' + msg = 'computed hash is not the same as the hosted file.' \ + 'Please investigate for default of synchronization, corruption, or hacked' raise Exception(msg) return content, computed_hash diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 2e94f794d..2514d1112 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -12,7 +12,8 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer from substrapp.utils import queryLedger, get_hash -from substrapp.views.utils import get_filters, getObjectFromLedger, ComputeHashMixin, ManageFileMixin, JsonException, find_primary_key_error +from substrapp.views.utils import (get_filters, getObjectFromLedger, ComputeHashMixin, ManageFileMixin, JsonException, + find_primary_key_error) class AlgoViewSet(mixins.CreateModelMixin, @@ -82,7 +83,7 @@ def create_or_update_algo(self, algo, pk): url = algo['description']['storageAddress'] try: r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) # TODO pass cert - except: + except Exception: raise Exception(f'Failed to fetch {url}') else: if r.status_code != 200: @@ -94,7 +95,8 @@ def create_or_update_algo(self, algo, pk): raise Exception('Failed to fetch description file') else: if computed_hash != algo['description']['hash']: - msg = 'computed hash is not the same as the hosted file. Please investigate for default of synchronization, corruption, or hacked' + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' raise Exception(msg) f = tempfile.TemporaryFile() @@ -117,7 +119,7 @@ def retrieve(self, request, *args, **kwargs): try: int(pk, 16) # test if pk is correct (hexadecimal) - except: + except Exception: return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) else: # get instance from remote node @@ -151,7 +153,9 @@ def retrieve(self, request, *args, **kwargs): # do not give access to local files address if instance is not None: - serializer = self.get_serializer(instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + serializer = self.get_serializer( + instance, + fields=('owner', 'pkhash', 'creation_date', 'last_modified')) data.update(serializer.data) else: data = {'message': 'Fail to get instance'} @@ -167,7 +171,7 @@ def list(self, request, *args, **kwargs): # init list to return if data is None: data = [] - l = [data] + data_samples_list = [data] if st == 200: @@ -177,20 +181,20 @@ def list(self, request, *args, **kwargs): if query_params is not None: try: filters = get_filters(query_params) - except Exception as exc: + except Exception: return Response( {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) else: # filtering, reinit l to empty array - l = [] + data_samples_list = [] for idx, filter in enumerate(filters): # init each list iteration to data - l.append(data) + data_samples_list.append(data) for k, subfilters in filter.items(): if k == 'algo': # filter by own key for key, val in subfilters.items(): - l[idx] = [x for x in l[idx] if x[key] in val] + data_samples_list[idx] = [x for x in data_samples_list[idx] if x[key] in val] elif k == 'model': # select objectives used by outModel hash if not modelData: # TODO find a way to put this call in cache @@ -201,11 +205,12 @@ def list(self, request, *args, **kwargs): modelData = [] for key, val in subfilters.items(): - filteredData = [x for x in modelData if x['outModel'] is not None and x['outModel'][key] in val] + filteredData = [x for x in modelData + if x['outModel'] is not None and x['outModel'][key] in val] algoKeys = [x['algo']['hash'] for x in filteredData] - l[idx] = [x for x in l[idx] if x['key'] in algoKeys] + data_samples_list[idx] = [x for x in data_samples_list[idx] if x['key'] in algoKeys] - return Response(l, status=st) + return Response(data_samples_list, status=st) @action(detail=True) def file(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 04e6fc18a..c8970a765 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -39,17 +39,20 @@ def dryrun(self, data_opener): try: node = ast.parse(file) - except: - return Response({'message': f'Opener must be a valid python file, please review your opener file and the documentation.'}, - status=status.HTTP_400_BAD_REQUEST) + except BaseException: + return Response({ + 'message': f'Opener must be a valid python file, please review your opener file and the documentation.' + }, status=status.HTTP_400_BAD_REQUEST) imported_module_names = [m.name for e in node.body if isinstance(e, ast.Import) for m in e.names] if 'substratools' not in imported_module_names: - return Response({'message': 'Opener must import substratools, please review your opener and the documentation.'}, - status=status.HTTP_400_BAD_REQUEST) + return Response({ + 'message': 'Opener must import substratools, please review your opener and the documentation.' + }, status=status.HTTP_400_BAD_REQUEST) - return Response({'message': f'Your data opener is valid. You can remove the dryrun option.'}, - status=status.HTTP_200_OK) + return Response({ + 'message': f'Your data opener is valid. You can remove the dryrun option.' + }, status=status.HTTP_200_OK) def create(self, request, *args, **kwargs): data = request.data @@ -112,14 +115,15 @@ def create_or_update_datamanager(self, instance, datamanager, pk): # create instance if does not exist if not instance: - instance, created = DataManager.objects.update_or_create(pkhash=pk, name=datamanager['name'], validated=True) + instance, created = DataManager.objects.update_or_create( + pkhash=pk, name=datamanager['name'], validated=True) if not instance.data_opener: try: url = datamanager['opener']['storageAddress'] try: r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) - except: + except BaseException: raise Exception(f'Failed to fetch {url}') else: if r.status_code != 200: @@ -131,7 +135,8 @@ def create_or_update_datamanager(self, instance, datamanager, pk): raise Exception('Failed to fetch opener file') else: if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. Please investigate for default of synchronization, corruption, or hacked' + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' raise Exception(msg) f = tempfile.TemporaryFile() @@ -148,7 +153,7 @@ def create_or_update_datamanager(self, instance, datamanager, pk): url = datamanager['description']['storageAddress'] try: r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) - except: + except BaseException: raise Exception(f'Failed to fetch {url}') else: if r.status_code != status.HTTP_200_OK: @@ -160,7 +165,8 @@ def create_or_update_datamanager(self, instance, datamanager, pk): raise Exception('Failed to fetch description file') else: if computed_hash != datamanager['description']['hash']: - msg = 'computed hash is not the same as the hosted file. Please investigate for default of synchronization, corruption, or hacked' + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' raise Exception(msg) f = tempfile.TemporaryFile() @@ -195,7 +201,7 @@ def retrieve(self, request, *args, **kwargs): try: int(pk, 16) # test if pk is correct (hexadecimal) - except: + except BaseException: return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) else: # get instance from remote node @@ -229,7 +235,9 @@ def retrieve(self, request, *args, **kwargs): # do not give access to local files address if instance is not None: - serializer = self.get_serializer(instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + serializer = self.get_serializer( + instance, + fields=('owner', 'pkhash', 'creation_date', 'last_modified')) data.update(serializer.data) else: data = {'message': 'Fail to get instance'} @@ -246,7 +254,7 @@ def list(self, request, *args, **kwargs): # init list to return if data is None: data = [] - l = [data] + data_managers_list = [data] if st == 200: @@ -256,20 +264,20 @@ def list(self, request, *args, **kwargs): if query_params is not None: try: filters = get_filters(query_params) - except Exception as exc: + except Exception: return Response( {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) else: # filtering, reinit l to empty array - l = [] + data_managers_list = [] for idx, filter in enumerate(filters): # init each list iteration to data - l.append(data) + data_managers_list.append(data) for k, subfilters in filter.items(): if k == 'dataset': # filter by own key for key, val in subfilters.items(): - l[idx] = [x for x in l[idx] if x[key] in val] + data_managers_list[idx] = [x for x in data_managers_list[idx] if x[key] in val] elif k == 'objective': # select objective used by these datamanagers if not objectiveData: # TODO find a way to put this call in cache @@ -285,7 +293,8 @@ def list(self, request, *args, **kwargs): else: filteredData = [x for x in objectiveData if x[key] in val] objectiveKeys = [x['key'] for x in filteredData] - l[idx] = [x for x in l[idx] if x['objectiveKey'] in objectiveKeys] + data_managers_list[idx] = [x for x in data_managers_list[idx] + if x['objectiveKey'] in objectiveKeys] elif k == 'model': # select objectives used by outModel hash if not modelData: # TODO find a way to put this call in cache @@ -296,11 +305,13 @@ def list(self, request, *args, **kwargs): modelData = [] for key, val in subfilters.items(): - filteredData = [x for x in modelData if x['outModel'] is not None and x['outModel'][key] in val] + filteredData = [x for x in modelData + if x['outModel'] is not None and x['outModel'][key] in val] objectiveKeys = [x['objective']['hash'] for x in filteredData] - l[idx] = [x for x in l[idx] if x['objectiveKey'] in objectiveKeys] + data_managers_list[idx] = [x for x in data_managers_list[idx] + if x['objectiveKey'] in objectiveKeys] - return Response(l, status=st) + return Response(data_managers_list, status=st) @action(methods=['post'], detail=True) def update_ledger(self, request, *args, **kwargs): @@ -314,7 +325,7 @@ def update_ledger(self, request, *args, **kwargs): try: int(pk, 16) # test if pk is correct (hexadecimal) - except: + except BaseException: return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) else: @@ -328,7 +339,7 @@ def update_ledger(self, request, *args, **kwargs): try: int(pk, 16) # test if pk is correct (hexadecimal) - except: + except BaseException: return Response({'message': f'Objective Key is wrong: {pk}'}, status.HTTP_400_BAD_REQUEST) else: diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 9f09d80e4..6c8ec771d 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -116,7 +116,7 @@ def compute_dryrun(self, data, data_manager_keys): try: container = client.containers.get(data_docker_name) container.remove() - except: + except Exception: logger.error('Could not remove containers') remove_subtuple_materials(subtuple_directory) for data_sample in data: @@ -145,7 +145,8 @@ def check_datamanagers(data_manager_keys): datamanager_count = DataManager.objects.filter(pkhash__in=data_manager_keys).count() if datamanager_count != len(data_manager_keys): - raise Exception(f'One or more datamanager keys provided do not exist in local substrabac database. Please create them before. DataManager keys: {data_manager_keys}') + raise Exception(f'One or more datamanager keys provided do not exist in local substrabac database. ' + f'Please create them before. DataManager keys: {data_manager_keys}') @staticmethod def commit(serializer, ledger_data): @@ -189,7 +190,9 @@ def compute_data(self, request): except KeyError: pass else: - raise Exception(f'Your data sample archives contain same files leading to same pkhash, please review the content of your achives. Archives {file} and {existing["file"]} are the same') + raise Exception(f'Your data sample archives contain same files leading to same pkhash, ' + f'please review the content of your achives. ' + f'Archives {file} and {existing["file"]} are the same') data[pkhash] = { 'pkhash': pkhash, 'file': file @@ -208,7 +211,8 @@ def compute_data(self, request): # paths, should be directories for path in paths: if not os.path.isdir(path): - raise Exception(f'One of your paths does not exist, is not a directory or is not an absolute path: {path}') + raise Exception(f'One of your paths does not exist, ' + f'is not a directory or is not an absolute path: {path}') pkhash = dirhash(path, 'sha256') try: existing = data[pkhash] @@ -216,7 +220,8 @@ def compute_data(self, request): pass else: # existing can be a dict with a field path or file - raise Exception(f'Your data sample directory contain same files leading to same pkhash. Invalid path: {path}.') + raise Exception(f'Your data sample directory contain same files leading to same pkhash. ' + f'Invalid path: {path}.') data[pkhash] = { 'pkhash': pkhash, diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index c567acade..4c34bf324 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -35,7 +35,7 @@ def create_or_update_model(self, traintuple, pk): url = traintuple['outModel']['storageAddress'] try: r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) # TODO pass cert - except: + except Exception: raise Exception(f'Failed to fetch {url}') else: if r.status_code != 200: @@ -47,7 +47,8 @@ def create_or_update_model(self, traintuple, pk): raise Exception('Failed to fetch outModel file') else: if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. Please investigate for default of synchronization, corruption, or hacked' + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' raise Exception(msg) f = tempfile.TemporaryFile() @@ -70,7 +71,7 @@ def retrieve(self, request, *args, **kwargs): try: int(pk, 16) # test if pk is correct (hexadecimal) - except: + except Exception: return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) else: # get instance from remote node @@ -106,7 +107,9 @@ def retrieve(self, request, *args, **kwargs): # do not give access to local files address if instance is not None: - serializer = self.get_serializer(instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + serializer = self.get_serializer( + instance, + fields=('owner', 'pkhash', 'creation_date', 'last_modified')) data.update(serializer.data) else: data = {'message': 'Fail to get instance'} @@ -124,7 +127,7 @@ def list(self, request, *args, **kwargs): # init list to return if data is None: data = [] - l = [data] + models_list = [data] if st == 200: # parse filters @@ -133,22 +136,24 @@ def list(self, request, *args, **kwargs): if query_params is not None: try: filters = get_filters(query_params) - except Exception as exc: + except Exception: return Response( {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) else: # filtering, reinit l to empty array - l = [] + models_list = [] for idx, filter in enumerate(filters): # init each list iteration to data if data is None: data = [] - l.append(data) + models_list.append(data) for k, subfilters in filter.items(): if k == 'model': # filter by own key for key, val in subfilters.items(): - l[idx] = [x for x in l[idx] if x['traintuple']['outModel'] is not None and x['traintuple']['outModel']['hash'] in val] + models_list[idx] = [x for x in models_list[idx] + if x['traintuple']['outModel'] is not None and + x['traintuple']['outModel']['hash'] in val] elif k == 'algo': # select model used by these algo if not algoData: # TODO find a way to put this call in cache @@ -161,7 +166,8 @@ def list(self, request, *args, **kwargs): for key, val in subfilters.items(): filteredData = [x for x in algoData if x[key] in val] algoHashes = [x['key'] for x in filteredData] - l[idx] = [x for x in l[idx] if x['traintuple']['algo']['hash'] in algoHashes] + models_list[idx] = [x for x in models_list[idx] + if x['traintuple']['algo']['hash'] in algoHashes] elif k == 'dataset': # select model which trainData.openerHash is if not dataManagerData: # TODO find a way to put this call in cache @@ -174,7 +180,9 @@ def list(self, request, *args, **kwargs): for key, val in subfilters.items(): filteredData = [x for x in dataManagerData if x[key] in val] datamanagerHashes = [x['key'] for x in filteredData] - l[idx] = [x for x in l[idx] if x['traintuple']['dataset']['openerHash'] in datamanagerHashes] + models_list[idx] = [ + x for x in models_list[idx] + if x['traintuple']['dataset']['openerHash'] in datamanagerHashes] elif k == 'objective': # select objective used by these datamanagers if not objectiveData: # TODO find a way to put this call in cache @@ -190,9 +198,10 @@ def list(self, request, *args, **kwargs): else: filteredData = [x for x in objectiveData if x[key] in val] objectiveKeys = [x['key'] for x in filteredData] - l[idx] = [x for x in l[idx] if x['traintuple']['objective']['hash'] in objectiveKeys] + models_list[idx] = [x for x in models_list[idx] + if x['traintuple']['objective']['hash'] in objectiveKeys] - return Response(l, status=st) + return Response(models_list, status=st) @action(detail=True) def file(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 18e5eb69e..1080f0662 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -6,8 +6,6 @@ import tempfile import uuid -from urllib.parse import unquote - import requests from django.conf import settings from django.db import IntegrityError @@ -28,7 +26,8 @@ from substrapp.utils import queryLedger, get_hash, get_computed_hash from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.views.utils import get_filters, getObjectFromLedger, ComputeHashMixin, ManageFileMixin, JsonException, find_primary_key_error +from substrapp.views.utils import (get_filters, getObjectFromLedger, ComputeHashMixin, ManageFileMixin, JsonException, + find_primary_key_error) @app.task(bind=True, ignore_result=False) @@ -112,29 +111,6 @@ def perform_create(self, serializer): return serializer.save() def create(self, request, *args, **kwargs): - """ - Create a new Objective \n - TODO add info about what has to be posted\n - - Example with curl (on localhost): \n - curl -u username:password -H "Content-Type: application/json"\ - -X POST\ - -d '{"name": "tough objective", "permissions": "all", "metrics_name": 'accuracy', "test_data": - ["data_5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379", - "data_5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389"],\ - "files": {"description.md": '#My tough objective',\ - 'metrics.py': 'def AUC_score(y_true, y_pred):\n\treturn 1'}}'\ - http://127.0.0.1:8000/substrapp/objective/ \n - Use double quotes for the json, simple quotes don't work.\n - - Example with the python package requests (on localhost): \n - requests.post('http://127.0.0.1:8000/objective/', - #auth=('username', 'password'), - data={'name': 'MSI classification', 'permissions': 'all', 'metrics_name': 'accuracy', 'test_data_sample_keys': ['da1bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc']}, - files={'description': open('description.md', 'rb'), 'metrics': open('metrics.py', 'rb')}, - headers={'Accept': 'application/json;version=0.0'}) \n - --- - response_serializer: ObjectiveSerializer - """ - data = request.data dryrun = data.get('dryrun', False) @@ -144,8 +120,9 @@ def create(self, request, *args, **kwargs): try: test_data_sample_keys = request.data.getlist('test_data_sample_keys', []) - except: - test_data_sample_keys = request.data.get('test_data_sample_keys', request.POST.getlist('test_data_sample_keys', [])) + except Exception: + test_data_sample_keys = request.data.get('test_data_sample_keys', + request.POST.getlist('test_data_sample_keys', [])) metrics = data.get('metrics') @@ -168,10 +145,12 @@ def create(self, request, *args, **kwargs): with open(metrics_path, 'wb') as metrics_file: metrics_file.write(metrics.open().read()) - task = compute_dryrun.apply_async((metrics_path, test_data_manager_key, pkhash), queue=f"{settings.LEDGER['name']}.dryrunner") + task = compute_dryrun.apply_async((metrics_path, test_data_manager_key, pkhash), + queue=f"{settings.LEDGER['name']}.dryrunner") except Exception as e: - return Response({'message': f'Could not launch objective creation with dry-run on this instance: {str(e)}'}, - status=status.HTTP_400_BAD_REQUEST) + return Response({ + 'message': f'Could not launch objective creation with dry-run on this instance: {str(e)}' + }, status=status.HTTP_400_BAD_REQUEST) current_site = getattr(settings, "DEFAULT_DOMAIN") task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' @@ -235,7 +214,8 @@ def create_or_update_objective(self, objective, pk): raise Exception('Failed to fetch description file') if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. Please investigate for default of synchronization, corruption, or hacked' + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' raise Exception(msg) f = tempfile.TemporaryFile() diff --git a/substrabac/substrapp/views/task.py b/substrabac/substrapp/views/task.py index d7717ac91..00a690452 100644 --- a/substrabac/substrapp/views/task.py +++ b/substrabac/substrapp/views/task.py @@ -15,12 +15,13 @@ def retrieve(self, request, pk=None): data = { 'status': res.status } - except: + except Exception: return Response({'message': 'Can\'t get task status'}, status=status.HTTP_400_BAD_REQUEST) else: if not res.successful(): if res.status == 'PENDING': - data['message'] = 'Task is either waiting, does not exist in this context or has been removed after 24h' + data['message'] = 'Task is either waiting, ' \ + 'does not exist in this context or has been removed after 24h' else: data['message'] = res.traceback else: diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index d7214b35a..f94fac844 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -22,31 +22,15 @@ def perform_create(self, serializer): return serializer.save() def create(self, request, *args, **kwargs): - # TODO update - ''' - curl -H "Accept: text/html;version=0.0, */*;version=0.0" - -d "algo_key=da58a7a29b549f2fe5f009fb51cce6b28ca184ec641a0c1db075729bb266549b&model_key=10060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568&train_data_keys[]=62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a&train_data[]=42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9" - -X POST http://localhost:8001/traintuple/ - - or - - curl -H "Accept: text/html;version=0.0, */*;version=0.0" - -H "Content-Type: application/json" - -d '{"algo_key":"da58a7a29b549f2fe5f009fb51cce6b28ca184ec641a0c1db075729bb266549b","model_key":"10060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568","train_data_keys":["62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a","42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9"]}' - -X POST http://localhost:8001/traintuple/?format=json - - :param request: - :return: - ''' - traintuple_key = request.data.get('traintuple_key', request.POST.get('traintuple_key', None)) data_manager_key = request.data.get('data_manager_key', request.POST.get('data_manager_key', '')) tag = request.data.get('tag', request.POST.get('tag', '')) try: test_data_sample_keys = request.data.getlist('test_data_sample_keys', []) - except: - test_data_sample_keys = request.data.get('test_data_sample_keys', request.POST.getlist('test_data_sample_keys', [])) + except Exception: + test_data_sample_keys = request.data.get('test_data_sample_keys', + request.POST.getlist('test_data_sample_keys', [])) data = { 'traintuple_key': traintuple_key, @@ -118,7 +102,7 @@ def retrieve(self, request, *args, **kwargs): try: int(pk, 16) # test if pk is correct (hexadecimal) - except: + except Exception: return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) else: # get instance from remote node diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 5fd650650..b3c0d9017 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -22,23 +22,6 @@ def perform_create(self, serializer): return serializer.save() def create(self, request, *args, **kwargs): - # TODO update - ''' - curl -H "Accept: text/html;version=0.0, */*;version=0.0" - -d "algo_key=da58a7a29b549f2fe5f009fb51cce6b28ca184ec641a0c1db075729bb266549b&model_key=10060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568&train_data_sample_keys[]=62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a&train_data[]=42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9" - -X POST http://localhost:8001/traintuple/ - - or - - curl -H "Accept: text/html;version=0.0, */*;version=0.0" - -H "Content-Type: application/json" - -d '{"algo_key":"da58a7a29b549f2fe5f009fb51cce6b28ca184ec641a0c1db075729bb266549b","model_key":"10060f1d9e450d98bb5892190860eee8dd48594f00e0e1c9374a27c5acdba568","train_data_sample_keys":["62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a","42303efa663015e729159833a12ffb510ff92a6e386b8152f90f6fb14ddc94c9"]}' - -X POST http://localhost:8001/traintuple/?format=json - - :param request: - :return: - ''' - algo_key = request.data.get('algo_key', request.POST.get('algo_key', None)) data_manager_key = request.data.get('data_manager_key', request.POST.get('data_manager_key', None)) objective_key = request.data.get('objective_key', request.POST.get('objective_key', None)) @@ -48,13 +31,14 @@ def create(self, request, *args, **kwargs): try: in_models_keys = request.data.getlist('in_models_keys', []) - except: + except Exception: in_models_keys = request.data.get('in_models_keys', request.POST.getlist('in_models_keys', [])) try: train_data_sample_keys = request.data.getlist('train_data_sample_keys', []) - except: - train_data_sample_keys = request.data.get('train_data_sample_keys', request.POST.getlist('train_data_sample_keys', [])) + except Exception: + train_data_sample_keys = request.data.get('train_data_sample_keys', + request.POST.getlist('train_data_sample_keys', [])) data = { 'algo_key': algo_key, @@ -63,7 +47,8 @@ def create(self, request, *args, **kwargs): 'rank': rank, 'FLtask_key': FLtask_key, 'in_models_keys': in_models_keys, - 'train_data_sample_keys': train_data_sample_keys, # list of train data keys (which are stored in the train worker node) + # list of train data keys (which are stored in the train worker node) + 'train_data_sample_keys': train_data_sample_keys, 'tag': tag } @@ -143,7 +128,7 @@ def retrieve(self, request, *args, **kwargs): try: int(pk, 16) # test if pk is correct (hexadecimal) - except: + except Exception: return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) else: # get instance from remote node diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 577f1867c..2c0a4a879 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -105,7 +105,7 @@ def manage_file(self, field): except Exception as e: return Response(e, status=status.HTTP_400_BAD_REQUEST) except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) else: object = self.get_object() @@ -118,11 +118,11 @@ def find_primary_key_error(validation_error, key_name='pkhash'): def find_unique_error(detail_dict): for key, errors in detail_dict.items(): - if key != key_name: - continue - for error in errors: - if error.code == 'unique': - return error + if key != key_name: + continue + for error in errors: + if error.code == 'unique': + return error return None From 9a9bd34d43cc6d950d7c23e0fb0619a406d32335 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 29 May 2019 08:38:27 +0200 Subject: [PATCH 043/457] Isolate ledger settings. --- substrabac/substrabac/settings/dev.py | 56 +------------------- substrabac/substrabac/settings/ledger.py | 59 +++++++++++++++++++++ substrabac/substrabac/settings/prod.py | 67 +++--------------------- 3 files changed, 66 insertions(+), 116 deletions(-) create mode 100644 substrabac/substrabac/settings/ledger.py diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index a7549cae8..a385670d1 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -1,73 +1,19 @@ import os -import asyncio -import glob -import json from .common import * +from .ledger import * from .deps.restframework import * from .deps.cors import * -from hfc.fabric import Client -from hfc.fabric.peer import Peer -from hfc.fabric.user import create_user -from hfc.fabric.orderer import Orderer -from hfc.util.keyvaluestore import FileKeyValueStore - DEBUG = True ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') DEFAULT_PORT = os.environ.get('SUBSTRABAC_DEFAULT_PORT', '8000') - ORG_NAME = ORG.replace('-', '') ORG_DB_NAME = ORG.replace('-', '_').upper() -LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) - -HLF_LOOP = asyncio.new_event_loop() -asyncio.set_event_loop(HLF_LOOP) - -channel_name = LEDGER['channel_name'] -chaincode_name = LEDGER['chaincode_name'] -peer = LEDGER['peer'] -peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] -orderer = LEDGER['orderer'] - -requestor_config = LEDGER['client'] - -CLIENT = Client() -CLIENT.new_channel(channel_name) - -REQUESTOR = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - -target_peer = Peer(name=peer['name']) - -# Need loop -target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) -CLIENT._peers[peer['name']] = target_peer - -target_orderer = Orderer(name=orderer['name']) - -# Need loop -target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', - 'grpcOptions': orderer['grpcOptions'], - 'tlsCACerts': {'path': orderer['ca']}, - 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) - 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) - }) -CLIENT._orderers[orderer['name']] = target_orderer - # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases diff --git a/substrabac/substrabac/settings/ledger.py b/substrabac/substrabac/settings/ledger.py new file mode 100644 index 000000000..d28d974f7 --- /dev/null +++ b/substrabac/substrabac/settings/ledger.py @@ -0,0 +1,59 @@ + +import os +import asyncio +import glob +import json + +from hfc.fabric import Client +from hfc.fabric.peer import Peer +from hfc.fabric.user import create_user +from hfc.fabric.orderer import Orderer +from hfc.util.keyvaluestore import FileKeyValueStore + + +ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') + +LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) + +HLF_LOOP = asyncio.new_event_loop() +asyncio.set_event_loop(HLF_LOOP) + +channel_name = LEDGER['channel_name'] +chaincode_name = LEDGER['chaincode_name'] +peer = LEDGER['peer'] +peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] +orderer = LEDGER['orderer'] + +requestor_config = LEDGER['client'] + +CLIENT = Client() +CLIENT.new_channel(channel_name) + +REQUESTOR = create_user(name=requestor_config['name'], + org=requestor_config['org'], + state_store=FileKeyValueStore(requestor_config['state_store']), + msp_id=requestor_config['msp_id'], + key_path=glob.glob(requestor_config['key_path'])[0], + cert_path=requestor_config['cert_path']) + +target_peer = Peer(name=peer['name']) + +# Need loop +target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', + 'grpcOptions': peer['grpcOptions'], + 'tlsCACerts': {'path': peer['tlsCACerts']}, + 'clientKey': {'path': peer['clientKey']}, + 'clientCert': {'path': peer['clientCert']}, + }) +CLIENT._peers[peer['name']] = target_peer + +target_orderer = Orderer(name=orderer['name']) + +# Need loop +target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', + 'grpcOptions': orderer['grpcOptions'], + 'tlsCACerts': {'path': orderer['ca']}, + 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) + }) +CLIENT._orderers[orderer['name']] = target_orderer diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 5ff9f166a..500f2a729 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -1,80 +1,25 @@ import os -import asyncio -import glob -import json from .common import * +from .ledger import * from .deps.restframework import * from .deps.cors import * from .deps.raven import * -from hfc.fabric import Client -from hfc.fabric.peer import Peer -from hfc.fabric.user import create_user -from hfc.fabric.orderer import Orderer -from hfc.util.keyvaluestore import FileKeyValueStore - DEBUG = False + USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') os.environ['HTTPS'] = "on" -os.environ['wsgi.url_scheme'] = 'https' # safer - -import os +os.environ['wsgi.url_scheme'] = 'https' ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') DEFAULT_PORT = os.environ.get('SUBSTRABAC_DEFAULT_PORT', '8000') - ORG_NAME = ORG.replace('-', '') ORG_DB_NAME = ORG.replace('-', '_').upper() -LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) - -HLF_LOOP = asyncio.new_event_loop() -asyncio.set_event_loop(HLF_LOOP) - -channel_name = LEDGER['channel_name'] -chaincode_name = LEDGER['chaincode_name'] -peer = LEDGER['peer'] -peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] -orderer = LEDGER['orderer'] - -requestor_config = LEDGER['client'] - -CLIENT = Client() -CLIENT.new_channel(channel_name) - -REQUESTOR = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - -target_peer = Peer(name=peer['name']) - -# Need loop -target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) -CLIENT._peers[peer['name']] = target_peer - -target_orderer = Orderer(name=orderer['name']) - -# Need loop -target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', - 'grpcOptions': orderer['grpcOptions'], - 'tlsCACerts': {'path': orderer['ca']}, - 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) - 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) - }) -CLIENT._orderers[orderer['name']] = target_orderer - # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases @@ -92,15 +37,15 @@ MEDIA_ROOT = f'/substra/medias/{ORG_NAME}' DRYRUN_ROOT = f'/substra/dryrun/{ORG}' +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'statics') + SITE_ID = 1 SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substrabac') SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') -STATIC_URL = '/static/' -STATIC_ROOT = os.path.join(BASE_DIR, 'statics') - # deactivate when public BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER', None) BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', None) From 41d922599ce4417ba6ecd0eb51833333e0c68518 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 29 May 2019 10:25:14 +0200 Subject: [PATCH 044/457] Improve settings and refacto ledger settings to be cleaner. --- docker/start.py | 57 +++++++++-------- substrabac/substrabac/settings/common.py | 11 ---- substrabac/substrabac/settings/deps/ledger.py | 63 +++++++++++++++++++ substrabac/substrabac/settings/deps/org.py | 6 ++ substrabac/substrabac/settings/dev.py | 11 +--- substrabac/substrabac/settings/ledger.py | 59 ----------------- substrabac/substrabac/settings/prod.py | 22 +++---- substrabac/substrapp/tests/tests_query.py | 5 ++ substrabac/substrapp/utils.py | 38 ++++++----- 9 files changed, 136 insertions(+), 136 deletions(-) create mode 100644 substrabac/substrabac/settings/deps/ledger.py create mode 100644 substrabac/substrabac/settings/deps/org.py delete mode 100644 substrabac/substrabac/settings/ledger.py diff --git a/docker/start.py b/docker/start.py index cc0679944..c9217ad5d 100644 --- a/docker/start.py +++ b/docker/start.py @@ -19,6 +19,8 @@ 'clb': 8002 } +SUBSTRA_FOLDER = '/substra' + def generate_docker_compose_file(conf, launch_settings): @@ -44,6 +46,9 @@ def generate_docker_compose_file(conf, launch_settings): except ImportError: import yaml + wait_rabbit = f'while ! {{ nc -z {RABBITMQ_DOMAIN} {RABBITMQ_PORT} 2>&1; }}; do sleep 1; done' + wait_psql = 'while ! { nc -z postgresql 5432 2>&1; }; do sleep 1; done' + # Docker compose config docker_compose = { 'substrabac_services': {}, @@ -59,7 +64,7 @@ def generate_docker_compose_file(conf, launch_settings): f'POSTGRES_PASSWORD={POSTGRES_PASSWORD}', f'POSTGRES_DB={POSTGRES_DB}'], 'volumes': [ - '/substra/backup/postgres-data:/var/lib/postgresql/data', + f'{SUBSTRA_FOLDER}/backup/postgres-data:/var/lib/postgresql/data', f'{dir_path}/postgresql/init.sh:/docker-entrypoint-initdb.d/init.sh'], }, 'celerybeat': { @@ -67,8 +72,7 @@ def generate_docker_compose_file(conf, launch_settings): 'hostname': 'celerybeat', 'image': 'substra/celerybeat', 'restart': 'unless-stopped', - 'command': '/bin/bash -c "while ! { nc -z rabbit 5672 2>&1; }; do sleep 1; done; ' - 'while ! { nc -z postgresql 5432 2>&1; }; do sleep 1; done; ' + 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' 'celery -A substrabac beat -l info"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': [ @@ -88,7 +92,7 @@ def generate_docker_compose_file(conf, launch_settings): f'RABBITMQ_DEFAULT_PASS={RABBITMQ_DEFAULT_PASS}', f'HOSTNAME={RABBITMQ_HOSTNAME}', f'RABBITMQ_NODENAME={RABBITMQ_NODENAME}'], - 'volumes': ['/substra/backup/rabbit-data:/var/lib/rabbitmq'] + 'volumes': [f'{SUBSTRA_FOLDER}/backup/rabbit-data:/var/lib/rabbitmq'] }, }, 'path': os.path.join(dir_path, './docker-compose-dynamic.yaml')} @@ -97,7 +101,7 @@ def generate_docker_compose_file(conf, launch_settings): org_name = org['name'] orderer_ca = org['orderer']['ca'] peer = org['peer']['name'] - tls_peer_dir = f'/substra/data/orgs/{org_name}/tls/{peer}' + tls_peer_dir = f'{SUBSTRA_FOLDER}/data/orgs/{org_name}/tls/{peer}' org_name_stripped = org_name.replace('-', '') @@ -121,6 +125,8 @@ def generate_docker_compose_file(conf, launch_settings): f'SUBSTRABAC_DEFAULT_PORT={port}', 'SUBSTRABAC_PEER_PORT=internal', + f'LEDGER_CONFIG_FILE={SUBSTRA_FOLDER}/conf/{org_name}/substrabac/conf.json', + 'PYTHONUNBUFFERED=1', 'DATABASE_HOST=postgresql', @@ -136,7 +142,7 @@ def generate_docker_compose_file(conf, launch_settings): hlf_volumes = [ # config (core.yaml + substrabac/conf.json) - f'/substra/conf/{org_name}:/substra/conf/{org_name}:ro', + f'{SUBSTRA_FOLDER}/conf/{org_name}:{SUBSTRA_FOLDER}/conf/{org_name}:ro', # HLF files f'{orderer_ca}:{orderer_ca}:ro', @@ -149,15 +155,15 @@ def generate_docker_compose_file(conf, launch_settings): 'image': 'substra/substrabac', 'restart': 'unless-stopped', 'ports': [f'{port}:{port}'], - 'command': f'/bin/bash -c "while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; ' + 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' f'yes | python manage.py migrate; {django_server}"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), 'volumes': [ - '/substra/medias:/substra/medias', - '/substra/dryrun:/substra/dryrun', - '/substra/servermedias:/substra/servermedias', - '/substra/static:/usr/src/app/substrabac/statics'] + hlf_volumes, + f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias', + f'{SUBSTRA_FOLDER}/dryrun:{SUBSTRA_FOLDER}/dryrun', + f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias', + f'{SUBSTRA_FOLDER}/static:/usr/src/app/substrabac/statics'] + hlf_volumes, 'depends_on': ['postgresql', 'rabbit']} scheduler = { @@ -165,8 +171,7 @@ def generate_docker_compose_file(conf, launch_settings): 'hostname': f'{org_name}.scheduler', 'image': 'substra/celeryworker', 'restart': 'unless-stopped', - 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; ' - f'while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; ' + 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' f'celery -A substrabac worker -l info -n {org_name_stripped} ' f'-Q {org_name},scheduler,celery --hostname {org_name}.scheduler"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, @@ -179,16 +184,15 @@ def generate_docker_compose_file(conf, launch_settings): 'hostname': f'{org_name}.worker', 'image': 'substra/celeryworker', 'restart': 'unless-stopped', - 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; ' - f'while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; ' + 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' f'celery -A substrabac worker -l info -n {org_name_stripped} ' f'-Q {org_name},{org_name}.worker,celery --hostname {org_name}.worker"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), 'volumes': [ '/var/run/docker.sock:/var/run/docker.sock', - '/substra/medias:/substra/medias', - '/substra/servermedias:/substra/servermedias'] + hlf_volumes, + f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias', + f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias'] + hlf_volumes, 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} dryrunner = { @@ -196,17 +200,16 @@ def generate_docker_compose_file(conf, launch_settings): 'hostname': f'{org_name}.dryrunner', 'image': 'substra/celeryworker', 'restart': 'unless-stopped', - 'command': f'/bin/bash -c "while ! {{ nc -z rabbit 5672 2>&1; }}; do sleep 1; done; ' - f'while ! {{ nc -z postgresql 5432 2>&1; }}; do sleep 1; done; ' + 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' f'celery -A substrabac worker -l info -n {org_name_stripped} ' f'-Q {org_name},{org_name}.dryrunner,celery --hostname {org_name}.dryrunner"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), 'volumes': [ '/var/run/docker.sock:/var/run/docker.sock', - '/substra/dryrun:/substra/dryrun', - '/substra/medias:/substra/medias', - '/substra/servermedias:/substra/servermedias'] + hlf_volumes, + f'{SUBSTRA_FOLDER}/dryrun:{SUBSTRA_FOLDER}/dryrun', + f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias', + f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias'] + hlf_volumes, 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} # Check if we have nvidia docker @@ -214,8 +217,8 @@ def generate_docker_compose_file(conf, launch_settings): worker['runtime'] = 'nvidia' if launch_settings == 'dev': - media_root = f'MEDIA_ROOT=/substra/medias/{org_name_stripped}' - dryrun_root = f'DRYRUN_ROOT=/substra/dryrun/{org_name}' + media_root = f'MEDIA_ROOT={SUBSTRA_FOLDER}/medias/{org_name_stripped}' + dryrun_root = f'DRYRUN_ROOT={SUBSTRA_FOLDER}/dryrun/{org_name}' worker['environment'].append(media_root) dryrunner['environment'].append(media_root) @@ -272,9 +275,9 @@ def start(conf, launch_settings, no_backup): print('Clean medias directory\n') call(['sh', os.path.join(dir_path, '../scripts/clean_media.sh')]) print('Remove postgresql database\n') - call(['rm', '-rf', '/substra/backup/postgres-data']) + call(['rm', '-rf', f'{SUBSTRA_FOLDER}/backup/postgres-data']) print('Remove rabbit database\n') - call(['rm', '-rf', '/substra/backup/rabbit-data']) + call(['rm', '-rf', f'{SUBSTRA_FOLDER}/backup/rabbit-data']) print('start docker-compose', flush=True) call(['docker-compose', '-f', docker_compose['path'], '--project-directory', @@ -298,7 +301,7 @@ def start(conf, launch_settings, no_backup): no_backup = args['no_backup'] - conf = [json.load(open(file_path, 'r')) for file_path in glob.glob('/substra/conf/*/substrabac/conf.json')] + conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/substrabac/conf.json')] print('Build substrabac for : ', flush=True) print(' Organizations :', flush=True) diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 35f49ce0d..0044fcd0c 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -141,23 +141,12 @@ MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'medias') MEDIA_URL = '/media/' -REST_FRAMEWORK = { - 'DEFAULT_RENDERER_CLASSES': ( - 'rest_framework.renderers.JSONRenderer', - 'rest_framework.renderers.AdminRenderer', - 'rest_framework.renderers.BrowsableAPIRenderer', - ) -} - SITE_ID = 1 -LEDGER_SYNC_ENABLED = True - CELERY_RESULT_BACKEND = 'django-db' CELERY_ACCEPT_CONTENT = ['application/json'] CELERY_RESULT_SERIALIZER = 'json' CELERY_TASK_SERIALIZER = 'json' CELERY_TASK_TRACK_STARTED = True # since 4.0 CELERY_WORKER_CONCURRENCY = 1 - CELERY_BROKER_URL = os.environ.get('CELERY_BROKER_URL', 'amqp://localhost:5672//'), diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py new file mode 100644 index 000000000..963764f86 --- /dev/null +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -0,0 +1,63 @@ + +import os +import asyncio +import glob +import json + +from .org import ORG + +from hfc.fabric import Client +from hfc.fabric.peer import Peer +from hfc.fabric.user import create_user +from hfc.fabric.orderer import Orderer +from hfc.util.keyvaluestore import FileKeyValueStore + + +LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/substrabac/conf.json') +LEDGER = json.load(open(LEDGER_CONFIG_FILE, 'r')) + +LEDGER_SYNC_ENABLED = True + +PEER_PORT = LEDGER['peer']['port'][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + +LEDGER['hfc'] = {} +LEDGER['hfc']['loop'] = asyncio.new_event_loop() +asyncio.set_event_loop(LEDGER['hfc']['loop']) + +LEDGER['hfc']['client'] = Client() +LEDGER['hfc']['client'].new_channel(LEDGER['channel_name']) + +LEDGER['hfc']['requestor'] = create_user( + name=LEDGER['client']['name'], + org=LEDGER['client']['org'], + state_store=FileKeyValueStore(LEDGER['client']['state_store']), + msp_id=LEDGER['client']['msp_id'], + key_path=glob.glob(LEDGER['client']['key_path'])[0], + cert_path=LEDGER['client']['cert_path'] +) + +target_peer = Peer(name=LEDGER['peer']['name']) + +# Need loop +target_peer.init_with_bundle({ + 'url': f'{LEDGER["peer"]["host"]}:{PEER_PORT}', + 'grpcOptions': LEDGER['peer']['grpcOptions'], + 'tlsCACerts': {'path': LEDGER['peer']['tlsCACerts']}, + 'clientKey': {'path': LEDGER['peer']['clientKey']}, + 'clientCert': {'path': LEDGER['peer']['clientCert']}, +}) + +LEDGER['hfc']['client']._peers[LEDGER['peer']['name']] = target_peer + +target_orderer = Orderer(name=LEDGER['orderer']['name']) + +# Need loop +target_orderer.init_with_bundle({ + 'url': f'{LEDGER["orderer"]["host"]}:{LEDGER["orderer"]["port"]}', + 'grpcOptions': LEDGER['orderer']['grpcOptions'], + 'tlsCACerts': {'path': LEDGER['orderer']['ca']}, + 'clientKey': {'path': LEDGER['peer']['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': LEDGER['peer']['clientCert']}, # use peer creds (mutual tls) +}) + +LEDGER['hfc']['client']._orderers[LEDGER['orderer']['name']] = target_orderer diff --git a/substrabac/substrabac/settings/deps/org.py b/substrabac/substrabac/settings/deps/org.py new file mode 100644 index 000000000..2de6039f7 --- /dev/null +++ b/substrabac/substrabac/settings/deps/org.py @@ -0,0 +1,6 @@ +import os + +ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') +DEFAULT_PORT = os.environ.get('SUBSTRABAC_DEFAULT_PORT', '8000') +ORG_NAME = ORG.replace('-', '') +ORG_DB_NAME = ORG.replace('-', '_').upper() diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index a385670d1..c8294cef9 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -1,20 +1,15 @@ import os from .common import * -from .ledger import * from .deps.restframework import * from .deps.cors import * +from .deps.org import * +from .deps.ledger import * DEBUG = True -ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') -DEFAULT_PORT = os.environ.get('SUBSTRABAC_DEFAULT_PORT', '8000') -ORG_NAME = ORG.replace('-', '') -ORG_DB_NAME = ORG.replace('-', '_').upper() - - # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases @@ -35,10 +30,8 @@ if not os.path.exists(DRYRUN_ROOT): os.makedirs(DRYRUN_ROOT, exist_ok=True) -SITE_ID = 1 SITE_HOST = f'{ORG_NAME}.substrabac' SITE_PORT = DEFAULT_PORT - DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') LOGGING = { diff --git a/substrabac/substrabac/settings/ledger.py b/substrabac/substrabac/settings/ledger.py deleted file mode 100644 index d28d974f7..000000000 --- a/substrabac/substrabac/settings/ledger.py +++ /dev/null @@ -1,59 +0,0 @@ - -import os -import asyncio -import glob -import json - -from hfc.fabric import Client -from hfc.fabric.peer import Peer -from hfc.fabric.user import create_user -from hfc.fabric.orderer import Orderer -from hfc.util.keyvaluestore import FileKeyValueStore - - -ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') - -LEDGER = json.load(open(f'/substra/conf/{ORG}/substrabac/conf.json', 'r')) - -HLF_LOOP = asyncio.new_event_loop() -asyncio.set_event_loop(HLF_LOOP) - -channel_name = LEDGER['channel_name'] -chaincode_name = LEDGER['chaincode_name'] -peer = LEDGER['peer'] -peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] -orderer = LEDGER['orderer'] - -requestor_config = LEDGER['client'] - -CLIENT = Client() -CLIENT.new_channel(channel_name) - -REQUESTOR = create_user(name=requestor_config['name'], - org=requestor_config['org'], - state_store=FileKeyValueStore(requestor_config['state_store']), - msp_id=requestor_config['msp_id'], - key_path=glob.glob(requestor_config['key_path'])[0], - cert_path=requestor_config['cert_path']) - -target_peer = Peer(name=peer['name']) - -# Need loop -target_peer.init_with_bundle({'url': f'{peer["host"]}:{peer_port}', - 'grpcOptions': peer['grpcOptions'], - 'tlsCACerts': {'path': peer['tlsCACerts']}, - 'clientKey': {'path': peer['clientKey']}, - 'clientCert': {'path': peer['clientCert']}, - }) -CLIENT._peers[peer['name']] = target_peer - -target_orderer = Orderer(name=orderer['name']) - -# Need loop -target_orderer.init_with_bundle({'url': f'{orderer["host"]}:{orderer["port"]}', - 'grpcOptions': orderer['grpcOptions'], - 'tlsCACerts': {'path': orderer['ca']}, - 'clientKey': {'path': peer['clientKey']}, # use peer creds (mutual tls) - 'clientCert': {'path': peer['clientCert']}, # use peer creds (mutual tls) - }) -CLIENT._orderers[orderer['name']] = target_orderer diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 500f2a729..27ba82362 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -1,11 +1,12 @@ import os from .common import * -from .ledger import * from .deps.restframework import * from .deps.cors import * from .deps.raven import * +from .deps.org import * +from .deps.ledger import * DEBUG = False @@ -15,10 +16,13 @@ os.environ['HTTPS'] = "on" os.environ['wsgi.url_scheme'] = 'https' -ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') -DEFAULT_PORT = os.environ.get('SUBSTRABAC_DEFAULT_PORT', '8000') -ORG_NAME = ORG.replace('-', '') -ORG_DB_NAME = ORG.replace('-', '_').upper() +STATIC_URL = '/static/' +STATIC_ROOT = os.path.join(BASE_DIR, 'statics') + +# deactivate when public +BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER', None) +BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', None) +MIDDLEWARE += ['libs.BasicAuthMiddleware.BasicAuthMiddleware'] # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases @@ -37,19 +41,11 @@ MEDIA_ROOT = f'/substra/medias/{ORG_NAME}' DRYRUN_ROOT = f'/substra/dryrun/{ORG}' -STATIC_URL = '/static/' -STATIC_ROOT = os.path.join(BASE_DIR, 'statics') -SITE_ID = 1 SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substrabac') SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) - DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') -# deactivate when public -BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER', None) -BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', None) -MIDDLEWARE += ['libs.BasicAuthMiddleware.BasicAuthMiddleware'] LOGGING = { 'version': 1, diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index e48595895..d5fed9d40 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -32,6 +32,7 @@ # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) class ObjectiveQueryTests(APITestCase): def setUp(self): @@ -270,6 +271,7 @@ def test_get_objective_metrics_wrong_version(self): @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) class DataManagerQueryTests(APITestCase): def setUp(self): @@ -383,6 +385,7 @@ def test_add_datamanager_wrong_version(self): @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) class DataSampleQueryTests(APITestCase): def setUp(self): @@ -895,6 +898,7 @@ def test_bulk_update_data(self): @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) class AlgoQueryTests(APITestCase): def setUp(self): @@ -1093,6 +1097,7 @@ def test_get_algo_files_wrong_version(self): @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) class TraintupleQueryTests(APITestCase): def setUp(self): diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 0457b0de3..35f48d1c6 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -18,10 +18,8 @@ from django.conf import settings LEDGER = getattr(settings, 'LEDGER', None) -CLIENT = getattr(settings, 'CLIENT', None) -REQUESTOR = getattr(settings, 'REQUESTOR', None) -HLF_LOOP = getattr(settings, 'HLF_LOOP', None) -asyncio.set_event_loop(HLF_LOOP) +if LEDGER: + asyncio.set_event_loop(LEDGER['hfc']['loop']) # careful, passing invoke parameters to queryLedger will NOT fail @@ -30,14 +28,17 @@ def queryLedger(fcn, args=None): if args is None: args = [] + peer = LEDGER['peer'] + loop = LEDGER['hfc']['loop'] + client = LEDGER['hfc']['client'] + requestor = LEDGER['hfc']['requestor'] channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] # Get chaincode version - response = HLF_LOOP.run_until_complete( - CLIENT.query_instantiated_chaincodes( - requestor=REQUESTOR, + response = loop.run_until_complete( + client.query_instantiated_chaincodes( + requestor=requestor, channel_name=channel_name, peers=[peer['name']], decode=True @@ -49,9 +50,9 @@ def queryLedger(fcn, args=None): try: # Async - need loop - response = HLF_LOOP.run_until_complete( - CLIENT.chaincode_query( - requestor=REQUESTOR, + response = loop.run_until_complete( + client.chaincode_query( + requestor=requestor, channel_name=channel_name, peers=[peer['name']], args=args, @@ -90,14 +91,17 @@ def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): if args is None: args = [] + peer = LEDGER['peer'] + loop = LEDGER['hfc']['loop'] + client = LEDGER['hfc']['client'] + requestor = LEDGER['hfc']['requestor'] channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] - peer = LEDGER['peer'] # Get chaincode version - response = HLF_LOOP.run_until_complete( - CLIENT.query_instantiated_chaincodes( - requestor=REQUESTOR, + response = loop.run_until_complete( + client.query_instantiated_chaincodes( + requestor=requestor, channel_name=channel_name, peers=[peer['name']], decode=True @@ -110,7 +114,7 @@ def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): try: # Async - need loop kwargs = { - 'requestor': REQUESTOR, + 'requestor': requestor, 'channel_name': channel_name, 'peers': [peer['name']], 'args': args, @@ -123,7 +127,7 @@ def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): if cc_pattern: kwargs['cc_pattern'] = cc_pattern - response = HLF_LOOP.run_until_complete(CLIENT.chaincode_invoke(**kwargs)) + response = loop.run_until_complete(client.chaincode_invoke(**kwargs)) except TimeoutError as e: st = status.HTTP_408_REQUEST_TIMEOUT data = {'message': str(e)} From 39ec92a280f3977d6a0952fc455b601c0d71ab35 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 29 May 2019 11:06:12 +0200 Subject: [PATCH 045/457] Update and clean ledger serializer. --- .../substrapp/serializers/ledger/__init__.py | 2 +- .../serializers/ledger/algo/serializer.py | 29 +++++++++++-------- .../substrapp/serializers/ledger/algo/util.py | 7 +++-- .../ledger/datamanager/serializer.py | 23 ++++++++------- .../serializers/ledger/datamanager/util.py | 12 ++++---- .../ledger/datasample/serializer.py | 6 ++-- .../serializers/ledger/datasample/util.py | 14 ++++----- .../serializers/ledger/model/__init__.py | 0 .../ledger/{model.py => model/serializer.py} | 0 .../ledger/objective/serializer.py | 15 ++++++---- .../serializers/ledger/objective/util.py | 7 +++-- .../ledger/testtuple/serializer.py | 7 ++--- .../ledger/traintuple/serializer.py | 11 ++++--- .../serializers/ledger/traintuple/util.py | 2 +- 14 files changed, 71 insertions(+), 64 deletions(-) create mode 100644 substrabac/substrapp/serializers/ledger/model/__init__.py rename substrabac/substrapp/serializers/ledger/{model.py => model/serializer.py} (100%) diff --git a/substrabac/substrapp/serializers/ledger/__init__.py b/substrabac/substrapp/serializers/ledger/__init__.py index 929e5c3af..32927cbab 100644 --- a/substrabac/substrapp/serializers/ledger/__init__.py +++ b/substrabac/substrapp/serializers/ledger/__init__.py @@ -1,7 +1,7 @@ # encoding: utf-8 from .objective.serializer import LedgerObjectiveSerializer -from .model import LedgerModelSerializer +from .model.serializer import LedgerModelSerializer from .datasample.serializer import LedgerDataSampleSerializer from .algo.serializer import LedgerAlgoSerializer from .traintuple.serializer import LedgerTrainTupleSerializer diff --git a/substrabac/substrapp/serializers/ledger/algo/serializer.py b/substrabac/substrapp/serializers/ledger/algo/serializer.py index 456c28168..85d6a7945 100644 --- a/substrabac/substrapp/serializers/ledger/algo/serializer.py +++ b/substrabac/substrapp/serializers/ledger/algo/serializer.py @@ -18,12 +18,16 @@ def create(self, validated_data): permissions = validated_data.get('permissions') # TODO, create a datamigration with new Site domain name when we will know the name of the final website - # current_site = Site.objects.get_current() + host = '' + protocol = 'http://' request = self.context.get('request', None) - protocol = 'https://' if request.is_secure() else 'http://' - host = '' if request is None else request.get_host() - # args = '"%(name)s", "%(algoHash)s", "%(storageAddress)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(permissions)s"' % { # noqa + if request: + protocol = 'https://' if request.is_secure() else 'http://' + host = request.get_host() + + # Json + # args = { # 'name': name, # 'algoHash': get_hash(instance.file), # 'storageAddress': protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), @@ -32,12 +36,14 @@ def create(self, validated_data): # 'permissions': permissions # } - args = [name, - get_hash(instance.file), - protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), - get_hash(instance.description), - protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), - permissions] + args = [ + name, + get_hash(instance.file), + protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), + get_hash(instance.description), + protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), + permissions, + ] if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerAlgo(args, instance.pkhash, sync=True) @@ -48,5 +54,4 @@ def create(self, validated_data): 'message': 'Algo added in local db waiting for validation. ' 'The substra network has been notified for adding this Algo' } - st = status.HTTP_202_ACCEPTED - return data, st + return data, status.HTTP_202_ACCEPTED diff --git a/substrabac/substrapp/serializers/ledger/algo/util.py b/substrabac/substrapp/serializers/ledger/algo/util.py index 7add6d6aa..3a064be31 100644 --- a/substrabac/substrapp/serializers/ledger/algo/util.py +++ b/substrabac/substrapp/serializers/ledger/algo/util.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, unicode_literals from rest_framework import status +from django.core.exceptions import ObjectDoesNotExist from substrapp.models import Algo from substrapp.utils import invokeLedger @@ -9,19 +10,19 @@ def createLedgerAlgo(args, pkhash, sync=False): data, st = invokeLedger(fcn='registerAlgo', args=args, sync=sync) - # if not created on ledger, delete from local db, else pass to validated true try: instance = Algo.objects.get(pk=pkhash) - except Exception: + except ObjectDoesNotExist: pass else: + # if not created on ledger, delete from local db if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): instance.delete() else: + # if created on ledger if st != status.HTTP_408_REQUEST_TIMEOUT: instance.validated = True instance.save() - # update data to return data['validated'] = True return data, st diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py index b89280264..1628f83fa 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py @@ -10,28 +10,32 @@ class LedgerDataManagerSerializer(serializers.Serializer): name = serializers.CharField(max_length=100) - type = serializers.CharField(max_length=30) + data_type = serializers.CharField(max_length=30) objective_key = serializers.CharField(max_length=256, allow_blank=True, required=False) permissions = serializers.CharField(min_length=1, max_length=60) def create(self, validated_data): instance = self.initial_data.get('instance') name = validated_data.get('name') - type = validated_data.get('type') + data_type = validated_data.get('type') permissions = validated_data.get('permissions') objective_key = validated_data.get('objective_key', '') # TODO, create a datamigration with new Site domain name when we will know the name of the final website - # current_site = Site.objects.get_current() + host = '' + protocol = 'http://' request = self.context.get('request', None) - protocol = 'https://' if request.is_secure() else 'http://' - host = '' if request is None else request.get_host() - # args = '"%(name)s", "%(openerHash)s", "%(openerStorageAddress)s", "%(type)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(objectiveKey)s", "%(permissions)s"' % { # noqa + if request: + protocol = 'https://' if request.is_secure() else 'http://' + host = request.get_host() + + # Json + # args = { # 'name': name, # 'openerHash': get_hash(instance.data_opener), # 'openerStorageAddress': protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), - # 'type': type, + # 'type': data_type, # 'descriptionHash': get_hash(instance.description), # 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), # noqa # 'objectiveKey': objective_key, @@ -42,7 +46,7 @@ def create(self, validated_data): name, get_hash(instance.data_opener), protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), - type, + data_type, get_hash(instance.description), protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), objective_key, @@ -59,5 +63,4 @@ def create(self, validated_data): 'message': 'DataManager added in local db waiting for validation. ' 'The substra network has been notified for adding this DataManager' } - st = status.HTTP_202_ACCEPTED - return data, st + return data, status.HTTP_202_ACCEPTED diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substrabac/substrapp/serializers/ledger/datamanager/util.py index 8ee5ffc5c..d12ce5b55 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/util.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/util.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, unicode_literals from rest_framework import status +from django.core.exceptions import ObjectDoesNotExist from substrapp.models import DataManager from substrapp.utils import invokeLedger @@ -9,26 +10,23 @@ def createLedgerDataManager(args, pkhash, sync=False): data, st = invokeLedger(fcn='registerDataManager', args=args, sync=sync) - # if not created on ledger, delete from local db, else pass to validated true try: instance = DataManager.objects.get(pk=pkhash) - except Exception: + except ObjectDoesNotExist: pass else: + # if not created on ledger, delete from local db if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): instance.delete() else: + # if created on ledger if st != status.HTTP_408_REQUEST_TIMEOUT: instance.validated = True instance.save() - # update data to return data['validated'] = True return data, st def updateLedgerDataManager(args, sync=False): - - data, st = invokeLedger(fcn='updateDataManager', args=args, sync=sync) - - return data, st + return invokeLedger(fcn='updateDataManager', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/datasample/serializer.py b/substrabac/substrapp/serializers/ledger/datasample/serializer.py index f92dd6e47..7cddd2c95 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datasample/serializer.py @@ -18,7 +18,8 @@ def create(self, validated_data): data_manager_keys = validated_data.get('data_manager_keys') test_only = validated_data.get('test_only') - # args = '"%(hashes)s", "%(dataManagerKeys)s", "%(testOnly)s"' % { + # Json + # args = { # 'hashes': ','.join([x.pk for x in instances]), # 'dataManagerKeys': ','.join([x for x in data_manager_keys]), # 'testOnly': json.dumps(test_only), @@ -39,5 +40,4 @@ def create(self, validated_data): 'message': 'Data samples added in local db waiting for validation. ' 'The substra network has been notified for adding this Data' } - st = status.HTTP_202_ACCEPTED - return data, st + return data, status.HTTP_202_ACCEPTED diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substrabac/substrapp/serializers/ledger/datasample/util.py index 9725aa985..6c23fe7b5 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/util.py +++ b/substrabac/substrapp/serializers/ledger/datasample/util.py @@ -1,33 +1,31 @@ from __future__ import absolute_import, unicode_literals from rest_framework import status +from django.core.exceptions import ObjectDoesNotExist from substrapp.models import DataSample from substrapp.utils import invokeLedger def createLedgerDataSample(args, pkhashes, sync=False): + data, st = invokeLedger(fcn='registerDataSample', args=args, sync=sync) - # if not created on ledger, delete from local db, else pass to validated true try: instances = DataSample.objects.filter(pk__in=pkhashes) - except Exception: + except ObjectDoesNotExist: pass else: - - # delete if not created + # if not created on ledger, delete from local db if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): instances.delete() else: - # do not pass to true if still waiting for validation + # if created on ledger if st != status.HTTP_408_REQUEST_TIMEOUT: instances.update(validated=True) - # update data to return data['validated'] = True return data, st def updateLedgerDataSample(args, sync=False): - data, st = invokeLedger(fcn='updateDataSample', args=args, sync=sync) - return data, st + return invokeLedger(fcn='updateDataSample', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/model/__init__.py b/substrabac/substrapp/serializers/ledger/model/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/substrapp/serializers/ledger/model.py b/substrabac/substrapp/serializers/ledger/model/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/model.py rename to substrabac/substrapp/serializers/ledger/model/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/objective/serializer.py b/substrabac/substrapp/serializers/ledger/objective/serializer.py index 73c31757e..cd9d5ffaf 100644 --- a/substrabac/substrapp/serializers/ledger/objective/serializer.py +++ b/substrabac/substrapp/serializers/ledger/objective/serializer.py @@ -26,12 +26,16 @@ def create(self, validated_data): test_data_sample_keys = validated_data.get('test_data_sample_keys', []) # TODO, create a datamigration with new Site domain name when we will know the name of the final website - # current_site = Site.objects.get_current() + host = '' + protocol = 'http://' request = self.context.get('request', None) - protocol = 'https://' if request.is_secure() else 'http://' - host = '' if request is None else request.get_host() - # args = '"%(name)s", "%(descriptionHash)s", "%(descriptionStorageAddress)s", "%(metricsName)s", "%(metricsHash)s", "%(metricsStorageAddress)s", "%(testDataSample)s", "%(permissions)s"' % { # noqa + if request: + protocol = 'https://' if request.is_secure() else 'http://' + host = request.get_host() + + # Json + # args = { # 'name': name, # 'descriptionHash': get_hash(instance.description), # 'descriptionStorageAddress': protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), # noqa @@ -62,5 +66,4 @@ def create(self, validated_data): 'message': 'Objective added in local db waiting for validation. ' 'The substra network has been notified for adding this Objective' } - st = status.HTTP_202_ACCEPTED - return data, st + return data, status.HTTP_202_ACCEPTED diff --git a/substrabac/substrapp/serializers/ledger/objective/util.py b/substrabac/substrapp/serializers/ledger/objective/util.py index cf4f191ef..c71e81cae 100644 --- a/substrabac/substrapp/serializers/ledger/objective/util.py +++ b/substrabac/substrapp/serializers/ledger/objective/util.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, unicode_literals from rest_framework import status +from django.core.exceptions import ObjectDoesNotExist from substrapp.models import Objective from substrapp.utils import invokeLedger @@ -9,19 +10,19 @@ def createLedgerObjective(args, pkhash, sync=False): data, st = invokeLedger(fcn='registerObjective', args=args, sync=sync) - # if not created on ledger, delete from local db, else pass to validated true try: instance = Objective.objects.get(pk=pkhash) - except Exception: + except ObjectDoesNotExist: pass else: + # if not created on ledger, delete from local db if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): instance.delete() else: + # if created on ledger if st != status.HTTP_408_REQUEST_TIMEOUT: instance.validated = True instance.save() - # update data to return data['validated'] = True return data, st diff --git a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py index 7a0e4ac93..2ada1638a 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py @@ -20,7 +20,8 @@ def get_args(self, validated_data): test_data_sample_keys = validated_data.get('test_data_sample_keys', []) tag = validated_data.get('tag', '') - # args = '"%(traintupleKey)s", "%(dataManagerKey)s", "%(dataSampleKeys)s", "%(tag)s"' % { + # Json + # args = { # 'traintupleKey': traintuple_key, # 'dataManagerKey': data_manager_key, # 'dataSampleKeys': ','.join(test_data_sample_keys), @@ -44,11 +45,9 @@ def create(self, validated_data): else: # use a celery task, as we are in an http request transaction createLedgerTesttupleAsync.delay(args) - data = { 'message': 'The substra network has been notified for adding this Testtuple. ' 'Please be aware you won\'t get return values from the ledger. ' 'You will need to check manually' } - st = status.HTTP_202_ACCEPTED - return data, st + return data, status.HTTP_202_ACCEPTED diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index 4cd372f7b..cbb4de2df 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -28,17 +28,18 @@ def get_args(self, validated_data): rank = '' if rank is None else rank # rank should be an integer or empty string, not None FLtask_key = validated_data.get('FLtask_key', '') train_data_sample_keys = validated_data.get('train_data_sample_keys', []) - in_models_keys = validated_data.get('in_models_keys') + in_models_keys = validated_data.get('in_models_keys', []) tag = validated_data.get('tag', '') - # args = '"%(algoKey)s", "%(associatedObjective)s", "%(inModels)s", "%(dataManagerKey)s", "%(dataSampleKeys)s", "%(FLtask)s", "%(rank)s", "%(tag)s"' % { # noqa + # Json + # args = { # 'algoKey': algo_key, # 'associatedObjective': objective_key, # 'inModels': ','.join(in_models_keys), # 'dataManagerKey': data_manager_key, # 'dataSampleKeys': ','.join(train_data_sample_keys), # 'FLtask': FLtask_key, - # 'rank': rank, + # 'rank': str(rank), # 'tag': tag # } @@ -63,11 +64,9 @@ def create(self, validated_data): else: # use a celery task, as we are in an http request transaction createLedgerTraintupleAsync.delay(args) - data = { 'message': 'The substra network has been notified for adding this Traintuple. ' 'Please be aware you won\'t get return values from the ledger. ' 'You will need to check manually' } - st = status.HTTP_202_ACCEPTED - return data, st + return data, status.HTTP_202_ACCEPTED diff --git a/substrabac/substrapp/serializers/ledger/traintuple/util.py b/substrabac/substrapp/serializers/ledger/traintuple/util.py index fa9e610f8..be771ee07 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/util.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/util.py @@ -5,4 +5,4 @@ def createLedgerTraintuple(args, sync=False): - return invokeLedger(fcn='createTraintuple', args=args, cc_pattern='traintuple-creation', sync=sync) + return invokeLedger(fcn='createTraintuple', args=args, sync=sync) From 38c34ee48d558ad139fd7754287d598f61ca8d87 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 29 May 2019 11:43:15 +0200 Subject: [PATCH 046/457] Fix serializer --- .../substrapp/serializers/ledger/datamanager/serializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py index 1628f83fa..684724e3d 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py @@ -10,7 +10,7 @@ class LedgerDataManagerSerializer(serializers.Serializer): name = serializers.CharField(max_length=100) - data_type = serializers.CharField(max_length=30) + type = serializers.CharField(max_length=30) objective_key = serializers.CharField(max_length=256, allow_blank=True, required=False) permissions = serializers.CharField(min_length=1, max_length=60) From 86ba759bf480107153e08d7bb38ef9a0c072cb97 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 29 May 2019 11:43:35 +0200 Subject: [PATCH 047/457] Improve signals. --- .../substrapp/signals/datasample/pre_save.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/substrabac/substrapp/signals/datasample/pre_save.py b/substrabac/substrapp/signals/datasample/pre_save.py index 5ef1df5ab..75ed866ec 100644 --- a/substrabac/substrapp/signals/datasample/pre_save.py +++ b/substrabac/substrapp/signals/datasample/pre_save.py @@ -29,30 +29,32 @@ def data_sample_pre_save(sender, instance, **kwargs): instance.path.seek(0) uncompress_content(content, directory) except Exception as e: - logging.info(e) + logging.exception(e) raise e else: - # calculate new hash + # compute new hash sha256hash = dirhash(directory, 'sha256') # rename directory to new hash if does not exist new_directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'datasamples', sha256hash) try: rename(directory, new_directory) - except Exception as e: - # directory already exists with same exact data sample inside + except OSError as e: + # new_directory already exists with same exact data sample inside # created by a previous save, delete directory entitled pkhash # for avoiding duplicates shutil.rmtree(directory) - logging.error(e, exc_info=True) + logging.exception(e) # override defaults instance.pkhash = sha256hash instance.path = new_directory + # make an hardlink on all files if a path else: + # try to make an hard link to keep a free copy of the data + # if not possible, keep the real path location try: - p = normpath(instance.path) - create_hard_links(p, directory) + create_hard_links(normpath(instance.path), directory) except Exception: pass else: From ce7d70e616df9ff706cdbe43b8b8ed84ca380345 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 29 May 2019 14:31:28 +0200 Subject: [PATCH 048/457] Update and refacto ledger function --- substrabac/substrapp/ledger_utils.py | 158 ++++++++++++++++++ .../substrapp/serializers/ledger/algo/util.py | 2 +- .../serializers/ledger/datamanager/util.py | 2 +- .../serializers/ledger/datasample/util.py | 2 +- .../serializers/ledger/objective/util.py | 2 +- .../serializers/ledger/testtuple/util.py | 2 +- .../serializers/ledger/traintuple/util.py | 2 +- substrabac/substrapp/tasks/tasks.py | 3 +- substrabac/substrapp/tests/tests_query.py | 2 + substrabac/substrapp/tests/tests_views.py | 18 +- substrabac/substrapp/utils.py | 139 +-------------- substrabac/substrapp/views/algo.py | 5 +- substrabac/substrapp/views/datamanager.py | 22 +-- substrabac/substrapp/views/model.py | 10 +- substrabac/substrapp/views/objective.py | 6 +- substrabac/substrapp/views/testtuple.py | 7 +- substrabac/substrapp/views/traintuple.py | 22 +-- substrabac/substrapp/views/utils.py | 24 +-- 18 files changed, 206 insertions(+), 222 deletions(-) create mode 100644 substrabac/substrapp/ledger_utils.py diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py new file mode 100644 index 000000000..b9ae1f47f --- /dev/null +++ b/substrabac/substrapp/ledger_utils.py @@ -0,0 +1,158 @@ +import asyncio +import json + +from rest_framework import status +from django.conf import settings +from django.http import Http404 + +from substrapp.utils import JsonException + +LEDGER = getattr(settings, 'LEDGER', None) +if LEDGER: + asyncio.set_event_loop(LEDGER['hfc']['loop']) + + +# careful, passing invoke parameters to queryLedger will NOT fail +def queryLedger(fcn, args=None): + + if args is None: + args = [] + + peer = LEDGER['peer'] + loop = LEDGER['hfc']['loop'] + client = LEDGER['hfc']['client'] + requestor = LEDGER['hfc']['requestor'] + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + + # Get chaincode version + response = loop.run_until_complete( + client.query_instantiated_chaincodes( + requestor=requestor, + channel_name=channel_name, + peers=[peer['name']], + decode=True + )) + for ccs in response: + for cc in ccs.chaincodes: + if cc.name == chaincode_name: + chaincode_version = cc.version + + try: + # Async - need loop + response = loop.run_until_complete( + client.chaincode_query( + requestor=requestor, + channel_name=channel_name, + peers=[peer['name']], + args=args, + cc_name=chaincode_name, + cc_version=chaincode_version, + fcn=fcn)) + except Exception as e: + st = status.HTTP_400_BAD_REQUEST + data = {'message': str(e)} + else: + msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' + print(msg, flush=True) + + st = status.HTTP_200_OK + + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py + try: + # json transformation if needed + data = json.loads(response) + except json.decoder.JSONDecodeError: + st = status.HTTP_400_BAD_REQUEST + + if 'access denied' in response: + st = status.HTTP_403_FORBIDDEN + elif 'no element with key' in response: + st = status.HTTP_404_NOT_FOUND + + data = {'message': response} + + return data, st + + +def getObjectFromLedger(pk, query): + # get instance from remote node + data, st = queryLedger(fcn=query, args=[f'{pk}']) + + if st == status.HTTP_404_NOT_FOUND: + raise Http404('Not found') + + if st != status.HTTP_200_OK: + raise JsonException(data) + + if 'permissions' not in data or data['permissions'] == 'all': + return data + else: + raise Exception('Not Allowed') + + +def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): + + if args is None: + args = [] + + peer = LEDGER['peer'] + loop = LEDGER['hfc']['loop'] + client = LEDGER['hfc']['client'] + requestor = LEDGER['hfc']['requestor'] + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + + # Get chaincode version + response = loop.run_until_complete( + client.query_instantiated_chaincodes( + requestor=requestor, + channel_name=channel_name, + peers=[peer['name']], + decode=True + )) + for ccs in response: + for cc in ccs.chaincodes: + if cc.name == chaincode_name: + chaincode_version = cc.version + + try: + # Async - need loop + kwargs = { + 'requestor': requestor, + 'channel_name': channel_name, + 'peers': [peer['name']], + 'args': args, + 'cc_name': chaincode_name, + 'cc_version': chaincode_version, + 'fcn': fcn, + 'wait_for_event': sync, + 'wait_for_event_timeout': 45 + } + if cc_pattern: + kwargs['cc_pattern'] = cc_pattern + + response = loop.run_until_complete(client.chaincode_invoke(**kwargs)) + except TimeoutError as e: + st = status.HTTP_408_REQUEST_TIMEOUT + data = {'message': str(e)} + except Exception as e: + st = status.HTTP_400_BAD_REQUEST + data = {'message': str(e)} + else: + # TO DO : review parsing error in case of failure + # May have changed by using fabric-sdk-py + # elif 'access denied' in msg or 'authentication handshake failed' in msg: + # st = status.HTTP_403_FORBIDDEN + + st = status.HTTP_201_CREATED + try: + response = json.loads(response) + pkhash = response.get('key', response.get('keys')) + data = {'pkhash': pkhash} + except json.decoder.JSONDecodeError: + st = status.HTTP_400_BAD_REQUEST + data = {'message': response} + + return data, st diff --git a/substrabac/substrapp/serializers/ledger/algo/util.py b/substrabac/substrapp/serializers/ledger/algo/util.py index 3a064be31..7d4c9f71d 100644 --- a/substrabac/substrapp/serializers/ledger/algo/util.py +++ b/substrabac/substrapp/serializers/ledger/algo/util.py @@ -3,7 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist from substrapp.models import Algo -from substrapp.utils import invokeLedger +from substrapp.ledger_utils import invokeLedger def createLedgerAlgo(args, pkhash, sync=False): diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substrabac/substrapp/serializers/ledger/datamanager/util.py index d12ce5b55..c8a1103a0 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/util.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/util.py @@ -3,7 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist from substrapp.models import DataManager -from substrapp.utils import invokeLedger +from substrapp.ledger_utils import invokeLedger def createLedgerDataManager(args, pkhash, sync=False): diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substrabac/substrapp/serializers/ledger/datasample/util.py index 6c23fe7b5..53f9f22f4 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/util.py +++ b/substrabac/substrapp/serializers/ledger/datasample/util.py @@ -3,7 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist from substrapp.models import DataSample -from substrapp.utils import invokeLedger +from substrapp.ledger_utils import invokeLedger def createLedgerDataSample(args, pkhashes, sync=False): diff --git a/substrabac/substrapp/serializers/ledger/objective/util.py b/substrabac/substrapp/serializers/ledger/objective/util.py index c71e81cae..f311bd6ad 100644 --- a/substrabac/substrapp/serializers/ledger/objective/util.py +++ b/substrabac/substrapp/serializers/ledger/objective/util.py @@ -3,7 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist from substrapp.models import Objective -from substrapp.utils import invokeLedger +from substrapp.ledger_utils import invokeLedger def createLedgerObjective(args, pkhash, sync=False): diff --git a/substrabac/substrapp/serializers/ledger/testtuple/util.py b/substrabac/substrapp/serializers/ledger/testtuple/util.py index d94056c33..ecb441011 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/util.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/util.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, unicode_literals -from substrapp.utils import invokeLedger +from substrapp.ledger_utils import invokeLedger def createLedgerTesttuple(args, sync=False): diff --git a/substrabac/substrapp/serializers/ledger/traintuple/util.py b/substrabac/substrapp/serializers/ledger/traintuple/util.py index be771ee07..5ea3c58b0 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/util.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/util.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, unicode_literals -from substrapp.utils import invokeLedger +from substrapp.ledger_utils import invokeLedger def createLedgerTraintuple(args, sync=False): diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 9b372fab4..c3c2e2301 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -11,7 +11,8 @@ from rest_framework.reverse import reverse from substrabac.celery import app -from substrapp.utils import queryLedger, invokeLedger, get_hash, create_directory, get_remote_file, uncompress_content +from substrapp.ledger_utils import queryLedger, invokeLedger +from substrapp.utils import get_hash, create_directory, get_remote_file, uncompress_content from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index d5fed9d40..55f033fe3 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -239,8 +239,10 @@ def test_get_objective_metrics(self): extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } + print(self.objective_metrics) response = self.client.get( f'/objective/{objective.pkhash}/metrics/', **extra) + self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertNotEqual(objective.pkhash, compute_hash(response.getvalue())) diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py index 9a2e5abbd..7c7137322 100644 --- a/substrabac/substrapp/tests/tests_views.py +++ b/substrabac/substrapp/tests/tests_views.py @@ -10,14 +10,16 @@ from rest_framework import status from rest_framework.test import APITestCase -from substrapp.views import DataManagerViewSet, TrainTupleViewSet, TestTupleViewSet, DataSampleViewSet +from substrapp.views import TrainTupleViewSet, TestTupleViewSet, DataSampleViewSet from substrapp.serializers import LedgerDataSampleSerializer, LedgerObjectiveSerializer, LedgerAlgoSerializer -from substrapp.views.utils import JsonException, ComputeHashMixin, getObjectFromLedger +from substrapp.utils import JsonException +from substrapp.views.utils import ComputeHashMixin from substrapp.views.datasample import path_leaf, compute_dryrun as data_sample_compute_dryrun from substrapp.views.objective import compute_dryrun as objective_compute_dryrun from substrapp.utils import compute_hash, get_hash +from substrapp.ledger_utils import getObjectFromLedger from substrapp.models import DataManager @@ -55,13 +57,13 @@ def test_utils_ComputeHashMixin(self): def test_utils_getObjectFromLedger(self): - with mock.patch('substrapp.views.utils.queryLedger') as mqueryLedger: + with mock.patch('substrapp.ledger_utils.queryLedger') as mqueryLedger: mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] data = getObjectFromLedger('', 'queryObjective') self.assertEqual(data, objective) - with mock.patch('substrapp.views.utils.queryLedger') as mqueryLedger: + with mock.patch('substrapp.ledger_utils.queryLedger') as mqueryLedger: mqueryLedger.side_effect = [('', status.HTTP_400_BAD_REQUEST)] with self.assertRaises(JsonException): getObjectFromLedger('', 'queryAllObjective') @@ -730,7 +732,7 @@ def test_datamanager_retrieve(self): url = reverse('substrapp:data_manager-list') datamanager_response = [d for d in datamanager if d['key'] == '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7'][0] - with mock.patch.object(DataManagerViewSet, 'getObjectFromLedger') as mgetObjectFromLedger, \ + with mock.patch('substrapp.views.datamanager.getObjectFromLedger') as mgetObjectFromLedger, \ mock.patch('substrapp.views.datamanager.requests.get') as mrequestsget: mgetObjectFromLedger.return_value = datamanager_response @@ -768,7 +770,7 @@ def test_datamanager_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - with mock.patch.object(DataManagerViewSet, 'getObjectFromLedger') as mgetObjectFromLedger: + with mock.patch('substrapp.views.datamanager.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) @@ -844,7 +846,7 @@ def test_traintuple_list_empty(self): def test_traintuple_retrieve(self): - with mock.patch.object(TrainTupleViewSet, 'getObjectFromLedger') as mgetObjectFromLedger: + with mock.patch('substrapp.views.traintuple.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.return_value = traintuple[0] url = reverse('substrapp:traintuple-list') search_params = 'c164f4c714a78c7e2ba2016de231cdd41e3eac61289e08c1f711e74915a0868f/' @@ -867,7 +869,7 @@ def test_traintuple_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - with mock.patch.object(TrainTupleViewSet, 'getObjectFromLedger') as mgetObjectFromLedger: + with mock.patch('substrapp.views.traintuple.getObjectFromLedger') as mgetObjectFromLedger: mgetObjectFromLedger.side_effect = JsonException('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 35f48d1c6..650d8024c 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -1,8 +1,6 @@ import io -import asyncio import hashlib -import json import logging import os import tempfile @@ -13,143 +11,14 @@ import zipfile from checksumdir import dirhash -from rest_framework import status from django.conf import settings -LEDGER = getattr(settings, 'LEDGER', None) -if LEDGER: - asyncio.set_event_loop(LEDGER['hfc']['loop']) - - -# careful, passing invoke parameters to queryLedger will NOT fail -def queryLedger(fcn, args=None): - - if args is None: - args = [] - - peer = LEDGER['peer'] - loop = LEDGER['hfc']['loop'] - client = LEDGER['hfc']['client'] - requestor = LEDGER['hfc']['requestor'] - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - - # Get chaincode version - response = loop.run_until_complete( - client.query_instantiated_chaincodes( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - decode=True - )) - for ccs in response: - for cc in ccs.chaincodes: - if cc.name == chaincode_name: - chaincode_version = cc.version - try: - # Async - need loop - response = loop.run_until_complete( - client.chaincode_query( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - args=args, - cc_name=chaincode_name, - cc_version=chaincode_version, - fcn=fcn)) - except Exception as e: - st = status.HTTP_400_BAD_REQUEST - data = {'message': str(e)} - else: - msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' - print(msg, flush=True) - - st = status.HTTP_200_OK - - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - try: - # json transformation if needed - data = json.loads(response) - except json.decoder.JSONDecodeError: - st = status.HTTP_400_BAD_REQUEST - - if 'access denied' in response: - st = status.HTTP_403_FORBIDDEN - elif 'no element with key' in response: - st = status.HTTP_404_NOT_FOUND - - data = {'message': response} - - return data, st - - -def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): - - if args is None: - args = [] - - peer = LEDGER['peer'] - loop = LEDGER['hfc']['loop'] - client = LEDGER['hfc']['client'] - requestor = LEDGER['hfc']['requestor'] - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - - # Get chaincode version - response = loop.run_until_complete( - client.query_instantiated_chaincodes( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - decode=True - )) - for ccs in response: - for cc in ccs.chaincodes: - if cc.name == chaincode_name: - chaincode_version = cc.version - - try: - # Async - need loop - kwargs = { - 'requestor': requestor, - 'channel_name': channel_name, - 'peers': [peer['name']], - 'args': args, - 'cc_name': chaincode_name, - 'cc_version': chaincode_version, - 'fcn': fcn, - 'wait_for_event': sync, - 'wait_for_event_timeout': 45 - } - if cc_pattern: - kwargs['cc_pattern'] = cc_pattern - - response = loop.run_until_complete(client.chaincode_invoke(**kwargs)) - except TimeoutError as e: - st = status.HTTP_408_REQUEST_TIMEOUT - data = {'message': str(e)} - except Exception as e: - st = status.HTTP_400_BAD_REQUEST - data = {'message': str(e)} - else: - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - # elif 'access denied' in msg or 'authentication handshake failed' in msg: - # st = status.HTTP_403_FORBIDDEN - - st = status.HTTP_201_CREATED - try: - response = json.loads(response) - pkhash = response.get('key', response.get('keys')) - data = {'pkhash': pkhash} - except json.decoder.JSONDecodeError: - st = status.HTTP_400_BAD_REQUEST - data = {'message': response} - - return data, st +class JsonException(Exception): + def __init__(self, msg): + self.msg = msg + super(JsonException, self).__init__() def get_dir_hash(archive_content): diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 2514d1112..5b67ef882 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -11,8 +11,9 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer -from substrapp.utils import queryLedger, get_hash -from substrapp.views.utils import (get_filters, getObjectFromLedger, ComputeHashMixin, ManageFileMixin, JsonException, +from substrapp.utils import get_hash, JsonException +from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.views.utils import (get_filters, ComputeHashMixin, ManageFileMixin, find_primary_key_error) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index c8970a765..10f55e50c 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -16,8 +16,9 @@ from substrapp.serializers import DataManagerSerializer, LedgerDataManagerSerializer from substrapp.serializers.ledger.datamanager.util import updateLedgerDataManager from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync -from substrapp.utils import queryLedger, get_hash -from substrapp.views.utils import get_filters, ManageFileMixin, ComputeHashMixin, JsonException, find_primary_key_error +from substrapp.utils import get_hash, JsonException +from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.views.utils import get_filters, ManageFileMixin, ComputeHashMixin, find_primary_key_error class DataManagerViewSet(mixins.CreateModelMixin, @@ -177,21 +178,6 @@ def create_or_update_datamanager(self, instance, datamanager, pk): return instance - def getObjectFromLedger(self, pk): - # get instance from remote node - data, st = queryLedger(fcn='queryDataset', args=[f'{pk}']) - - if st == status.HTTP_404_NOT_FOUND: - raise Http404('Not found') - - if st != status.HTTP_200_OK: - raise JsonException(data) - - if data['permissions'] == 'all': - return data - else: - raise Exception('Not Allowed') - def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] @@ -206,7 +192,7 @@ def retrieve(self, request, *args, **kwargs): else: # get instance from remote node try: - data = self.getObjectFromLedger(pk) # datamanager use particular query to ledger + data = getObjectFromLedger(pk, 'queryDataset') except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 4c34bf324..1eee76e35 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -11,10 +11,9 @@ from substrapp.models import Model from substrapp.serializers import ModelSerializer -# from hfc.fabric import Client -# cli = Client(net_profile="../network.json") -from substrapp.utils import queryLedger -from substrapp.views.utils import get_filters, ComputeHashMixin, getObjectFromLedger, CustomFileResponse, JsonException +from substrapp.utils import JsonException +from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.views.utils import get_filters, ComputeHashMixin, CustomFileResponse class ModelViewSet(mixins.RetrieveModelMixin, @@ -23,6 +22,7 @@ class ModelViewSet(mixins.RetrieveModelMixin, GenericViewSet): queryset = Model.objects.all() serializer_class = ModelSerializer + ledger_query_call = 'queryModelDetails' # permission_classes = (permissions.IsAuthenticated,) @@ -76,7 +76,7 @@ def retrieve(self, request, *args, **kwargs): else: # get instance from remote node try: - data = getObjectFromLedger(pk, 'queryModelDetails') + data = getObjectFromLedger(pk, self.ledger_query_call) except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 1080f0662..1efa7f676 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -23,10 +23,10 @@ from substrapp.models import Objective from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer - -from substrapp.utils import queryLedger, get_hash, get_computed_hash +from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.utils import get_hash, get_computed_hash, JsonException from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.views.utils import (get_filters, getObjectFromLedger, ComputeHashMixin, ManageFileMixin, JsonException, +from substrapp.views.utils import (get_filters, ComputeHashMixin, ManageFileMixin, find_primary_key_error) diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index f94fac844..38acca786 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -4,8 +4,8 @@ from rest_framework.viewsets import GenericViewSet from substrapp.serializers import LedgerTestTupleSerializer -from substrapp.utils import queryLedger -from substrapp.views.utils import getObjectFromLedger, JsonException +from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.utils import JsonException class TestTupleViewSet(mixins.CreateModelMixin, @@ -13,6 +13,7 @@ class TestTupleViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, GenericViewSet): serializer_class = LedgerTestTupleSerializer + ledger_query_call = 'queryTesttuple' def get_queryset(self): queryset = [] @@ -107,7 +108,7 @@ def retrieve(self, request, *args, **kwargs): else: # get instance from remote node try: - data = getObjectFromLedger(pk, 'queryTesttuple') + data = getObjectFromLedger(pk, self.ledger_query_call) except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index b3c0d9017..03be3ae16 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -4,8 +4,8 @@ from rest_framework.viewsets import GenericViewSet from substrapp.serializers import LedgerTrainTupleSerializer -from substrapp.utils import queryLedger -from substrapp.views.utils import JsonException +from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.utils import JsonException class TrainTupleViewSet(mixins.CreateModelMixin, @@ -13,6 +13,7 @@ class TrainTupleViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, GenericViewSet): serializer_class = LedgerTrainTupleSerializer + ledger_query_call = 'queryTraintuple' def get_queryset(self): queryset = [] @@ -104,21 +105,6 @@ def list(self, request, *args, **kwargs): return Response(data, status=st) - def getObjectFromLedger(self, pk): - # get instance from remote node - data, st = queryLedger(fcn='queryTraintuple', args=[f'{pk}']) - - if st == status.HTTP_404_NOT_FOUND: - raise Http404('Not found') - - if st != status.HTTP_200_OK: - raise JsonException(data) - - if 'permissions' not in data or data['permissions'] == 'all': - return data - else: - raise Exception('Not Allowed') - def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] @@ -133,7 +119,7 @@ def retrieve(self, request, *args, **kwargs): else: # get instance from remote node try: - data = self.getObjectFromLedger(pk) + data = getObjectFromLedger(pk, self.ledger_query_call) except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 2c0a4a879..8a1518f21 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -6,13 +6,7 @@ from rest_framework import status from rest_framework.response import Response -from substrapp.utils import queryLedger - - -class JsonException(Exception): - def __init__(self, msg): - self.msg = msg - super(JsonException, self).__init__() +from substrapp.ledger_utils import getObjectFromLedger def get_filters(query_params): @@ -54,22 +48,6 @@ def get_filters(query_params): return filters -def getObjectFromLedger(pk, query): - # get instance from remote node - data, st = queryLedger(fcn=query, args=[f'{pk}']) - - if st == status.HTTP_404_NOT_FOUND: - raise Http404('Not found') - - if st != status.HTTP_200_OK: - raise JsonException(data) - - if 'permissions' not in data or data['permissions'] == 'all': - return data - else: - raise Exception('Not Allowed') - - class ComputeHashMixin(object): def compute_hash(self, file, key=None): From 6601f1bffb4d83605968817847bb6f0b03e42139 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 29 May 2019 16:09:57 +0200 Subject: [PATCH 049/457] refactor tasks.py --- substrabac/substrapp/tasks/tasks.py | 225 ++++++++++------------ substrabac/substrapp/tests/tests_tasks.py | 8 +- 2 files changed, 100 insertions(+), 133 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index c3c2e2301..81f65c9a2 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -6,6 +6,7 @@ from os import path from checksumdir import dirhash +from django.core.exceptions import ObjectDoesNotExist from django.conf import settings from rest_framework import status from rest_framework.reverse import reverse @@ -26,143 +27,124 @@ def get_objective(subtuple): from substrapp.models import Objective - # check if objective exists and its metrics is not null objectiveHash = subtuple['objective']['hash'] + objective = None try: - # get objective from local db objective = Objective.objects.get(pk=objectiveHash) - except Exception: - objective = None - finally: - if objective is None or not objective.metrics: - # get objective metrics - try: - content, computed_hash = get_remote_file(subtuple['objective']['metrics']) - except Exception as e: - raise e + except ObjectDoesNotExist: + pass - objective, created = Objective.objects.update_or_create(pkhash=objectiveHash, validated=True) + # get objective from ledger as it is not available in local db and store it in local db + if objective is None or not objective.metrics: + content, computed_hash = get_remote_file(subtuple['objective']['metrics']) - try: - f = tempfile.TemporaryFile() - f.write(content) - objective.metrics.save('metrics.py', f) # update objective in local db for later use - except Exception as e: - logging.error('Failed to save objective metrics in local db for later use') - raise e + objective, _ = Objective.objects.update_or_create(pkhash=objectiveHash, validated=True) + + tmp_file = tempfile.TemporaryFile() + tmp_file.write(content) + objective.metrics.save('metrics.py', tmp_file) return objective def get_algo(subtuple): - algo_content, algo_computed_hash = get_remote_file(subtuple['algo']) - return algo_content, algo_computed_hash + algo_content, _ = get_remote_file(subtuple['algo']) + return algo_content -def get_model(subtuple): - model_content, model_computed_hash = None, None +def _get_model(model): + model_content, _ = get_remote_file(model, model['traintupleKey']) + return model_content - if subtuple.get('model', None) is not None: - model_content, model_computed_hash = get_remote_file(subtuple['model'], subtuple['model']['traintupleKey']) - return model_content, model_computed_hash +def get_model(subtuple): + if 'model' in subtuple: + return _get_model(subtuple['model']) + else: + return None def get_models(subtuple): - models_content, models_computed_hash = [], [] - - if subtuple.get('inModels', None) is not None: - for subtuple_model in subtuple['inModels']: - model_content, model_computed_hash = get_remote_file(subtuple_model, subtuple_model['traintupleKey']) - models_content.append(model_content) - models_computed_hash.append(model_computed_hash) + input_models = subtuple.get('inModels', []) + return [_get_model(item) for item in input_models] - return models_content, models_computed_hash +def _put_model(subtuple, subtuple_directory, model_content, model_hash, traintuple_key): + if not model_content: + raise Exception('Model content should not be empty') -def put_model(subtuple, subtuple_directory, model_content): - if model_content is not None: - from substrapp.models import Model + from substrapp.models import Model - model_dst_path = path.join(subtuple_directory, f'model/{subtuple["model"]["traintupleKey"]}') + # store a model in local subtuple directory from input model content + model_dst_path = path.join(subtuple_directory, f'model/{traintuple_key}') + model = None + try: + model = Model.objects.get(pk=model_hash) + except ObjectDoesNotExist: # write it to local disk + with open(model_dst_path, 'wb') as f: + f.write(model_content) + else: + # verify that local db model file is not corrupted + if get_hash(model.file.path, traintuple_key) != model_hash: + raise Exception('Model Hash in Subtuple is not the same as in local db') - try: - model = Model.objects.get(pk=subtuple['model']['hash']) - except Exception: # write it to local disk - with open(model_dst_path, 'wb') as f: - f.write(model_content) + if not os.path.exists(model_dst_path): + os.link(model.file.path, model_dst_path) else: - if get_hash(model.file.path, subtuple["model"]["traintupleKey"]) != subtuple['model']['hash']: - raise Exception('Model Hash in Subtuple is not the same as in local db') - - if not os.path.exists(model_dst_path): - os.link(model.file.path, model_dst_path) - else: - if get_hash(model_dst_path, subtuple["model"]["traintupleKey"]) != subtuple['model']['hash']: - raise Exception('Model Hash in Subtuple is not the same as in local medias') + # verify that local subtuple model file is not corrupted + if get_hash(model_dst_path, traintuple_key) != model_hash: + raise Exception('Model Hash in Subtuple is not the same as in local medias') -def put_models(subtuple, subtuple_directory, models_content): - if models_content: - from substrapp.models import Model +def put_model(subtuple, subtuple_directory, model_content): + return _put_model(subtuple, subtuple_directory, model_content, subtuple['model']['hash'], + subtuple['model']['traintupleKey']) - for model_content, subtuple_model in zip(models_content, subtuple['inModels']): - model_dst_path = path.join(subtuple_directory, f'model/{subtuple_model["traintupleKey"]}') - try: - model = Model.objects.get(pk=subtuple_model['hash']) - except Exception: # write it to local disk - with open(model_dst_path, 'wb') as f: - f.write(model_content) - else: - if get_hash(model.file.path, subtuple_model["traintupleKey"]) != subtuple_model['hash']: - raise Exception('Model Hash in Subtuple is not the same as in local db') +def put_models(subtuple, subtuple_directory, models_content): + if not models_content: + raise Exception('Models content should not be empty') - if not os.path.exists(model_dst_path): - os.link(model.file.path, model_dst_path) - else: - if get_hash(model_dst_path, subtuple_model["traintupleKey"]) != subtuple_model['hash']: - raise Exception('Model Hash in Subtuple is not the same as in local medias') + for model_content, model in zip(models_content, subtuple['inModels']): + _put_model(model, subtuple_directory, model_content, model['hash'], model['traintupleKey']) def put_opener(subtuple, subtuple_directory): from substrapp.models import DataManager + data_opener_hash = subtuple['dataset']['openerHash'] - try: - datamanager = DataManager.objects.get(pk=subtuple['dataset']['openerHash']) - except Exception as e: - raise e + datamanager = DataManager.objects.get(pk=data_opener_hash) - data_opener_hash = get_hash(datamanager.data_opener.path) - if data_opener_hash != subtuple['dataset']['openerHash']: + # verify that local db opener file is not corrupted + if get_hash(datamanager.data_opener.path) != data_opener_hash: raise Exception('DataOpener Hash in Subtuple is not the same as in local db') opener_dst_path = path.join(subtuple_directory, 'opener/opener.py') if not os.path.exists(opener_dst_path): os.link(datamanager.data_opener.path, opener_dst_path) + else: + # verify that local subtuple data opener file is not corrupted + if get_hash(opener_dst_path) != data_opener_hash: + raise Exception('DataOpener Hash in Subtuple is not the same as in local medias') def put_data_sample(subtuple, subtuple_directory): from substrapp.models import DataSample for data_sample_key in subtuple['dataset']['keys']: - try: - data_sample = DataSample.objects.get(pk=data_sample_key) - except Exception as e: - raise e - else: - data_sample_hash = dirhash(data_sample.path, 'sha256') - if data_sample_hash != data_sample_key: - raise Exception('Data Sample Hash in Subtuple is not the same as in local db') + data_sample = DataSample.objects.get(pk=data_sample_key) + data_sample_hash = dirhash(data_sample.path, 'sha256') + if data_sample_hash != data_sample_key: + raise Exception('Data Sample Hash in Subtuple is not the same as in local db') - # create a symlink on the folder containing data - try: - subtuple_data_directory = path.join(subtuple_directory, 'data', data_sample_key) - os.symlink(data_sample.path, subtuple_data_directory) - except Exception as e: - logging.error(e, exc_info=True) - raise Exception('Failed to create sym link for subtuple data sample') + # create a symlink on the folder containing data + subtuple_data_directory = path.join(subtuple_directory, 'data', data_sample_key) + try: + os.symlink(data_sample.path, subtuple_data_directory) + except OSError as e: + logging.exception(e) + raise Exception('Failed to create sym link for subtuple data sample') def put_metric(subtuple_directory, objective): @@ -172,11 +154,7 @@ def put_metric(subtuple_directory, objective): def put_algo(subtuple_directory, algo_content): - try: - uncompress_content(algo_content, subtuple_directory) - except Exception as e: - logging.error('Fail to uncompress algo file') - raise e + uncompress_content(algo_content, subtuple_directory) def build_subtuple_folders(subtuple): @@ -193,21 +171,20 @@ def remove_subtuple_materials(subtuple_directory): try: shutil.rmtree(subtuple_directory) except Exception as e: - logging.error(e) + logging.exception(e) -def fail(key, err_msg, tuple_type): - # Log Fail TrainTest +def log_fail_subtuple(key, err_msg, tuple_type): err_msg = str(err_msg).replace('"', "'").replace('\\', "").replace('\\n', "")[:200] fail_type = 'logFailTrain' if tuple_type == 'traintuple' else 'logFailTest' data, st = invokeLedger(fcn=fail_type, args=[f'{key}', f'{err_msg}'], sync=True) - if st is not status.HTTP_201_CREATED: + if st != status.HTTP_201_CREATED: logging.error(data, exc_info=True) - - logging.info('Successfully passed the subtuple to failed') + else: + logging.info('Successfully passed the subtuple to failed') return data @@ -258,7 +235,7 @@ def prepareTuple(subtuple, tuple_type, model_type): except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - return fail(subtuple['key'], error_code, tuple_type) + return log_fail_subtuple(subtuple['key'], error_code, tuple_type) def prepareTask(tuple_type, model_type): @@ -305,7 +282,7 @@ def computeTask(self, tuple_type, subtuple, model_type, fltask): except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - fail(subtuple['key'], error_code, tuple_type) + log_fail_subtuple(subtuple['key'], error_code, tuple_type) return result logging.info(f'Prepare Task success {tuple_type}') @@ -315,7 +292,7 @@ def computeTask(self, tuple_type, subtuple, model_type, fltask): except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - fail(subtuple['key'], error_code, tuple_type) + log_fail_subtuple(subtuple['key'], error_code, tuple_type) return result else: # Invoke ledger to log success @@ -343,31 +320,23 @@ def computeTask(self, tuple_type, subtuple, model_type, fltask): def prepareMaterials(subtuple, model_type): # get subtuple components - try: - objective = get_objective(subtuple) - algo_content, algo_computed_hash = get_algo(subtuple) - if model_type == 'model': - model_content, model_computed_hash = get_model(subtuple) # can return None, None - if model_type == 'inModels': - models_content, models_computed_hash = get_models(subtuple) # can return [], [] - - except Exception as e: - raise e + objective = get_objective(subtuple) + algo_content = get_algo(subtuple) + if model_type == 'model': + model_content = get_model(subtuple) + elif model_type == 'inModels': + models_content = get_models(subtuple) # create subtuple - try: - subtuple_directory = build_subtuple_folders(subtuple) # do not put anything in pred folder - put_opener(subtuple, subtuple_directory) - put_data_sample(subtuple, subtuple_directory) - put_metric(subtuple_directory, objective) - put_algo(subtuple_directory, algo_content) - if model_type == 'model': # testtuple - put_model(subtuple, subtuple_directory, model_content) - if model_type == 'inModels': # traintuple - put_models(subtuple, subtuple_directory, models_content) - - except Exception as e: - raise e + subtuple_directory = build_subtuple_folders(subtuple) # do not put anything in pred folder + put_opener(subtuple, subtuple_directory) + put_data_sample(subtuple, subtuple_directory) + put_metric(subtuple_directory, objective) + put_algo(subtuple_directory, algo_content) + if model_type == 'model': # testtuple + put_model(subtuple, subtuple_directory, model_content) + elif model_type == 'inModels': # traintuple + put_models(subtuple, subtuple_directory, models_content) def doTask(subtuple, tuple_type): @@ -473,7 +442,7 @@ def doTask(subtuple, tuple_type): except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - return fail(subtuple['key'], error_code, tuple_type) + return log_fail_subtuple(subtuple['key'], error_code, tuple_type) with open(end_model_path, 'rb') as f: instance.file.save('model', f) diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index e813e79c7..c9f2e34dc 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -333,10 +333,9 @@ def test_get_model(self): with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: mget_remote_file.return_value = model_content, model_hash - model_content, model_hash = get_model(subtuple) + model_content = get_model(subtuple) self.assertIsNotNone(model_content) - self.assertIsNotNone(model_hash) def test_get_models(self): model_content = self.model.read().encode() @@ -356,10 +355,9 @@ def test_get_models(self): with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: mget_remote_file.side_effect = [[models_content[0], models_hash[0]], [models_content[1], models_hash[1]]] - models_content_res, models_hash_res = get_models(subtuple) + models_content_res = get_models(subtuple) self.assertEqual(models_content_res, models_content) - self.assertIsNotNone(models_hash_res, models_hash) def test_get_algo(self): algo_content = self.algo.read() @@ -367,7 +365,7 @@ def test_get_algo(self): with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: mget_remote_file.return_value = algo_content, algo_hash - self.assertEqual((algo_content, algo_hash), get_algo({'algo': ''})) + self.assertEqual(algo_content, get_algo({'algo': ''})) def test_get_objective(self): metrics_content = self.script.read() From 5414a9c2de134b9d11c7f4966f12c41ecee7ba3f Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 29 May 2019 16:59:11 +0200 Subject: [PATCH 050/457] Fix tasks. --- substrabac/substrapp/tasks/tasks.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 81f65c9a2..93d56bca5 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -59,15 +59,19 @@ def _get_model(model): def get_model(subtuple): - if 'model' in subtuple: - return _get_model(subtuple['model']) + model = subtuple.get('model') + if model: + return _get_model(model) else: return None def get_models(subtuple): - input_models = subtuple.get('inModels', []) - return [_get_model(item) for item in input_models] + input_models = subtuple.get('inModels') + if input_models: + return [_get_model(item) for item in input_models] + else: + return [] def _put_model(subtuple, subtuple_directory, model_content, model_hash, traintuple_key): @@ -335,7 +339,7 @@ def prepareMaterials(subtuple, model_type): put_algo(subtuple_directory, algo_content) if model_type == 'model': # testtuple put_model(subtuple, subtuple_directory, model_content) - elif model_type == 'inModels': # traintuple + elif model_type == 'inModels' and models_content: # traintuple put_models(subtuple, subtuple_directory, models_content) From d347a424fe06b31738352586c046fc46d8aa355a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 29 May 2019 17:34:08 +0200 Subject: [PATCH 051/457] Refacto exception handling. --- .../substrapp/tasks/exception_handler.py | 82 +++++++++++++++++++ substrabac/substrapp/tasks/exceptions.json | 6 +- .../tasks/generate_exceptions_map.py | 82 ------------------- substrabac/substrapp/tests/tests_exception.py | 18 +--- 4 files changed, 88 insertions(+), 100 deletions(-) delete mode 100644 substrabac/substrapp/tasks/generate_exceptions_map.py diff --git a/substrabac/substrapp/tasks/exception_handler.py b/substrabac/substrapp/tasks/exception_handler.py index 888a572a6..2082ec263 100644 --- a/substrabac/substrapp/tasks/exception_handler.py +++ b/substrabac/substrapp/tasks/exception_handler.py @@ -4,6 +4,8 @@ import traceback import json import re +import inspect + LANGUAGES = { 'ShellScript': '00', @@ -66,3 +68,83 @@ def compute_error_code(exception): exception_code, service_code = get_exception_code(exception.__class__) error_code = f'[{service_code}-{LANGUAGES["Python"]}-{exception_code}-{exception_uuid}]' return error_code + + +def exception_tree(cls, exceptions_classes): + exceptions_classes.add(cls.__name__) + for subcls in cls.__subclasses__(): + exception_tree(subcls, exceptions_classes) + + +def find_exception(module): + # Exception classes in module + exceptions = [ename for ename, eclass in inspect.getmembers(module, inspect.isclass) + if issubclass(eclass, BaseException)] + + # Exception classes in submodule + for submodule in inspect.getmembers(module, inspect.ismodule): + exceptions += [ename for ename, eclass in inspect.getmembers(module, inspect.isclass) + if issubclass(eclass, BaseException)] + + return set(exceptions) + + +def generate_exceptions_map(append=True): + + os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabac.settings.prod' + + import requests.exceptions + import celery.exceptions + import tarfile + import django.core.exceptions + import django.urls + import django.db + import django.http + import django.db.transaction + import rest_framework.exceptions + + # Modules to inspect + MODULES = [docker.errors, requests.exceptions, celery.exceptions, tarfile, + django.core.exceptions, django.urls, django.db, django.http, django.db.transaction, + rest_framework.exceptions] + + exceptions_classes = set() + + # Add exceptions from modules + for errors_module in MODULES: + exceptions_classes.update(find_exception(errors_module)) + + # Add exceptions from python + exception_tree(BaseException, exceptions_classes) + + exceptions_classes = sorted(exceptions_classes) + + if os.path.exists(EXCEPTION_PATH) and append: + # Append values to it + json_exceptions = json.load(open(EXCEPTION_PATH)) + + # get all new exceptions + exceptions_classes = [e for e in exceptions_classes if e not in json_exceptions.keys()] + + # get the last value + start_value = max(map(int, json_exceptions.values())) + + for code_exception, exception_name in enumerate(exceptions_classes, start=start_value + 1): + json_exceptions[exception_name] = f'{code_exception:04d}' + + return json_exceptions + + else: + # Generate the json exceptions + json_exceptions = dict() + for code_exception, exception_name in enumerate(exceptions_classes, start=1): + json_exceptions[exception_name] = f'{code_exception:04d}' + + return json_exceptions + + +if __name__ == '__main__': + os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabac.settings.common' + json_exceptions = generate_exceptions_map() + with open(EXCEPTION_PATH, 'w') as outfile: + json.dump(json_exceptions, outfile, indent=4) diff --git a/substrabac/substrapp/tasks/exceptions.json b/substrabac/substrapp/tasks/exceptions.json index b3e1ad106..aea02b75a 100644 --- a/substrabac/substrapp/tasks/exceptions.json +++ b/substrabac/substrapp/tasks/exceptions.json @@ -480,5 +480,7 @@ "error": "0480", "gaierror": "0481", "herror": "0482", - "timeout": "0483" -} + "timeout": "0483", + "MessageNacked": "0484", + "PkgResourcesDeprecationWarning": "0485" +} \ No newline at end of file diff --git a/substrabac/substrapp/tasks/generate_exceptions_map.py b/substrabac/substrapp/tasks/generate_exceptions_map.py deleted file mode 100644 index 3775d8cac..000000000 --- a/substrabac/substrapp/tasks/generate_exceptions_map.py +++ /dev/null @@ -1,82 +0,0 @@ -import os -import inspect -import json - - -# Modules to inspect -os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabac.settings.prod' - -import docker.errors -import requests.exceptions -import celery.exceptions -import tarfile -import django.core.exceptions -import django.urls -import django.db -import django.http -import django.db.transaction -import rest_framework.exceptions - -MODULES = [docker.errors, requests.exceptions, celery.exceptions, tarfile, - django.core.exceptions, django.urls, django.db, django.http, django.db.transaction, - rest_framework.exceptions] - -EXCEPTION_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'exceptions.json') - - -def exception_tree(cls, exceptions_classes): - exceptions_classes.add(cls.__name__) - for subcls in cls.__subclasses__(): - exception_tree(subcls, exceptions_classes) - - -def find_exception(module): - # Exception classes in module - exceptions = [ename for ename, eclass in inspect.getmembers(module, inspect.isclass) - if issubclass(eclass, BaseException)] - - # Exception classes in submodule - for submodule in inspect.getmembers(module, inspect.ismodule): - exceptions += [ename for ename, eclass in inspect.getmembers(module, inspect.isclass) - if issubclass(eclass, BaseException)] - - return set(exceptions) - - -if __name__ == '__main__': - - exceptions_classes = set() - - # Add exceptions from modules - for errors_module in MODULES: - exceptions_classes.update(find_exception(errors_module)) - - # Add exceptions from python - exception_tree(BaseException, exceptions_classes) - - exceptions_classes = sorted(exceptions_classes) - - if os.path.exists(EXCEPTION_PATH): - # Append values to it - json_exceptions = json.load(open(EXCEPTION_PATH)) - - # get all new exceptions - exceptions_classes = [e for e in exceptions_classes if e not in json_exceptions.keys()] - - # get the last value - start_value = max(map(int, json_exceptions.values())) - - for code_exception, exception_name in enumerate(exceptions_classes, start=start_value + 1): - json_exceptions[exception_name] = f'{code_exception:04d}' - - with open(EXCEPTION_PATH, 'w') as outfile: - json.dump(json_exceptions, outfile, indent=4) - - else: - # Generate the json exceptions - json_exceptions = dict() - for code_exception, exception_name in enumerate(exceptions_classes, start=1): - json_exceptions[exception_name] = f'{code_exception:04d}' - - with open(EXCEPTION_PATH, 'w') as outfile: - json.dump(json_exceptions, outfile, indent=4) diff --git a/substrabac/substrapp/tests/tests_exception.py b/substrabac/substrapp/tests/tests_exception.py index 3d40a9ea5..e071295a4 100644 --- a/substrabac/substrapp/tests/tests_exception.py +++ b/substrabac/substrapp/tests/tests_exception.py @@ -2,8 +2,7 @@ import json import docker from django.test import TestCase -from substrapp.tasks.generate_exceptions_map import exception_tree, find_exception, MODULES -from substrapp.tasks.exception_handler import compute_error_code, get_exception_code +from substrapp.tasks.exception_handler import compute_error_code, get_exception_code, generate_exceptions_map class ExceptionTests(TestCase): @@ -16,21 +15,8 @@ def tearDown(self): def test_exception_map(self): - # Build the exception map from local configuration - exceptions_classes = set() - - # Get exceptions of modules - for errors_module in MODULES: - exceptions_classes.update(find_exception(errors_module)) - - # Get exceptions from python - exception_tree(BaseException, exceptions_classes) - # Build the exception map - exception_map = dict() - for code_exception, exception_name in enumerate(exceptions_classes, start=1): - exception_map[exception_name] = f'{code_exception:04d}' - + exception_map = generate_exceptions_map(append=False) # Exception map reference EXCEPTION_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../tasks/exceptions.json') reference_exception_map = json.load(open(EXCEPTION_PATH)) From 84c28324831d661957d1dabd5e254389da6137ad Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 3 Jun 2019 11:13:33 +0200 Subject: [PATCH 052/457] Cleanup pkhash in tests. --- .../tests/tests_bulkcreatedatasample.py | 6 +- substrabac/substrapp/tests/tests_query.py | 55 +++++++++---------- substrabac/substrapp/tests/tests_views.py | 19 ++++--- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py b/substrabac/substrapp/tests/tests_bulkcreatedatasample.py index 4772774fb..27a276a39 100644 --- a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py +++ b/substrabac/substrapp/tests/tests_bulkcreatedatasample.py @@ -71,6 +71,7 @@ def test_bulkcreatedatasample(self): 'data_manager_keys': data_manager_keys, 'test_only': False} + # dir hash pkhash1 = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' pkhash2 = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' @@ -127,7 +128,7 @@ def test_bulkcreatedatasample_path(self): 'data_manager_keys': data_manager_keys, 'test_only': False} - pkhash1 = 'e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c' + pkhash1 = get_hash(data_path1) with patch.object(DataManager.objects, 'filter') as mdatamanager, \ patch.object(LedgerDataSampleSerializer, 'create') as mcreate: @@ -183,7 +184,7 @@ def test_bulkcreatedatasample_original_path(self): 'data_manager_keys': data_manager_keys, 'test_only': False} - pkhash1 = 'e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c' + pkhash1 = get_hash(data_path1) with patch.object(DataManager.objects, 'filter') as mdatamanager, \ patch.object(LedgerDataSampleSerializer, 'create') as mcreate: @@ -240,6 +241,7 @@ def test_bulkcreatedatasample_path_and_files(self): 'data_manager_keys': data_manager_keys, 'test_only': False} + # dir hash pkhash1 = 'e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c' pkhash2 = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index 55f033fe3..b757654f9 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -45,6 +45,10 @@ def setUp(self): self.data_description, self.data_description_filename, self.data_data_opener, \ self.data_opener_filename = get_sample_datamanager() + self.test_data_sample_keys = [ + '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379', + '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389'] + def tearDown(self): try: shutil.rmtree(MEDIA_ROOT) @@ -65,9 +69,7 @@ def get_default_objective_data(self): data = { 'name': 'tough objective', 'test_data_manager_key': get_hash(self.data_data_opener), - 'test_data_sample_keys': [ - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379', - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389'], + 'test_data_sample_keys': self.test_data_sample_keys, 'description': desc, 'metrics': metrics, 'permissions': 'all', @@ -140,9 +142,7 @@ def test_add_objective_no_sync_ok(self): data = { 'name': 'tough objective', 'test_data_manager_key': get_hash(self.data_data_opener), - 'test_data_sample_keys': [ - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379', - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389'], + 'test_data_sample_keys': self.test_data_sample_keys, 'description': self.objective_description, 'metrics': self.objective_metrics, 'permissions': 'all', @@ -187,9 +187,7 @@ def test_add_objective_no_version(self): data = { 'name': 'tough objective', - 'test_data_sample_keys': [ - 'data_5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379', - 'data_5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389'], + 'test_data_sample_keys': self.test_data_sample_keys, 'description': description, 'metrics': metrics, } @@ -212,9 +210,7 @@ def test_add_objective_wrong_version(self): data = { 'name': 'tough objective', - 'test_data_sample_keys': [ - 'data_5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379', - 'data_5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389'], + 'test_data_sample_keys': self.test_data_sample_keys, 'description': description, 'metrics': metrics, } @@ -1109,6 +1105,9 @@ def setUp(self): self.objective_description, self.objective_description_filename, \ self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + self.train_data_sample_keys = ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'] + self.fake_key = '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088' + def tearDown(self): try: shutil.rmtree(MEDIA_ROOT) @@ -1124,13 +1123,13 @@ def test_add_traintuple_ok(self): url = reverse('substrapp:traintuple-list') data = { - 'train_data_sample_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], - 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'data_manager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'objective_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', + 'train_data_sample_keys': self.train_data_sample_keys, + 'algo_key': self.fake_key, + 'data_manager_key': self.fake_key, + 'objective_key': self.fake_key, 'rank': -1, - 'FLtask_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'in_models_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422']} + 'FLtask_key': self.fake_key, + 'in_models_keys': [self.fake_key]} extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } @@ -1154,8 +1153,8 @@ def test_add_traintuple_ko(self): url = reverse('substrapp:traintuple-list') data = { - 'train_data_sample_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], - 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088' + 'train_data_sample_keys': self.train_data_sample_keys, + 'model_key': self.fake_key } extra = { @@ -1182,10 +1181,10 @@ def test_add_traintuple_no_version(self): url = reverse('substrapp:traintuple-list') data = { - 'train_data_sample_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], - 'datamanager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088'} + 'train_data_sample_keys': self.train_data_sample_keys, + 'datamanager_key': self.fake_key, + 'model_key': self.fake_key, + 'algo_key': self.fake_key} response = self.client.post(url, data, format='multipart') r = response.json() @@ -1201,10 +1200,10 @@ def test_add_traintuple_wrong_version(self): url = reverse('substrapp:traintuple-list') data = { - 'train_data_sample_keys': ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'], - 'datamanager_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'model_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088', - 'algo_key': '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088'} + 'train_data_sample_keys': self.train_data_sample_keys, + 'datamanager_key': self.fake_key, + 'model_key': self.fake_key, + 'algo_key': self.fake_key} extra = { 'HTTP_ACCEPT': 'application/json;version=-1.0', } diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py index 7c7137322..57c8bd649 100644 --- a/substrabac/substrapp/tests/tests_views.py +++ b/substrabac/substrapp/tests/tests_views.py @@ -84,6 +84,11 @@ def setUp(self): self.objective_description, self.objective_description_filename, \ self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + self.test_data_sample_keys = [ + "2d0f943aa81a9cb3fe84b162559ce6aff068ccb04e0cb284733b8f9d7e06517e", + "533ee6e7b9d8b247e7e853b24547f57e6ef351852bac0418f13a0666173448f1" + ] + self.extra = { 'HTTP_ACCEPT': 'application/json;version=0.0' } @@ -235,10 +240,7 @@ def test_objective_create(self): 'metrics_name': 'macro-average recall', 'metrics': open(metrics_path, 'rb'), 'permissions': 'all', - 'test_data_sample_keys': [ - "2d0f943aa81a9cb3fe84b162559ce6aff068ccb04e0cb284733b8f9d7e06517e", - "533ee6e7b9d8b247e7e853b24547f57e6ef351852bac0418f13a0666173448f1" - ], + 'test_data_sample_keys': self.test_data_sample_keys, 'test_data_manager_key': test_data_manager_key } @@ -273,10 +275,7 @@ def test_objective_create_dryrun(self): 'metrics_name': 'macro-average recall', 'metrics': open(metrics_path, 'rb'), 'permissions': 'all', - 'test_data_sample_keys': [ - "2d0f943aa81a9cb3fe84b162559ce6aff068ccb04e0cb284733b8f9d7e06517e", - "533ee6e7b9d8b247e7e853b24547f57e6ef351852bac0418f13a0666173448f1" - ], + 'test_data_sample_keys': self.test_data_sample_keys, 'test_data_manager_key': test_data_manager_key, 'dryrun': True } @@ -1042,6 +1041,7 @@ def test_data_create_bulk(self): data_path1 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') data_path2 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') + # dir hash pkhash1 = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' pkhash2 = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' @@ -1113,6 +1113,7 @@ def test_data_create(self): data_path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + # dir hash pkhash = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' data_manager_keys = [ @@ -1181,7 +1182,7 @@ def test_data_sample_compute_dryrun(self): opener_path = os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') - pkhash = '62fb3263208d62c7235a046ee1d80e25512fe782254b730a9e566276b8c0ef3a' + pkhash = get_hash(data_path) data = { 'filepath': os.path.join(MEDIA_ROOT, '0024700.zip'), From 02f4c99a7407d50276e6c77be9d95fe041acb715 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 3 Jun 2019 11:42:33 +0200 Subject: [PATCH 053/457] Update coveragerc. --- substrabac/.coveragerc | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/substrabac/.coveragerc b/substrabac/.coveragerc index a5b94c111..46ae5d5cf 100644 --- a/substrabac/.coveragerc +++ b/substrabac/.coveragerc @@ -4,8 +4,8 @@ source = ./substrapp/ omit = - ./substrapp/apps.py - ./substrapp/serializers/ledger/* + #./substrapp/serializers/ledger/* + ./substrapp/tests/generate_assets.py [report] # Regexes for lines to exclude from consideration @@ -17,20 +17,10 @@ exclude_lines = def __repr__ if self\.debug - # Don't complain if tests don't hit defensive assertion code: - # raise - # Don't complain if non-runnable code isn't run: if 0: if __name__ == .__main__.: - # Don't complain if exception code isn't run: - logging - # except: - # except Exception - # except FileNotFoundError - EXCEPTIONS_MAP = dict() - # Don't complain if no gpu during test if gpu_set if __gpu_list @@ -38,10 +28,5 @@ exclude_lines = if 'environment' in job_args # Ignore functions - # def queryLedger - # def invokeLedger - # def getObjectFromLedger def prepareTrainingTask def prepareTestingTask - # class CustomFileResponse - # class ManageFileMixin From b2abdd3b793d9bc321cb118f9c5d8abeb98a29d8 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 3 Jun 2019 11:42:54 +0200 Subject: [PATCH 054/457] Ignore errors on shutil.rmtree instead of handling exception during tests. --- .../tests/tests_bulkcreatedatasample.py | 5 +- .../tests/tests_createdatamanager.py | 5 +- .../substrapp/tests/tests_createobjective.py | 5 +- substrabac/substrapp/tests/tests_exception.py | 6 --- substrabac/substrapp/tests/tests_misc.py | 6 --- substrabac/substrapp/tests/tests_model.py | 5 +- substrabac/substrapp/tests/tests_query.py | 25 ++-------- substrabac/substrapp/tests/tests_tasks.py | 12 +---- substrabac/substrapp/tests/tests_views.py | 47 ++++--------------- 9 files changed, 18 insertions(+), 98 deletions(-) diff --git a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py b/substrabac/substrapp/tests/tests_bulkcreatedatasample.py index 27a276a39..d284f9880 100644 --- a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py +++ b/substrabac/substrapp/tests/tests_bulkcreatedatasample.py @@ -50,10 +50,7 @@ def setUp(self): self.data_sample_file, self.data_sample_file_filename = get_sample_zip_data_sample() def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_bulkcreatedatasample(self): diff --git a/substrabac/substrapp/tests/tests_createdatamanager.py b/substrabac/substrapp/tests/tests_createdatamanager.py index d6f4cc1bf..0a49e99f3 100644 --- a/substrabac/substrapp/tests/tests_createdatamanager.py +++ b/substrabac/substrapp/tests/tests_createdatamanager.py @@ -26,10 +26,7 @@ def setUp(self): os.makedirs(MEDIA_ROOT) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_createdatamanager(self): diff --git a/substrabac/substrapp/tests/tests_createobjective.py b/substrabac/substrapp/tests/tests_createobjective.py index be2b38a28..9f97d9789 100644 --- a/substrabac/substrapp/tests/tests_createobjective.py +++ b/substrabac/substrapp/tests/tests_createobjective.py @@ -26,10 +26,7 @@ def setUp(self): self.maxDiff = None def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_createobjective(self): diff --git a/substrabac/substrapp/tests/tests_exception.py b/substrabac/substrapp/tests/tests_exception.py index e071295a4..993e2ba26 100644 --- a/substrabac/substrapp/tests/tests_exception.py +++ b/substrabac/substrapp/tests/tests_exception.py @@ -7,12 +7,6 @@ class ExceptionTests(TestCase): - def setUp(self): - pass - - def tearDown(self): - pass - def test_exception_map(self): # Build the exception map diff --git a/substrabac/substrapp/tests/tests_misc.py b/substrabac/substrapp/tests/tests_misc.py index 95a52a529..37b974da7 100644 --- a/substrabac/substrapp/tests/tests_misc.py +++ b/substrabac/substrapp/tests/tests_misc.py @@ -19,12 +19,6 @@ def write(self, s): class MiscTests(TestCase): """Misc tests""" - def setUp(self): - pass - - def tearDown(self): - pass - def test_cpu_sets(self): cpu_count = 16 for concurrency in range(1, cpu_count + 1, 1): diff --git a/substrabac/substrapp/tests/tests_model.py b/substrabac/substrapp/tests/tests_model.py index 7efebc419..5dedfc6aa 100644 --- a/substrabac/substrapp/tests/tests_model.py +++ b/substrabac/substrapp/tests/tests_model.py @@ -19,10 +19,7 @@ class ModelTests(TestCase): """Model tests""" def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_create_objective(self): description, _, metrics, _ = get_sample_objective() diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index b757654f9..0a074813d 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -50,10 +50,7 @@ def setUp(self): '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389'] def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def add_default_data_manager(self): DataManager.objects.create(name='slide opener', @@ -280,10 +277,7 @@ def setUp(self): self.data_opener_filename = get_sample_datamanager() def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_add_datamanager_sync_ok(self): url = reverse('substrapp:data_manager-list') @@ -402,10 +396,7 @@ def setUp(self): self.data_opener_filename2 = get_sample_datamanager2() def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_add_data_sample_sync_ok(self): @@ -912,10 +903,7 @@ def setUp(self): self.data_opener_filename = get_sample_datamanager() def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_add_algo_sync_ok(self): @@ -1109,10 +1097,7 @@ def setUp(self): self.fake_key = '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088' def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_add_traintuple_ok(self): # Add associated objective diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index c9f2e34dc..ce9c4f523 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -46,10 +46,7 @@ def setUp(self): self.ResourcesManager = ResourcesManager() def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) def test_create_directory(self): directory = './test/' @@ -122,13 +119,6 @@ def test_put_algo_tar(self): mget_hash.return_value = subtuple_key put_algo(os.path.join(self.subtuple_path, f'subtuple/{subtuple["key"]}/'), algo_content) - def tree_printer(root): - for root, dirs, files in os.walk(root): - for d in dirs: - print(os.path.join(root, d)) - for f in files: - print(os.path.join(root, f)) - self.assertTrue(os.path.exists(os.path.join(self.subtuple_path, f'subtuple/{subtuple["key"]}/algo.py'))) self.assertTrue(os.path.exists(os.path.join(self.subtuple_path, f'subtuple/{subtuple["key"]}/Dockerfile'))) diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py index 57c8bd649..485ee055b 100644 --- a/substrabac/substrapp/tests/tests_views.py +++ b/substrabac/substrapp/tests/tests_views.py @@ -32,13 +32,6 @@ # APITestCase class ViewTests(APITestCase): - - def setUp(self): - pass - - def tearDown(self): - pass - def test_data_sample_path_view(self): self.assertEqual('tutu', path_leaf('/toto/tata/tutu')) self.assertEqual('toto', path_leaf('/toto/')) @@ -98,10 +91,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) self.logger.setLevel(self.previous_level) @@ -339,10 +329,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) self.logger.setLevel(self.previous_level) @@ -515,10 +502,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) self.logger.setLevel(self.previous_level) @@ -660,10 +644,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) self.logger.setLevel(self.previous_level) @@ -823,10 +804,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) self.logger.setLevel(self.previous_level) @@ -896,10 +874,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) self.logger.setLevel(self.previous_level) @@ -969,10 +944,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) self.logger.setLevel(self.previous_level) @@ -1026,10 +998,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - try: - shutil.rmtree(MEDIA_ROOT) - except FileNotFoundError: - pass + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) self.logger.setLevel(self.previous_level) From 33b95c594f897240871242ac3ac37700a5a877bd Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Mon, 3 Jun 2019 15:56:28 +0200 Subject: [PATCH 055/457] Refacto tuples views --- substrabac/substrapp/ledger_utils.py | 12 +++ substrabac/substrapp/views/testtuple.py | 82 +++++--------------- substrabac/substrapp/views/traintuple.py | 97 ++++++------------------ substrabac/substrapp/views/utils.py | 10 +++ 4 files changed, 68 insertions(+), 133 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index b9ae1f47f..ea34808e7 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -72,7 +72,13 @@ def queryLedger(fcn, args=None): st = status.HTTP_404_NOT_FOUND data = {'message': response} + # TODO: get 409 from the chaincode + if 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if len(pkhash) == 64: + st = status.HTTP_409_CONFLICT + data['pkhash'] = pkhash return data, st @@ -154,5 +160,11 @@ def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): except json.decoder.JSONDecodeError: st = status.HTTP_400_BAD_REQUEST data = {'message': response} + # TODO: get 409 from the chaincode + if 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if len(pkhash) == 64: + st = status.HTTP_409_CONFLICT + data['pkhash'] = pkhash return data, st diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 38acca786..19cf1edf6 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -6,6 +6,7 @@ from substrapp.serializers import LedgerTestTupleSerializer from substrapp.ledger_utils import queryLedger, getObjectFromLedger from substrapp.utils import JsonException +from substrapp.views.utils import validate_pk class TestTupleViewSet(mixins.CreateModelMixin, @@ -16,69 +17,35 @@ class TestTupleViewSet(mixins.CreateModelMixin, ledger_query_call = 'queryTesttuple' def get_queryset(self): - queryset = [] - return queryset + return [] def perform_create(self, serializer): return serializer.save() def create(self, request, *args, **kwargs): - traintuple_key = request.data.get('traintuple_key', request.POST.get('traintuple_key', None)) - data_manager_key = request.data.get('data_manager_key', request.POST.get('data_manager_key', '')) - tag = request.data.get('tag', request.POST.get('tag', '')) - - try: - test_data_sample_keys = request.data.getlist('test_data_sample_keys', []) - except Exception: - test_data_sample_keys = request.data.get('test_data_sample_keys', - request.POST.getlist('test_data_sample_keys', [])) - data = { - 'traintuple_key': traintuple_key, - 'data_manager_key': data_manager_key, - 'test_data_sample_keys': test_data_sample_keys, # list of test data keys - 'tag': tag + 'traintuple_key': request.data.get('traintuple_key'), + 'data_manager_key': request.data.get('data_manager_key', ''), + 'test_data_sample_keys': request.data.getlist('test_data_sample_keys'), + 'tag': request.data.get('tag', '') } # init ledger serializer serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) - # Get testtuple pkhash of the proposal with a queryLedger in case of 408 timeout + # Get testtuple pkhash to handle 408 timeout in invokeLedger args = serializer.get_args(serializer.validated_data) data, st = queryLedger(fcn='createTesttuple', args=args) - - if st == status.HTTP_200_OK: - pkhash = data.get('key', data.get('keys')) - else: - # If queryLedger fails, invoke will fail too so we handle the issue right now - if 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - - if len(pkhash) != 64: - raise Exception('bad pkhash') - else: - st = status.HTTP_409_CONFLICT - + if st == status.HTTP_409_CONFLICT: return Response({'message': data['message'], - 'pkhash': pkhash}, status=st) + 'pkhash': data['pkhash']}, status=st) + pkhash = data.get('key') # create on ledger data, st = serializer.create(serializer.validated_data) - if st == status.HTTP_408_REQUEST_TIMEOUT: - return Response({'message': data['message'], - 'pkhash': pkhash}, status=st) - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED): - if 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - - if len(pkhash) != 64: - raise Exception('bad pkhash') - else: - st = status.HTTP_409_CONFLICT - return Response({'message': data['message'], 'pkhash': pkhash}, status=st) @@ -86,32 +53,25 @@ def create(self, request, *args, **kwargs): return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): - # can modify result by interrogating `request.version` - data, st = queryLedger(fcn='queryTesttuples', args=[]) - data = data if data else [] - return Response(data, status=st) def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - if len(pk) != 64: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + try: + validate_pk(pk) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + # get instance from remote node try: - int(pk, 16) # test if pk is correct (hexadecimal) - except Exception: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + data = getObjectFromLedger(pk, self.ledger_query_call) + except JsonException as e: + return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) + except Http404: + return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) else: - # get instance from remote node - try: - data = getObjectFromLedger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) - else: - return Response(data, status=status.HTTP_200_OK) + return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 03be3ae16..31ac9f1fa 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -6,6 +6,7 @@ from substrapp.serializers import LedgerTrainTupleSerializer from substrapp.ledger_utils import queryLedger, getObjectFromLedger from substrapp.utils import JsonException +from substrapp.views.utils import validate_pk class TrainTupleViewSet(mixins.CreateModelMixin, @@ -16,82 +17,39 @@ class TrainTupleViewSet(mixins.CreateModelMixin, ledger_query_call = 'queryTraintuple' def get_queryset(self): - queryset = [] - return queryset + return [] def perform_create(self, serializer): return serializer.save() def create(self, request, *args, **kwargs): - algo_key = request.data.get('algo_key', request.POST.get('algo_key', None)) - data_manager_key = request.data.get('data_manager_key', request.POST.get('data_manager_key', None)) - objective_key = request.data.get('objective_key', request.POST.get('objective_key', None)) - rank = request.data.get('rank', request.POST.get('rank', None)) - FLtask_key = request.data.get('FLtask_key', request.POST.get('FLtask_key', '')) - tag = request.data.get('tag', request.POST.get('tag', '')) - - try: - in_models_keys = request.data.getlist('in_models_keys', []) - except Exception: - in_models_keys = request.data.get('in_models_keys', request.POST.getlist('in_models_keys', [])) - - try: - train_data_sample_keys = request.data.getlist('train_data_sample_keys', []) - except Exception: - train_data_sample_keys = request.data.get('train_data_sample_keys', - request.POST.getlist('train_data_sample_keys', [])) - data = { - 'algo_key': algo_key, - 'data_manager_key': data_manager_key, - 'objective_key': objective_key, - 'rank': rank, - 'FLtask_key': FLtask_key, - 'in_models_keys': in_models_keys, + 'algo_key': request.data.get('algo_key'), + 'data_manager_key': request.data.get('data_manager_key'), + 'objective_key': request.data.get('objective_key'), + 'rank': request.data.get('rank'), + 'FLtask_key': request.data.get('FLtask_key', ''), + 'in_models_keys': request.data.getlist('in_models_keys'), # list of train data keys (which are stored in the train worker node) - 'train_data_sample_keys': train_data_sample_keys, - 'tag': tag + 'train_data_sample_keys': request.data.getlist('train_data_sample_keys'), + 'tag': request.data.get('tag', '') } - # init ledger serializer serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) - # Get traintuple pkhash of the proposal with a queryLedger in case of 408 timeout + # Get traintuple pkhash to handle 408 timeout in invokeLedger args = serializer.get_args(serializer.validated_data) data, st = queryLedger(fcn='createTraintuple', args=args) - - if st == status.HTTP_200_OK: - pkhash = data.get('key', data.get('keys')) - else: - # If queryLedger fails, invoke will fail too so we handle the issue right now - if 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - - if len(pkhash) != 64: - raise Exception('bad pkhash') - else: - st = status.HTTP_409_CONFLICT - + if st == status.HTTP_409_CONFLICT: return Response({'message': data['message'], - 'pkhash': pkhash}, status=st) + 'pkhash': data['pkhash']}, status=st) + pkhash = data.get('key') # create on ledger data, st = serializer.create(serializer.validated_data) - if st == status.HTTP_408_REQUEST_TIMEOUT: - return Response({'message': data['message'], - 'pkhash': pkhash}, status=st) - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED): - if 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - - if len(pkhash) != 64: - raise Exception('bad pkhash') - else: - st = status.HTTP_409_CONFLICT - return Response({'message': data['message'], 'pkhash': pkhash}, status=st) @@ -100,29 +58,24 @@ def create(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): data, st = queryLedger(fcn='queryTraintuples', args=[]) - data = data if data else [] - return Response(data, status=st) def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - if len(pk) != 64: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + try: + validate_pk(pk) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + # get instance from remote node try: - int(pk, 16) # test if pk is correct (hexadecimal) - except Exception: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + data = getObjectFromLedger(pk, self.ledger_query_call) + except JsonException as e: + return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) + except Http404: + return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) else: - # get instance from remote node - try: - data = getObjectFromLedger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) - else: - return Response(data, status=status.HTTP_200_OK) + return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 8a1518f21..a7b883251 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -118,3 +118,13 @@ def find_unique_error(detail_dict): return unique_error return None + + +def validate_pk(pk): + if len(pk) != 64: + raise Exception(f'Wrong pk {pk}') + + try: + int(pk, 16) # test if pk is correct (hexadecimal) + except ValueError: + raise Exception(f'Wrong pk {pk}') From 69293f669fedb895a761bea3b8169125dbc8dc2b Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Mon, 3 Jun 2019 15:57:36 +0200 Subject: [PATCH 056/457] Flake8 datasample --- substrabac/substrapp/views/datasample.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 6c8ec771d..760d7cabf 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -310,7 +310,7 @@ def validate_bulk_update(self, data): # validation try: data_manager_keys = data.getlist('data_manager_keys', []) - except: + except Exception: raise Exception('Please pass a valid data_manager_keys key param') else: data_manager_keys = ','.join(data_manager_keys) @@ -319,7 +319,7 @@ def validate_bulk_update(self, data): try: data_sample_keys = data.getlist('data_sample_keys', []) - except: + except Exception: raise Exception('Please pass a valid data_sample_keys key param') else: data_sample_keys = ','.join(data_sample_keys) From 1e899d35b5d1fe420cdc4174f406910cdab99280 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 3 Jun 2019 16:27:28 +0200 Subject: [PATCH 057/457] Fix bug in query/invoke Ledger. --- substrabac/substrapp/ledger_utils.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index ea34808e7..f563210d0 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -72,13 +72,15 @@ def queryLedger(fcn, args=None): st = status.HTTP_404_NOT_FOUND data = {'message': response} - # TODO: get 409 from the chaincode - if 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if len(pkhash) == 64: - st = status.HTTP_409_CONFLICT - data['pkhash'] = pkhash + # TODO: get 409 from the chaincode + if 'message' in data and 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + + if len(pkhash) == 64: + st = status.HTTP_409_CONFLICT + data['pkhash'] = pkhash + return data, st @@ -160,11 +162,12 @@ def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): except json.decoder.JSONDecodeError: st = status.HTTP_400_BAD_REQUEST data = {'message': response} - # TODO: get 409 from the chaincode - if 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if len(pkhash) == 64: - st = status.HTTP_409_CONFLICT - data['pkhash'] = pkhash + # TODO: get 409 from the chaincode + if 'message' in data and 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if len(pkhash) == 64: + st = status.HTTP_409_CONFLICT + data['pkhash'] = pkhash + return data, st From 451a43b94cc3d7810777ee0af6ae5f992cc4b551 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 4 Jun 2019 09:45:52 +0200 Subject: [PATCH 058/457] Refacto and clean filters. --- substrabac/substrapp/tests/tests_views.py | 70 ++++--- substrabac/substrapp/views/algo.py | 53 ++---- substrabac/substrapp/views/datamanager.py | 64 ++----- substrabac/substrapp/views/filters.py | 164 +++++++++++++++++ substrabac/substrapp/views/model.py | 211 +++++++--------------- substrabac/substrapp/views/objective.py | 94 +++------- substrabac/substrapp/views/utils.py | 40 ---- 7 files changed, 318 insertions(+), 378 deletions(-) create mode 100644 substrabac/substrapp/views/filters.py diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py index 485ee055b..6aa153d5a 100644 --- a/substrabac/substrapp/tests/tests_views.py +++ b/substrabac/substrapp/tests/tests_views.py @@ -144,9 +144,10 @@ def test_objective_list_filter_metrics(self): def test_objective_list_filter_datamanager(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(objective, status.HTTP_200_OK), - (datamanager, status.HTTP_200_OK)] + with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -156,9 +157,10 @@ def test_objective_list_filter_datamanager(self): def test_objective_list_filter_model(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(objective, status.HTTP_200_OK), - (traintuple, status.HTTP_200_OK)] + with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' @@ -371,9 +373,10 @@ def test_algo_list_filter_name(self): def test_algo_list_filter_datamanager(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(algo, status.HTTP_200_OK), - (datamanager, status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -383,9 +386,10 @@ def test_algo_list_filter_datamanager(self): def test_algo_list_filter_objective(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(algo, status.HTTP_200_OK), - (objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -395,9 +399,10 @@ def test_algo_list_filter_objective(self): def test_algo_list_filter_model(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(algo, status.HTTP_200_OK), - (traintuple, status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' @@ -545,9 +550,10 @@ def test_model_list_filter_hash(self): def test_model_list_filter_datamanager(self): url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(model, status.HTTP_200_OK), - (datamanager, status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] search_params = '?search=dataset%253Aname%253AISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -557,9 +563,10 @@ def test_model_list_filter_datamanager(self): def test_model_list_filter_objective(self): url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(model, status.HTTP_200_OK), - (objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -569,9 +576,10 @@ def test_model_list_filter_objective(self): def test_model_list_filter_algo(self): url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(model, status.HTTP_200_OK), - (algo, status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(algo, status.HTTP_200_OK)] search_params = '?search=algo%253Aname%253ALogistic%2520regression' response = self.client.get(url + search_params, **self.extra) @@ -686,9 +694,10 @@ def test_datamanager_list_filter_name(self): def test_datamanager_list_filter_objective(self): url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK), - (objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -698,9 +707,10 @@ def test_datamanager_list_filter_objective(self): def test_datamanager_list_filter_model(self): url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK), - (traintuple, status.HTTP_200_OK)] + with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK)] + mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' response = self.client.get(url + search_params, **self.extra) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 5b67ef882..6d9c21fb9 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -1,5 +1,5 @@ import tempfile - +import logging import requests from django.http import Http404 @@ -13,8 +13,8 @@ from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer from substrapp.utils import get_hash, JsonException from substrapp.ledger_utils import queryLedger, getObjectFromLedger -from substrapp.views.utils import (get_filters, ComputeHashMixin, ManageFileMixin, - find_primary_key_error) +from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error +from substrapp.views.filters import filter_list class AlgoViewSet(mixins.CreateModelMixin, @@ -164,54 +164,29 @@ def retrieve(self, request, *args, **kwargs): return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): - # can modify result by interrogating `request.version` - data, st = queryLedger(fcn='queryAlgos', args=[]) - modelData = None + data = data if data else [] - # init list to return - if data is None: - data = [] - data_samples_list = [data] + algos_list = [data] - if st == 200: + if st == status.HTTP_200_OK: # parse filters query_params = request.query_params.get('search', None) if query_params is not None: try: - filters = get_filters(query_params) - except Exception: + algos_list = filter_list( + object_type='algo', + data=data, + query_params=query_params) + except Exception as e: + logging.exception(e) return Response( {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) - else: - # filtering, reinit l to empty array - data_samples_list = [] - for idx, filter in enumerate(filters): - # init each list iteration to data - data_samples_list.append(data) - for k, subfilters in filter.items(): - if k == 'algo': # filter by own key - for key, val in subfilters.items(): - data_samples_list[idx] = [x for x in data_samples_list[idx] if x[key] in val] - elif k == 'model': # select objectives used by outModel hash - if not modelData: - # TODO find a way to put this call in cache - modelData, st = queryLedger(fcn='queryTraintuples', args=[]) - if st != status.HTTP_200_OK: - return Response(modelData, status=st) - if modelData is None: - modelData = [] - - for key, val in subfilters.items(): - filteredData = [x for x in modelData - if x['outModel'] is not None and x['outModel'][key] in val] - algoKeys = [x['algo']['hash'] for x in filteredData] - data_samples_list[idx] = [x for x in data_samples_list[idx] if x['key'] in algoKeys] - - return Response(data_samples_list, status=st) + + return Response(algos_list, status=st) @action(detail=True) def file(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 10f55e50c..13627b5b9 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -1,6 +1,6 @@ import ast import tempfile - +import logging import requests from django.conf import settings from django.http import Http404 @@ -18,7 +18,8 @@ from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync from substrapp.utils import get_hash, JsonException from substrapp.ledger_utils import queryLedger, getObjectFromLedger -from substrapp.views.utils import get_filters, ManageFileMixin, ComputeHashMixin, find_primary_key_error +from substrapp.views.utils import ManageFileMixin, ComputeHashMixin, find_primary_key_error +from substrapp.views.filters import filter_list class DataManagerViewSet(mixins.CreateModelMixin, @@ -231,71 +232,28 @@ def retrieve(self, request, *args, **kwargs): return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): - # can modify result by interrogating `request.version` data, st = queryLedger(fcn='queryDataManagers', args=[]) - objectiveData = None - modelData = None + data = data if data else [] - # init list to return - if data is None: - data = [] data_managers_list = [data] - if st == 200: + if st == status.HTTP_200_OK: # parse filters query_params = request.query_params.get('search', None) if query_params is not None: try: - filters = get_filters(query_params) - except Exception: + data_managers_list = filter_list( + object_type='dataset', + data=data, + query_params=query_params) + except Exception as e: + logging.exception(e) return Response( {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) - else: - # filtering, reinit l to empty array - data_managers_list = [] - for idx, filter in enumerate(filters): - # init each list iteration to data - data_managers_list.append(data) - for k, subfilters in filter.items(): - if k == 'dataset': # filter by own key - for key, val in subfilters.items(): - data_managers_list[idx] = [x for x in data_managers_list[idx] if x[key] in val] - elif k == 'objective': # select objective used by these datamanagers - if not objectiveData: - # TODO find a way to put this call in cache - objectiveData, st = queryLedger(fcn='queryObjectives', args=[]) - if st != status.HTTP_200_OK: - return Response(objectiveData, status=st) - if objectiveData is None: - objectiveData = [] - - for key, val in subfilters.items(): - if key == 'metrics': # specific to nested metrics - filteredData = [x for x in objectiveData if x[key]['name'] in val] - else: - filteredData = [x for x in objectiveData if x[key] in val] - objectiveKeys = [x['key'] for x in filteredData] - data_managers_list[idx] = [x for x in data_managers_list[idx] - if x['objectiveKey'] in objectiveKeys] - elif k == 'model': # select objectives used by outModel hash - if not modelData: - # TODO find a way to put this call in cache - modelData, st = queryLedger(fcn='queryTraintuples', args=[]) - if st != status.HTTP_200_OK: - return Response(modelData, status=st) - if modelData is None: - modelData = [] - - for key, val in subfilters.items(): - filteredData = [x for x in modelData - if x['outModel'] is not None and x['outModel'][key] in val] - objectiveKeys = [x['objective']['hash'] for x in filteredData] - data_managers_list[idx] = [x for x in data_managers_list[idx] - if x['objectiveKey'] in objectiveKeys] return Response(data_managers_list, status=st) diff --git a/substrabac/substrapp/views/filters.py b/substrabac/substrapp/views/filters.py new file mode 100644 index 000000000..7bf517be2 --- /dev/null +++ b/substrabac/substrapp/views/filters.py @@ -0,0 +1,164 @@ +from urllib.parse import unquote + +from rest_framework import status +from rest_framework.response import Response + +from substrapp.ledger_utils import queryLedger + + +FILTER_QUERIES = { + 'dataset': 'queryDataManagers', + 'algo': 'queryAlgos', + 'objective': 'queryObjectives', + 'model': 'queryTraintuples', +} + +AUTHORIZED_FILTERS = { + 'dataset': ['dataset', 'model', 'objective'], + 'algo': ['model', 'algo'], + 'objective': ['model', 'dataset', 'objective'], + 'model': ['model', 'algo', 'dataset', 'objective'], +} + + +def get_filters(query_params): + filters = [] + groups = query_params.split('-OR-') + for idx, group in enumerate(groups): + + # init + filters.append({}) + + # get number of subfilters and decode them + subfilters = [unquote(x) for x in group.split(',')] + + for subfilter in subfilters: + el = subfilter.split(':') + + # get parent + parent = el[0] + subparent = el[1] + value = el[2] + + filter = { + subparent: [unquote(value)] + } + + if not len(filters[idx]): # create and add it + filters[idx] = { + parent: filter + } + else: # add it + if parent in filters[idx]: # add + if el[1] in filters[idx][parent]: # concat in subparent + filters[idx][parent][subparent].extend([value]) + else: # add new subparent + filters[idx][parent].update(filter) + else: # create + filters[idx].update({parent: filter}) + + return filters + + +def filter_list(object_type, data, query_params): + + filters = get_filters(query_params) + + object_list = [] + + for user_filter in filters: + + for filter_key, subfilters in user_filter.items(): + + if filter_key not in AUTHORIZED_FILTERS[object_type]: + raise Exception(f'Not authorized filter key {filter_key} for asset {object_type}') + + # Will be appended in object_list after been filtered + filtered_list = data + + if filter_key == object_type: + # Filter by own asset + if filter_key == 'model': + for attribute, val in subfilters.items(): + filtered_list = [x for x in filtered_list + if x['traintuple']['outModel'] is not None and + x['traintuple']['outModel']['hash'] in val] + elif filter_key == 'objective': + for attribute, val in subfilters.items(): + if attribute == 'metrics': # specific to nested metrics + filtered_list = [x for x in filtered_list if x[attribute]['name'] in val] + else: + filtered_list = [x for x in filtered_list if x[attribute] in val] + + else: + for attribute, val in subfilters.items(): + filtered_list = [x for x in filtered_list if x[attribute] in val] + else: + # Filter by other asset + + # Get other asset list + filtering_data, st = queryLedger(fcn=FILTER_QUERIES[filter_key], args=[]) + if st != status.HTTP_200_OK: + return Response(filtering_data, status=st) + filtering_data = filtering_data if filtering_data else [] + + if filter_key == 'algo': + for attribute, val in subfilters.items(): + filtering_data = [x for x in filtering_data if x[attribute] in val] + hashes = [x['key'] for x in filtering_data] + + if object_type == 'model': + filtered_list = [x for x in filtered_list + if x['traintuple']['algo']['hash'] in hashes] + + elif filter_key == 'model': + for attribute, val in subfilters.items(): + filtering_data = [x for x in filtering_data + if x['outModel'] is not None and x['outModel'][attribute] in val] + + if object_type == 'algo': + hashes = [x['algo']['hash'] for x in filtering_data] + filtered_list = [x for x in filtered_list if x['key'] in hashes] + + elif object_type == 'dataset': + hashes = [x['objective']['hash'] for x in filtering_data] + filtered_list = [x for x in filtered_list + if x['objectiveKey'] in hashes] + + elif object_type == 'objective': + hashes = [x['objective']['hash'] for x in filtering_data] + filtered_list = [x for x in filtered_list if x['key'] in hashes] + + elif filter_key == 'dataset': + for attribute, val in subfilters.items(): + filtering_data = [x for x in filtering_data if x[attribute] in val] + hashes = [x['key'] for x in filtering_data] + + if object_type == 'model': + filtered_list = [x for x in filtered_list + if x['traintuple']['dataset']['openerHash'] in hashes] + elif object_type == 'objective': + objectiveKeys = [x['objectiveKey'] for x in filtering_data] + filtered_list = [x for x in filtered_list + if x['key'] in objectiveKeys or + (x['testDataset'] and x['testDataset']['dataManagerKey'] in hashes)] + + elif filter_key == 'objective': + for attribute, val in subfilters.items(): + if attribute == 'metrics': # specific to nested metrics + filtering_data = [x for x in filtering_data if x[attribute]['name'] in val] + else: + filtering_data = [x for x in filtering_data if x[attribute] in val] + + hashes = [x['key'] for x in filtering_data] + + if object_type == 'model': + filtered_list = [x for x in filtered_list + if x['traintuple']['objective']['hash'] in hashes] + elif object_type == 'dataset': + filtered_list = [x for x in filtered_list + if x['objectiveKey'] in hashes] + + object_list.append(filtered_list) + + return object_list diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 1eee76e35..b89a04355 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -1,6 +1,6 @@ import os import tempfile - +import logging import requests from django.http import Http404 from rest_framework import status, mixins @@ -13,7 +13,8 @@ from substrapp.utils import JsonException from substrapp.ledger_utils import queryLedger, getObjectFromLedger -from substrapp.views.utils import get_filters, ComputeHashMixin, CustomFileResponse +from substrapp.views.utils import ComputeHashMixin, CustomFileResponse, validate_pk +from substrapp.views.filters import filter_list class ModelViewSet(mixins.RetrieveModelMixin, @@ -30,193 +31,111 @@ def create_or_update_model(self, traintuple, pk): if traintuple['outModel'] is None: raise Exception(f'This traintuple related to this model key {pk} does not have a outModel') + # Get model from remote node + url = traintuple['outModel']['storageAddress'] try: - # get objective description from remote node - url = traintuple['outModel']['storageAddress'] - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) # TODO pass cert - except Exception: - raise Exception(f'Failed to fetch {url}') - else: - if r.status_code != 200: - raise Exception(f'end to end node report {r.text}') + r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) + except Exception: + raise Exception(f'Failed to fetch {url}') + else: + if r.status_code != 200: + raise Exception(f'end to end node report {r.text}') - try: - computed_hash = self.compute_hash(r.content, traintuple['key']) - except Exception: - raise Exception('Failed to fetch outModel file') - else: - if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) - - f = tempfile.TemporaryFile() - f.write(r.content) - - # save/update objective in local db for later use - instance, created = Model.objects.update_or_create(pkhash=pk, validated=True) - instance.file.save('model', f) - except Exception as e: - raise e + # Verify model received has a good pkhash + try: + computed_hash = self.compute_hash(r.content, traintuple['key']) + except Exception: + raise Exception('Failed to fetch outModel file') else: - return instance + if computed_hash != pk: + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' + raise Exception(msg) + + # Write model in local db for later use + tmp_model = tempfile.TemporaryFile() + tmp_model.write(r.content) + instance, created = Model.objects.update_or_create(pkhash=pk, validated=True) + instance.file.save('model', tmp_model) + + return instance def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - if len(pk) != 64: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + try: + validate_pk(pk) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + # get instance from remote node try: - int(pk, 16) # test if pk is correct (hexadecimal) - except Exception: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + data = getObjectFromLedger(pk, self.ledger_query_call) + except JsonException as e: + return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) + except Http404: + return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) else: - # get instance from remote node + # Try to get it from local db, else create it in local db try: - data = getObjectFromLedger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) + instance = self.get_object() except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) - else: - error = None - instance = None try: - # try to get it from local db to check if description exists - instance = self.get_object() - except Http404: + instance = self.create_or_update_model(data['traintuple'], + data['traintuple']['outModel']['hash']) + except Exception as e: + Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + else: + if not instance.file: try: instance = self.create_or_update_model(data['traintuple'], data['traintuple']['outModel']['hash']) except Exception as e: - error = e - else: - # check if instance has file - if not instance.file: - try: - instance = self.create_or_update_model(data['traintuple'], - data['traintuple']['outModel']['hash']) - except Exception as e: - error = e - finally: - if error is not None: - return Response({'message': str(error)}, status=status.HTTP_400_BAD_REQUEST) - - # do not give access to local files address - if instance is not None: - serializer = self.get_serializer( - instance, - fields=('owner', 'pkhash', 'creation_date', 'last_modified')) - data.update(serializer.data) - else: - data = {'message': 'Fail to get instance'} - - return Response(data, status=status.HTTP_200_OK) + Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) + data.update(serializer.data) + + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): - # can modify result by interrogating `request.version` data, st = queryLedger(fcn='queryModels', args=[]) - algoData = None - objectiveData = None - dataManagerData = None + data = data if data else [] - # init list to return - if data is None: - data = [] models_list = [data] - if st == 200: + if st == status.HTTP_200_OK: # parse filters query_params = request.query_params.get('search', None) if query_params is not None: try: - filters = get_filters(query_params) - except Exception: + models_list = filter_list( + object_type='model', + data=data, + query_params=query_params) + except Exception as e: + logging.exception(e) return Response( {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) - else: - # filtering, reinit l to empty array - models_list = [] - for idx, filter in enumerate(filters): - # init each list iteration to data - if data is None: - data = [] - models_list.append(data) - for k, subfilters in filter.items(): - if k == 'model': # filter by own key - for key, val in subfilters.items(): - models_list[idx] = [x for x in models_list[idx] - if x['traintuple']['outModel'] is not None and - x['traintuple']['outModel']['hash'] in val] - elif k == 'algo': # select model used by these algo - if not algoData: - # TODO find a way to put this call in cache - algoData, st = queryLedger(fcn='queryAlgos', args=[]) - if st != status.HTTP_200_OK: - return Response(algoData, status=st) - - if algoData is None: - algoData = [] - for key, val in subfilters.items(): - filteredData = [x for x in algoData if x[key] in val] - algoHashes = [x['key'] for x in filteredData] - models_list[idx] = [x for x in models_list[idx] - if x['traintuple']['algo']['hash'] in algoHashes] - elif k == 'dataset': # select model which trainData.openerHash is - if not dataManagerData: - # TODO find a way to put this call in cache - dataManagerData, st = queryLedger(fcn='queryDataManagers', args=[]) - if st != status.HTTP_200_OK: - return Response(dataManagerData, status=st) - - if dataManagerData is None: - dataManagerData = [] - for key, val in subfilters.items(): - filteredData = [x for x in dataManagerData if x[key] in val] - datamanagerHashes = [x['key'] for x in filteredData] - models_list[idx] = [ - x for x in models_list[idx] - if x['traintuple']['dataset']['openerHash'] in datamanagerHashes] - elif k == 'objective': # select objective used by these datamanagers - if not objectiveData: - # TODO find a way to put this call in cache - objectiveData, st = queryLedger(fcn='queryObjectives', args=[]) - if st != status.HTTP_200_OK: - return Response(objectiveData, status=st) - - if objectiveData is None: - objectiveData = [] - for key, val in subfilters.items(): - if key == 'metrics': # specific to nested metrics - filteredData = [x for x in objectiveData if x[key]['name'] in val] - else: - filteredData = [x for x in objectiveData if x[key] in val] - objectiveKeys = [x['key'] for x in filteredData] - models_list[idx] = [x for x in models_list[idx] - if x['traintuple']['objective']['hash'] in objectiveKeys] return Response(models_list, status=st) @action(detail=True) def file(self, request, *args, **kwargs): - object = self.get_object() - - # TODO query model permissions - - data = getattr(object, 'file') + model_object = self.get_object() + data = getattr(model_object, 'file') return CustomFileResponse(open(data.path, 'rb'), as_attachment=True, filename=os.path.basename(data.path)) @action(detail=True) def details(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - data, st = queryLedger(fcn='queryModelDetails', args=[f'{pk}']) - return Response(data, st) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 1efa7f676..5efbd8c1e 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -26,8 +26,9 @@ from substrapp.ledger_utils import queryLedger, getObjectFromLedger from substrapp.utils import get_hash, get_computed_hash, JsonException from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.views.utils import (get_filters, ComputeHashMixin, ManageFileMixin, - find_primary_key_error) +from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error + +from substrapp.views.filters import filter_list @app.task(bind=True, ignore_result=False) @@ -265,76 +266,29 @@ def retrieve(self, request, *args, **kwargs): return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): - # can modify result by interrogating `request.version` data, st = queryLedger(fcn='queryObjectives', args=[]) - - data = [] if data is None else data - objectives = [data] - - if st != status.HTTP_200_OK: - return Response(objectives, status=st) - - dataManagerData = None - modelData = None - - # parse filters - query_params = request.query_params.get('search', None) - if query_params is None: - return Response(objectives, status=st) - - try: - filters = get_filters(query_params) - except Exception: - return Response( - {'message': f'Malformed search filters {query_params}'}, - status=status.HTTP_400_BAD_REQUEST) - - # filtering - objectives = [] - for idx, filter in enumerate(filters): - # init each list iteration to data - objectives.append(data) - - for k, subfilters in filter.items(): - if k == 'objective': # filter by own key - for key, val in subfilters.items(): - if key == 'metrics': # specific to nested metrics - objectives[idx] = [x for x in objectives[idx] if x[key]['name'] in val] - else: - objectives[idx] = [x for x in objectives[idx] if x[key] in val] - - elif k == 'dataset': # select objective used by these datamanagers - if not dataManagerData: - # TODO find a way to put this call in cache - dataManagerData, st = queryLedger(fcn='queryDataManagers', args=[]) - if st != status.HTTP_200_OK: - return Response(dataManagerData, status=st) - if dataManagerData is None: - dataManagerData = [] - - for key, val in subfilters.items(): - filteredData = [x for x in dataManagerData if x[key] in val] - dataManagerKeys = [x['key'] for x in filteredData] - objectiveKeys = [x['objectiveKey'] for x in filteredData] - objectives[idx] = [x for x in objectives[idx] if x['key'] in objectiveKeys or - (x['testDataset'] and x['testDataset']['dataManagerKey'] in dataManagerKeys)] - - elif k == 'model': # select objectives used by outModel hash - if not modelData: - # TODO find a way to put this call in cache - modelData, st = queryLedger(fcn='queryTraintuples', args=[]) - if st != status.HTTP_200_OK: - return Response(modelData, status=st) - if modelData is None: - modelData = [] - - for key, val in subfilters.items(): - filteredData = [x for x in modelData if x['outModel'] is not None and x['outModel'][key] in val] - objectiveKeys = [x['objective']['hash'] for x in filteredData] - objectives[idx] = [x for x in objectives[idx] if x['key'] in objectiveKeys] - - return Response(objectives, status=st) + data = data if data else [] + + objectives_list = [data] + + if st == status.HTTP_200_OK: + # parse filters + query_params = request.query_params.get('search', None) + + if query_params is not None: + try: + objectives_list = filter_list( + object_type='objective', + data=data, + query_params=query_params) + except Exception as e: + logging.exception(e) + return Response( + {'message': f'Malformed search filters {query_params}'}, + status=status.HTTP_400_BAD_REQUEST) + + return Response(objectives_list, status=st) @action(detail=True) def description(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index a7b883251..b865f17f9 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -1,6 +1,5 @@ import hashlib import os -from urllib.parse import unquote from django.http import FileResponse, Http404 from rest_framework import status @@ -9,45 +8,6 @@ from substrapp.ledger_utils import getObjectFromLedger -def get_filters(query_params): - filters = [] - groups = query_params.split('-OR-') - for idx, group in enumerate(groups): - - # init - filters.append({}) - - # get number of subfilters and decode them - subfilters = [unquote(x) for x in group.split(',')] - - for subfilter in subfilters: - el = subfilter.split(':') - - # get parent - parent = el[0] - subparent = el[1] - value = el[2] - - filter = { - subparent: [unquote(value)] - } - - if not len(filters[idx]): # create and add it - filters[idx] = { - parent: filter - } - else: # add it - if parent in filters[idx]: # add - if el[1] in filters[idx][parent]: # concat in subparent - filters[idx][parent][subparent].extend([value]) - else: # add new subparent - filters[idx][parent].update(filter) - else: # create - filters[idx].update({parent: filter}) - - return filters - - class ComputeHashMixin(object): def compute_hash(self, file, key=None): From 2a19c31adc4049f7186dfd7f3c937b4f8e1f4923 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 4 Jun 2019 09:56:51 +0200 Subject: [PATCH 059/457] Rename filters.py into filters_utils.py and fix view tests. --- substrabac/substrapp/tests/tests_views.py | 28 +++++++++---------- substrabac/substrapp/views/algo.py | 2 +- substrabac/substrapp/views/datamanager.py | 2 +- .../views/{filters.py => filters_utils.py} | 1 - substrabac/substrapp/views/model.py | 2 +- substrabac/substrapp/views/objective.py | 3 +- 6 files changed, 18 insertions(+), 20 deletions(-) rename substrabac/substrapp/views/{filters.py => filters_utils.py} (99%) diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py index 6aa153d5a..ca888964b 100644 --- a/substrabac/substrapp/tests/tests_views.py +++ b/substrabac/substrapp/tests/tests_views.py @@ -145,7 +145,7 @@ def test_objective_list_filter_metrics(self): def test_objective_list_filter_datamanager(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] @@ -158,7 +158,7 @@ def test_objective_list_filter_datamanager(self): def test_objective_list_filter_model(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] @@ -371,10 +371,10 @@ def test_algo_list_filter_name(self): self.assertEqual(len(r[0]), 1) - def test_algo_list_filter_datamanager(self): + def test_algo_list_filter_datamanager_fail(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] @@ -382,12 +382,12 @@ def test_algo_list_filter_datamanager(self): response = self.client.get(url + search_params, **self.extra) r = response.json() - self.assertEqual(len(r[0]), len(algo)) + self.assertIn('Malformed search filters', r['message']) - def test_algo_list_filter_objective(self): + def test_algo_list_filter_objective_fail(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] @@ -395,12 +395,12 @@ def test_algo_list_filter_objective(self): response = self.client.get(url + search_params, **self.extra) r = response.json() - self.assertEqual(len(r[0]), 3) + self.assertIn('Malformed search filters', r['message']) def test_algo_list_filter_model(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] @@ -551,7 +551,7 @@ def test_model_list_filter_hash(self): def test_model_list_filter_datamanager(self): url = reverse('substrapp:model-list') with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] @@ -564,7 +564,7 @@ def test_model_list_filter_datamanager(self): def test_model_list_filter_objective(self): url = reverse('substrapp:model-list') with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] @@ -577,7 +577,7 @@ def test_model_list_filter_objective(self): def test_model_list_filter_algo(self): url = reverse('substrapp:model-list') with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(algo, status.HTTP_200_OK)] @@ -695,7 +695,7 @@ def test_datamanager_list_filter_name(self): def test_datamanager_list_filter_objective(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] @@ -708,7 +708,7 @@ def test_datamanager_list_filter_objective(self): def test_datamanager_list_filter_model(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters.queryLedger') as mqueryLedger2: + mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK)] mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] pkhash = model[0]['traintuple']['outModel']['hash'] diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 6d9c21fb9..ee411e412 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -14,7 +14,7 @@ from substrapp.utils import get_hash, JsonException from substrapp.ledger_utils import queryLedger, getObjectFromLedger from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error -from substrapp.views.filters import filter_list +from substrapp.views.filters_utils import filter_list class AlgoViewSet(mixins.CreateModelMixin, diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 13627b5b9..883710be4 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -19,7 +19,7 @@ from substrapp.utils import get_hash, JsonException from substrapp.ledger_utils import queryLedger, getObjectFromLedger from substrapp.views.utils import ManageFileMixin, ComputeHashMixin, find_primary_key_error -from substrapp.views.filters import filter_list +from substrapp.views.filters_utils import filter_list class DataManagerViewSet(mixins.CreateModelMixin, diff --git a/substrabac/substrapp/views/filters.py b/substrabac/substrapp/views/filters_utils.py similarity index 99% rename from substrabac/substrapp/views/filters.py rename to substrabac/substrapp/views/filters_utils.py index 7bf517be2..bed30ef4b 100644 --- a/substrabac/substrapp/views/filters.py +++ b/substrabac/substrapp/views/filters_utils.py @@ -34,7 +34,6 @@ def get_filters(query_params): for subfilter in subfilters: el = subfilter.split(':') - # get parent parent = el[0] subparent = el[1] diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index b89a04355..1082adc52 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -14,7 +14,7 @@ from substrapp.utils import JsonException from substrapp.ledger_utils import queryLedger, getObjectFromLedger from substrapp.views.utils import ComputeHashMixin, CustomFileResponse, validate_pk -from substrapp.views.filters import filter_list +from substrapp.views.filters_utils import filter_list class ModelViewSet(mixins.RetrieveModelMixin, diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 5efbd8c1e..e62e4f7ac 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -27,8 +27,7 @@ from substrapp.utils import get_hash, get_computed_hash, JsonException from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error - -from substrapp.views.filters import filter_list +from substrapp.views.filters_utils import filter_list @app.task(bind=True, ignore_result=False) From be2d5c9d398fb6c4ca3347446af14a8e1fc99607 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 4 Jun 2019 10:26:54 +0200 Subject: [PATCH 060/457] refactor algo views --- substrabac/substrapp/views/algo.py | 190 +++++++++++++---------------- 1 file changed, 87 insertions(+), 103 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index ee411e412..ecc539f13 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -13,7 +13,8 @@ from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer from substrapp.utils import get_hash, JsonException from substrapp.ledger_utils import queryLedger, getObjectFromLedger -from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error +from substrapp.views.utils import (ComputeHashMixin, ManageFileMixin, find_primary_key_error, + validate_pk) from substrapp.views.filters_utils import filter_list @@ -31,14 +32,13 @@ def perform_create(self, serializer): return serializer.save() def create(self, request, *args, **kwargs): - data = request.data - file = data.get('file') + file = request.data.get('file') pkhash = get_hash(file) serializer = self.get_serializer(data={ 'pkhash': pkhash, 'file': file, - 'description': data.get('description') + 'description': request.data.get('description') }) try: @@ -48,120 +48,104 @@ def create(self, request, *args, **kwargs): if find_primary_key_error(e): st = status.HTTP_409_CONFLICT return Response({'message': e.args, 'pkhash': pkhash}, status=st) - else: - # create on db - try: - instance = self.perform_create(serializer) - except Exception as exc: - return Response({'message': exc.args}, - status=status.HTTP_400_BAD_REQUEST) - else: - # init ledger serializer - ledger_serializer = LedgerAlgoSerializer(data={'name': data.get('name'), - 'permissions': data.get('permissions', 'all'), - 'instance': instance}, - context={'request': request}) - if not ledger_serializer.is_valid(): - # delete instance - instance.delete() - raise ValidationError(ledger_serializer.errors) - - # create on ledger - data, st = ledger_serializer.create(ledger_serializer.validated_data) - - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED, status.HTTP_408_REQUEST_TIMEOUT): - return Response(data, status=st) - - headers = self.get_success_headers(serializer.data) - d = dict(serializer.data) - d.update(data) - return Response(d, status=st, headers=headers) + # create on db + try: + instance = self.perform_create(serializer) + except Exception as e: + return Response({'message': e.args}, + status=status.HTTP_400_BAD_REQUEST) + + # init ledger serializer + ledger_serializer = LedgerAlgoSerializer(data={ + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions', 'all'), + 'instance': instance + }, context={'request': request}) + if not ledger_serializer.is_valid(): + # delete instance + instance.delete() + raise ValidationError(ledger_serializer.errors) + + # create on ledger + data, st = ledger_serializer.create(ledger_serializer.validated_data) + + if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED, status.HTTP_408_REQUEST_TIMEOUT): + return Response(data, status=st) + + headers = self.get_success_headers(serializer.data) + d = dict(serializer.data) + d.update(data) + return Response(d, status=st, headers=headers) def create_or_update_algo(self, algo, pk): + # get algo description from remote node + url = algo['description']['storageAddress'] try: - # get algo description from remote node - url = algo['description']['storageAddress'] - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) # TODO pass cert - except Exception: - raise Exception(f'Failed to fetch {url}') - else: - if r.status_code != 200: - raise Exception(f'end to end node report {r.text}') + r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) # TODO pass cert + except Exception as e: + raise Exception(f'Failed to fetch {url}') from e - try: - computed_hash = self.compute_hash(r.content) - except Exception: - raise Exception('Failed to fetch description file') - else: - if computed_hash != algo['description']['hash']: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) - - f = tempfile.TemporaryFile() - f.write(r.content) - - # save/update objective in local db for later use - instance, created = Algo.objects.update_or_create(pkhash=pk, validated=True) - instance.description.save('description.md', f) + if r.status_code != 200: + logging.error(f'Request failed: {r.text}') + raise Exception(f'Failed to fetch {url}: invalid status code {r.status_code}') + + try: + computed_hash = self.compute_hash(r.content) except Exception as e: - raise e - else: - return instance + raise Exception('Failed to fetch description file') from e + + if computed_hash != algo['description']['hash']: + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' + raise Exception(msg) + + f = tempfile.TemporaryFile() + f.write(r.content) + + # save/update objective in local db for later use + instance, created = Algo.objects.update_or_create(pkhash=pk, validated=True) + instance.description.save('description.md', f) + + return instance def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - if len(pk) != 64: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + try: + validate_pk(pk) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + # get instance from remote node try: - int(pk, 16) # test if pk is correct (hexadecimal) - except Exception: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) - else: - # get instance from remote node - error = None + data = getObjectFromLedger(pk, self.ledger_query_call) + except JsonException as e: + return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) + except Http404: + return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + + # try to get it from local db to check if description exists + try: + instance = self.get_object() + except Http404: instance = None + + # check if instance has description + if not instance or not instance.description: try: - data = getObjectFromLedger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) - else: - try: - # try to get it from local db to check if description exists - instance = self.get_object() - except Http404: - try: - instance = self.create_or_update_algo(data, pk) - except Exception as e: - error = e - else: - # check if instance has description - if not instance.description: - try: - instance = self.create_or_update_algo(data, pk) - except Exception as e: - error = e - finally: - if error is not None: - return Response(str(error), status=status.HTTP_400_BAD_REQUEST) - - # do not give access to local files address - if instance is not None: - serializer = self.get_serializer( - instance, - fields=('owner', 'pkhash', 'creation_date', 'last_modified')) - data.update(serializer.data) - else: - data = {'message': 'Fail to get instance'} - - return Response(data, status=status.HTTP_200_OK) + instance = self.create_or_update_algo(data, pk) + except Exception as e: + logging.exception(e) + return Response(str(e), status=status.HTTP_400_BAD_REQUEST) + + # do not give access to local files address + serializer = self.get_serializer( + instance, + fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + data.update(serializer.data) + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): data, st = queryLedger(fcn='queryAlgos', args=[]) From a7fe13a88cfb746017b4ec72ff6acf970cfa9546 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 4 Jun 2019 10:43:28 +0200 Subject: [PATCH 061/457] refactor datamanager views --- substrabac/substrapp/views/datamanager.py | 298 +++++++++------------- 1 file changed, 127 insertions(+), 171 deletions(-) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 883710be4..eea59c0f9 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -18,7 +18,8 @@ from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync from substrapp.utils import get_hash, JsonException from substrapp.ledger_utils import queryLedger, getObjectFromLedger -from substrapp.views.utils import ManageFileMixin, ComputeHashMixin, find_primary_key_error +from substrapp.views.utils import (ManageFileMixin, ComputeHashMixin, find_primary_key_error, + validate_pk) from substrapp.views.filters_utils import filter_list @@ -57,18 +58,15 @@ def dryrun(self, data_opener): }, status=status.HTTP_200_OK) def create(self, request, *args, **kwargs): - data = request.data - - dryrun = data.get('dryrun', False) - - data_opener = data.get('data_opener') + dryrun = request.data.get('dryrun', False) + data_opener = request.data.get('data_opener') pkhash = get_hash(data_opener) serializer = self.get_serializer(data={ 'pkhash': pkhash, 'data_opener': data_opener, - 'description': data.get('description'), - 'name': data.get('name'), + 'description': request.data.get('description'), + 'name': request.data.get('name'), }) try: @@ -78,40 +76,40 @@ def create(self, request, *args, **kwargs): if find_primary_key_error(e): st = status.HTTP_409_CONFLICT return Response({'message': e.args, 'pkhash': pkhash}, status=st) - else: - if dryrun: - return self.dryrun(data_opener) - # create on db - try: - instance = self.perform_create(serializer) - except Exception as e: - return Response({'message': e.args}, - status=status.HTTP_400_BAD_REQUEST) - else: - # init ledger serializer - ledger_serializer = LedgerDataManagerSerializer(data={'name': data.get('name'), - 'permissions': data.get('permissions'), - 'type': data.get('type'), - 'objective_keys': data.getlist('objective_keys'), - 'instance': instance}, - context={'request': request}) - - if not ledger_serializer.is_valid(): - # delete instance - instance.delete() - raise ValidationError(ledger_serializer.errors) - - # create on ledger - data, st = ledger_serializer.create(ledger_serializer.validated_data) - - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED, status.HTTP_408_REQUEST_TIMEOUT): - return Response(data, status=st) - - headers = self.get_success_headers(serializer.data) - d = dict(serializer.data) - d.update(data) - return Response(d, status=st, headers=headers) + if dryrun: + return self.dryrun(data_opener) + + # create on db + try: + instance = self.perform_create(serializer) + except Exception as e: + return Response({'message': e.args}, + status=status.HTTP_400_BAD_REQUEST) + + # init ledger serializer + ledger_serializer = LedgerDataManagerSerializer(data={ + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions'), + 'type': request.data.get('type'), + 'objective_keys': request.data.getlist('objective_keys'), + 'instance': instance + }, context={'request': request}) + + if not ledger_serializer.is_valid(): + # delete instance + instance.delete() + raise ValidationError(ledger_serializer.errors) + + # create on ledger + data, st = ledger_serializer.create(ledger_serializer.validated_data) + if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED, status.HTTP_408_REQUEST_TIMEOUT): + return Response(data, status=st) + + headers = self.get_success_headers(serializer.data) + d = dict(serializer.data) + d.update(data) + return Response(d, status=st, headers=headers) def create_or_update_datamanager(self, instance, datamanager, pk): @@ -121,61 +119,56 @@ def create_or_update_datamanager(self, instance, datamanager, pk): pkhash=pk, name=datamanager['name'], validated=True) if not instance.data_opener: + url = datamanager['opener']['storageAddress'] try: - url = datamanager['opener']['storageAddress'] - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) - except BaseException: - raise Exception(f'Failed to fetch {url}') - else: - if r.status_code != 200: - raise Exception(f'end to end node report {r.text}') - - try: - computed_hash = self.compute_hash(r.content) - except Exception: - raise Exception('Failed to fetch opener file') - else: - if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) - - f = tempfile.TemporaryFile() - f.write(r.content) - - # save/update data_opener in local db for later use - instance.data_opener.save('opener.py', f) + r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) + except Exception as e: + raise Exception(f'Failed to fetch {url}') from e + + if r.status_code != 200: + raise Exception(f'end to end node report {r.text}') + try: + computed_hash = self.compute_hash(r.content) except Exception as e: - raise e + raise Exception('Failed to fetch opener file') from e + + if computed_hash != pk: + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' + raise Exception(msg) + + f = tempfile.TemporaryFile() + f.write(r.content) + # save/update data_opener in local db for later use + instance.data_opener.save('opener.py', f) + + # do the same for description if not instance.description: - # do the same for description url = datamanager['description']['storageAddress'] try: r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) - except BaseException: - raise Exception(f'Failed to fetch {url}') - else: - if r.status_code != status.HTTP_200_OK: - raise Exception(f'end to end node report {r.text}') + except Exception as e: + raise Exception(f'Failed to fetch {url}') from e + if r.status_code != status.HTTP_200_OK: + raise Exception(f'end to end node report {r.text}') - try: - computed_hash = self.compute_hash(r.content) - except Exception: - raise Exception('Failed to fetch description file') - else: - if computed_hash != datamanager['description']['hash']: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) + try: + computed_hash = self.compute_hash(r.content) + except Exception as e: + raise Exception('Failed to fetch description file') from e + + if computed_hash != datamanager['description']['hash']: + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' + raise Exception(msg) - f = tempfile.TemporaryFile() - f.write(r.content) + f = tempfile.TemporaryFile() + f.write(r.content) - # save/update description in local db for later use - instance.description.save('description.md', f) + # save/update description in local db for later use + instance.description.save('description.md', f) return instance @@ -183,53 +176,39 @@ def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - if len(pk) != 64: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + try: + validate_pk(pk) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + # get instance from remote node try: - int(pk, 16) # test if pk is correct (hexadecimal) - except BaseException: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) - else: - # get instance from remote node + data = getObjectFromLedger(pk, 'queryDataset') + except JsonException as e: + return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) + except Http404: + return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + + # try to get it from local db to check if description exists + try: + instance = self.get_object() + except Http404: + instance = None + + # check if instance has description or data_opener + if not instance or not instance.description or not instance.data_opener: try: - data = getObjectFromLedger(pk, 'queryDataset') - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) - else: - error = None - instance = None - try: - # try to get it from local db to check if description exists - instance = self.get_object() - except Http404: - try: - instance = self.create_or_update_datamanager(instance, data, pk) - except Exception as e: - error = e - else: - # check if instance has description or data_opener - if not instance.description or not instance.data_opener: - try: - instance = self.create_or_update_datamanager(instance, data, pk) - except Exception as e: - error = e - finally: - if error is not None: - return Response({'message': str(error)}, status=status.HTTP_400_BAD_REQUEST) - - # do not give access to local files address - if instance is not None: - serializer = self.get_serializer( - instance, - fields=('owner', 'pkhash', 'creation_date', 'last_modified')) - data.update(serializer.data) - else: - data = {'message': 'Fail to get instance'} - - return Response(data, status=status.HTTP_200_OK) + instance = self.create_or_update_datamanager(instance, data, pk) + except Exception as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + # do not give access to local files address + serializer = self.get_serializer( + instance, + fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + data.update(serializer.data) + + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): @@ -263,52 +242,29 @@ def update_ledger(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - if len(pk) != 64: - return Response({'message': f'Wrong pk {pk}'}, - status.HTTP_400_BAD_REQUEST) - try: - int(pk, 16) # test if pk is correct (hexadecimal) - except BaseException: - return Response({'message': f'Wrong pk {pk}'}, - status.HTTP_400_BAD_REQUEST) - else: + validate_pk(pk) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) - data = request.data - objective_key = data.get('objective_key') + objective_key = request.data.get('objective_key') + args = [pk, objective_key] - if len(pk) != 64: - return Response({'message': f'Objective Key is wrong: {pk}'}, - status.HTTP_400_BAD_REQUEST) + if getattr(settings, 'LEDGER_SYNC_ENABLED'): + data, st = updateLedgerDataManager(args, sync=True) + # patch status for update + if st == status.HTTP_201_CREATED: + st = status.HTTP_200_OK + return Response(data, status=st) - try: - int(pk, 16) # test if pk is correct (hexadecimal) - except BaseException: - return Response({'message': f'Objective Key is wrong: {pk}'}, - status.HTTP_400_BAD_REQUEST) - else: - # args = '"%(dataManagerKey)s", "%(objectiveKey)s"' % { - # 'dataManagerKey': pk, - # 'objectiveKey': objective_key, - # } - - args = [pk, objective_key] - - if getattr(settings, 'LEDGER_SYNC_ENABLED'): - data, st = updateLedgerDataManager(args, sync=True) - - # patch status for update - if st == status.HTTP_201_CREATED: - st = status.HTTP_200_OK - return Response(data, status=st) - else: - # use a celery task, as we are in an http request transaction - updateLedgerDataManagerAsync.delay(args) - data = { - 'message': 'The substra network has been notified for updating this DataManager' - } - st = status.HTTP_202_ACCEPTED - return Response(data, status=st) + else: + # use a celery task, as we are in an http request transaction + updateLedgerDataManagerAsync.delay(args) + data = { + 'message': 'The substra network has been notified for updating this DataManager' + } + st = status.HTTP_202_ACCEPTED + return Response(data, status=st) @action(detail=True) def description(self, request, *args, **kwargs): From 35d06e48509a75b7e4a3180703840ecce39365ec Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 4 Jun 2019 10:52:58 +0200 Subject: [PATCH 062/457] Refacto and clean model view --- substrabac/substrapp/views/model.py | 53 +++++++++++++---------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 1082adc52..90fae5838 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -24,14 +24,13 @@ class ModelViewSet(mixins.RetrieveModelMixin, queryset = Model.objects.all() serializer_class = ModelSerializer ledger_query_call = 'queryModelDetails' - # permission_classes = (permissions.IsAuthenticated,) def create_or_update_model(self, traintuple, pk): if traintuple['outModel'] is None: raise Exception(f'This traintuple related to this model key {pk} does not have a outModel') - # Get model from remote node + # get model from remote node url = traintuple['outModel']['storageAddress'] try: r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) @@ -41,7 +40,7 @@ def create_or_update_model(self, traintuple, pk): if r.status_code != 200: raise Exception(f'end to end node report {r.text}') - # Verify model received has a good pkhash + # verify model received has a good pkhash try: computed_hash = self.compute_hash(r.content, traintuple['key']) except Exception: @@ -52,7 +51,7 @@ def create_or_update_model(self, traintuple, pk): 'Please investigate for default of synchronization, corruption, or hacked' raise Exception(msg) - # Write model in local db for later use + # write model in local db for later use tmp_model = tempfile.TemporaryFile() tmp_model.write(r.content) instance, created = Model.objects.update_or_create(pkhash=pk, validated=True) @@ -76,31 +75,27 @@ def retrieve(self, request, *args, **kwargs): return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) - else: - # Try to get it from local db, else create it in local db + + # Try to get it from local db, else create it in local db + try: + instance = self.get_object() + except Http404: + instance = None + + if not instance or not instance.file: try: - instance = self.get_object() - except Http404: - try: - instance = self.create_or_update_model(data['traintuple'], - data['traintuple']['outModel']['hash']) - except Exception as e: - Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) - else: - if not instance.file: - try: - instance = self.create_or_update_model(data['traintuple'], - data['traintuple']['outModel']['hash']) - except Exception as e: - Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) - - # For security reason, do not give access to local file address - # Restrain data to some fields - # TODO: do we need to send creation date and/or last modified date - serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) - data.update(serializer.data) - - return Response(data, status=status.HTTP_200_OK) + instance = self.create_or_update_model(data['traintuple'], + data['traintuple']['outModel']['hash']) + except Exception as e: + Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date ? + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) + data.update(serializer.data) + + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): @@ -110,9 +105,7 @@ def list(self, request, *args, **kwargs): models_list = [data] if st == status.HTTP_200_OK: - # parse filters query_params = request.query_params.get('search', None) - if query_params is not None: try: models_list = filter_list( From 04de52866630a88c57dc68eb171f5633bf5903a9 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 4 Jun 2019 10:53:14 +0200 Subject: [PATCH 063/457] Refacto and clean objective view. --- substrabac/substrapp/views/objective.py | 281 ++++++++++++------------ 1 file changed, 136 insertions(+), 145 deletions(-) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index e62e4f7ac..a31d969f5 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -26,76 +26,10 @@ from substrapp.ledger_utils import queryLedger, getObjectFromLedger from substrapp.utils import get_hash, get_computed_hash, JsonException from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error +from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk from substrapp.views.filters_utils import filter_list -@app.task(bind=True, ignore_result=False) -def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): - - dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' - - subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) - - metrics_path_dst = os.path.join(subtuple_directory, 'metrics/metrics.py') - if not os.path.exists(metrics_path_dst): - shutil.copy2(metrics_path, os.path.join(subtuple_directory, 'metrics/metrics.py')) - os.remove(metrics_path) - - if not test_data_manager_key: - raise Exception('Cannot do a objective dryrun without a data manager key.') - - datamanager = getObjectFromLedger(test_data_manager_key, 'queryDataManager') - opener_content, opener_computed_hash = get_computed_hash(datamanager['opener']['storageAddress']) - with open(os.path.join(subtuple_directory, 'opener/opener.py'), 'wb') as opener_file: - opener_file.write(opener_content) - - # Launch verification - client = docker.from_env() - pred_path = os.path.join(subtuple_directory, 'pred') - opener_file = os.path.join(subtuple_directory, 'opener/opener.py') - metrics_file = os.path.join(subtuple_directory, 'metrics/metrics.py') - metrics_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/dryrun_metrics') - - metrics_docker = 'metrics_dry_run' # tag must be lowercase for docker - metrics_docker_name = f'{metrics_docker}_{dryrun_uuid}' - volumes = {pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, - metrics_file: {'bind': '/sandbox/metrics/__init__.py', 'mode': 'ro'}, - opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}} - - client.images.build(path=metrics_path, - tag=metrics_docker, - rm=False) - - job_args = {'image': metrics_docker, - 'name': metrics_docker_name, - 'cpuset_cpus': '0-0', - 'mem_limit': '1G', - 'command': None, - 'volumes': volumes, - 'shm_size': '8G', - 'labels': ['dryrun'], - 'detach': False, - 'auto_remove': False, - 'remove': False} - - try: - client.containers.run(**job_args) - if not os.path.exists(os.path.join(pred_path, 'perf.json')): - raise Exception('Perf file not found') - - except ContainerError as e: - raise Exception(e.stderr) - - finally: - try: - container = client.containers.get(metrics_docker_name) - container.remove(force=True) - except BaseException as e: - logging.error(e, exc_info=True) - remove_subtuple_materials(subtuple_directory) - - class ObjectiveViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, @@ -111,119 +45,113 @@ def perform_create(self, serializer): return serializer.save() def create(self, request, *args, **kwargs): - data = request.data - - dryrun = data.get('dryrun', False) - - description = data.get('description') - test_data_manager_key = request.data.get('test_data_manager_key', request.POST.get('test_data_manager_key', '')) - - try: - test_data_sample_keys = request.data.getlist('test_data_sample_keys', []) - except Exception: - test_data_sample_keys = request.data.get('test_data_sample_keys', - request.POST.getlist('test_data_sample_keys', [])) - - metrics = data.get('metrics') - + metrics = request.data.get('metrics') + description = request.data.get('description') pkhash = get_hash(description) + test_data_manager_key = request.data.get('test_data_manager_key', '') + + # try to serialize in local db to check that it is valid serializer = self.get_serializer(data={'pkhash': pkhash, 'metrics': metrics, 'description': description}) - try: serializer.is_valid(raise_exception=True) except ValidationError as e: - st = status.HTTP_400_BAD_REQUEST if find_primary_key_error(e): st = status.HTTP_409_CONFLICT + else: + st = status.HTTP_400_BAD_REQUEST return Response({'message': e.args, 'pkhash': pkhash}, status=st) - if dryrun: + # perform dry run if requested + if request.data.get('dryrun', False): try: metrics_path = os.path.join(getattr(settings, 'DRYRUN_ROOT'), f'metrics_{pkhash}.py') with open(metrics_path, 'wb') as metrics_file: metrics_file.write(metrics.open().read()) - - task = compute_dryrun.apply_async((metrics_path, test_data_manager_key, pkhash), - queue=f"{settings.LEDGER['name']}.dryrunner") + task = compute_dryrun.apply_async( + (metrics_path, test_data_manager_key, pkhash), + queue=f"{settings.LEDGER['name']}.dryrunner" + ) except Exception as e: return Response({ 'message': f'Could not launch objective creation with dry-run on this instance: {str(e)}' }, status=status.HTTP_400_BAD_REQUEST) + else: + current_site = getattr(settings, "DEFAULT_DOMAIN") + task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' + msg = f'Your dry-run has been taken in account. You can follow the task execution on {task_route}' - current_site = getattr(settings, "DEFAULT_DOMAIN") - task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' - msg = f'Your dry-run has been taken in account. You can follow the task execution on {task_route}' + return Response({'id': task.id, 'message': msg}, status=status.HTTP_202_ACCEPTED) - return Response({'id': task.id, 'message': msg}, status=status.HTTP_202_ACCEPTED) - - # create on db + # create on local db try: instance = self.perform_create(serializer) - except IntegrityError as exc: + except IntegrityError as e: try: - pkhash = re.search(r'\(pkhash\)=\((\w+)\)', exc.args[0]).group(1) - except BaseException: + pkhash = re.search(r'\(pkhash\)=\((\w+)\)', e.args[0]).group(1) + except IndexError: pkhash = '' - finally: - return Response({'message': 'A objective with this description file already exists.', 'pkhash': pkhash}, - status=status.HTTP_409_CONFLICT) - except Exception as exc: - return Response({'message': exc.args}, + return Response({'message': 'A objective with this description file already exists.', 'pkhash': pkhash}, + status=status.HTTP_409_CONFLICT) + except Exception as e: + return Response({'message': e.args}, status=status.HTTP_400_BAD_REQUEST) - # init ledger serializer - ledger_serializer = LedgerObjectiveSerializer(data={'test_data_sample_keys': test_data_sample_keys, - 'test_data_manager_key': test_data_manager_key, - 'name': data.get('name'), - 'permissions': data.get('permissions'), - 'metrics_name': data.get('metrics_name'), - 'instance': instance}, - context={'request': request}) + # create on ledger db + ledger_serializer = LedgerObjectiveSerializer( + data={'test_data_sample_keys': request.data.getlist('test_data_sample_keys', []), + 'test_data_manager_key': test_data_manager_key, + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions'), + 'metrics_name': request.data.get('metrics_name'), + 'instance': instance}, + context={'request': request} + ) if not ledger_serializer.is_valid(): - # delete instance instance.delete() raise ValidationError(ledger_serializer.errors) - # create on ledger - data, st = ledger_serializer.create(ledger_serializer.validated_data) + ledger_data, st = ledger_serializer.create(ledger_serializer.validated_data) if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED, status.HTTP_408_REQUEST_TIMEOUT): - return Response(data, status=st) + return Response(ledger_data, status=st) + # return response with local db and ledger data information headers = self.get_success_headers(serializer.data) - d = dict(serializer.data) - d.update(data) - return Response(d, status=st, headers=headers) + data = dict(serializer.data) # local db data + data.update(ledger_data) # ledger data + return Response(data, status=st, headers=headers) def create_or_update_objective(self, objective, pk): - # get objective description from remote node + + # get description from remote node url = objective['description']['storageAddress'] try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) # TODO pass cert + r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout): raise Exception(f'Failed to fetch {url}') - if r.status_code != status.HTTP_200_OK: - raise Exception(f'end to end node report {r.text}') + else: + if r.status_code != status.HTTP_200_OK: + raise Exception(f'end to end node report {r.text}') + # verify description received has a good pkhash try: computed_hash = self.compute_hash(r.content) except Exception: raise Exception('Failed to fetch description file') - - if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) - - f = tempfile.TemporaryFile() - f.write(r.content) - - # save/update objective in local db for later use + else: + if computed_hash != pk: + msg = 'computed hash is not the same as the hosted file. ' \ + 'Please investigate for default of synchronization, corruption, or hacked' + raise Exception(msg) + + # write objective with description in local db for later use + tmp_description = tempfile.TemporaryFile() + tmp_description.write(r.content) instance, created = Objective.objects.update_or_create(pkhash=pk, validated=True) - instance.description.save('description.md', f) + instance.description.save('description.md', tmp_description) return instance @@ -231,13 +159,10 @@ def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - if len(pk) != 64: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) - try: - int(pk, 16) # test if pk is correct (hexadecimal) - except ValueError: - return Response({'message': f'Wrong pk {pk}'}, status.HTTP_400_BAD_REQUEST) + validate_pk(pk) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) # get instance from remote node try: @@ -246,6 +171,7 @@ def retrieve(self, request, *args, **kwargs): return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + # try to get it from local db to check if description exists try: instance = self.get_object() @@ -258,10 +184,12 @@ def retrieve(self, request, *args, **kwargs): except Exception as e: return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) - # do not give access to local files address - serializer = self.get_serializer( - instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date ? + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) data.update(serializer.data) + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): @@ -272,9 +200,7 @@ def list(self, request, *args, **kwargs): objectives_list = [data] if st == status.HTTP_200_OK: - # parse filters query_params = request.query_params.get('search', None) - if query_params is not None: try: objectives_list = filter_list( @@ -304,7 +230,72 @@ def data(self, request, *args, **kwargs): # TODO fetch list of data from ledger # query list of related algos and models from ledger - # return success and model - serializer = self.get_serializer(instance) return Response(serializer.data) + + +@app.task(bind=True, ignore_result=False) +def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): + + dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' + + subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) + + metrics_path_dst = os.path.join(subtuple_directory, 'metrics/metrics.py') + if not os.path.exists(metrics_path_dst): + shutil.copy2(metrics_path, os.path.join(subtuple_directory, 'metrics/metrics.py')) + os.remove(metrics_path) + + if not test_data_manager_key: + raise Exception('Cannot do a objective dryrun without a data manager key.') + + datamanager = getObjectFromLedger(test_data_manager_key, 'queryDataManager') + opener_content, opener_computed_hash = get_computed_hash(datamanager['opener']['storageAddress']) + with open(os.path.join(subtuple_directory, 'opener/opener.py'), 'wb') as file: + file.write(opener_content) + + # Launch verification + client = docker.from_env() + pred_path = os.path.join(subtuple_directory, 'pred') + opener_file = os.path.join(subtuple_directory, 'opener/opener.py') + metrics_file = os.path.join(subtuple_directory, 'metrics/metrics.py') + metrics_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/dryrun_metrics') + + metrics_docker = 'metrics_dry_run' + metrics_docker_name = f'{metrics_docker}_{dryrun_uuid}' + volumes = { + pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, + metrics_file: {'bind': '/sandbox/metrics/__init__.py', 'mode': 'ro'}, + opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}} + + client.images.build(path=metrics_path, + tag=metrics_docker, + rm=False) + + job_args = { + 'image': metrics_docker, + 'name': metrics_docker_name, + 'cpuset_cpus': '0-0', + 'mem_limit': '1G', + 'command': None, + 'volumes': volumes, + 'shm_size': '8G', + 'labels': ['dryrun'], + 'detach': False, + 'auto_remove': False, + 'remove': False} + + try: + client.containers.run(**job_args) + if not os.path.exists(os.path.join(pred_path, 'perf.json')): + raise Exception('Perf file not found') + except ContainerError as e: + raise Exception(e.stderr) + finally: + try: + container = client.containers.get(metrics_docker_name) + container.remove(force=True) + except BaseException as e: + logging.error(e, exc_info=True) + + remove_subtuple_materials(subtuple_directory) From 70119a7aacdaba71bb29bc77badde699290d85d1 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 4 Jun 2019 10:54:45 +0200 Subject: [PATCH 064/457] cosmetic fix :) --- substrabac/substrapp/views/algo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index ecc539f13..94ee7f8dd 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -86,7 +86,7 @@ def create_or_update_algo(self, algo, pk): except Exception as e: raise Exception(f'Failed to fetch {url}') from e - if r.status_code != 200: + if r.status_code != status.HTTP_200_OK: logging.error(f'Request failed: {r.text}') raise Exception(f'Failed to fetch {url}: invalid status code {r.status_code}') From fd19610132088500bdbe58e5a82e5a50c3342a93 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 4 Jun 2019 11:11:35 +0200 Subject: [PATCH 065/457] refactor datasample views --- substrabac/substrapp/views/datasample.py | 186 +++++++++++------------ substrabac/substrapp/views/utils.py | 15 ++ 2 files changed, 101 insertions(+), 100 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 760d7cabf..83ee2ecc9 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -24,111 +24,13 @@ from substrapp.serializers.ledger.datasample.tasks import updateLedgerDataSampleAsync from substrapp.utils import uncompress_path, get_dir_hash from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.views.utils import find_primary_key_error +from substrapp.views.utils import find_primary_key_error, LedgerException, ValidationException logger = logging.getLogger('django.request') -def path_leaf(path): - head, tail = ntpath.split(path) - return tail or ntpath.basename(head) - - -class LedgerException(Exception): - def __init__(self, data, st): - self.data = data - self.st = st - super(LedgerException).__init__() - - -class ValidationException(Exception): - def __init__(self, data, pkhash, st): - self.data = data - self.pkhash = pkhash - self.st = st - super(ValidationException).__init__() - - -@app.task(bind=True, ignore_result=False) -def compute_dryrun(self, data, data_manager_keys): - from shutil import copy - from substrapp.models import DataManager - - client = docker.from_env() - - # Name of the dry-run subtuple (not important) - pkhash = data[0]['pkhash'] - dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' - subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) - data_path = os.path.join(subtuple_directory, 'data') - volumes = {} - - try: - - for data_sample in data: - # uncompress only for file - if 'file' in data_sample: - try: - uncompress_path(data_sample['file'], os.path.join(data_path, data_sample['pkhash'])) - except Exception as e: - raise e - # for all data paths, we need to create symbolic links inside data_path - # and add real path to volume bind docker - elif 'path' in data_sample: - os.symlink(data_sample['path'], os.path.join(data_path, data_sample['pkhash'])) - volumes.update({data_sample['path']: {'bind': data_sample['path'], 'mode': 'ro'}}) - - for datamanager_key in data_manager_keys: - datamanager = DataManager.objects.get(pk=datamanager_key) - copy(datamanager.data_opener.path, os.path.join(subtuple_directory, 'opener/opener.py')) - - # Launch verification - opener_file = os.path.join(subtuple_directory, 'opener/opener.py') - data_sample_docker_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/dryrun_data_sample') - - data_docker = 'data_dry_run' # tag must be lowercase for docker - data_docker_name = f'{data_docker}_{dryrun_uuid}' - - volumes.update({data_path: {'bind': '/sandbox/data', 'mode': 'rw'}, - opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}}) - - client.images.build(path=data_sample_docker_path, - tag=data_docker, - rm=False) - - job_args = {'image': data_docker, - 'name': data_docker_name, - 'cpuset_cpus': '0-0', - 'mem_limit': '1G', - 'command': None, - 'volumes': volumes, - 'shm_size': '8G', - 'labels': ['dryrun'], - 'detach': False, - 'auto_remove': False, - 'remove': False} - - client.containers.run(**job_args) - - except ContainerError as e: - raise Exception(e.stderr) - finally: - try: - container = client.containers.get(data_docker_name) - container.remove() - except Exception: - logger.error('Could not remove containers') - remove_subtuple_materials(subtuple_directory) - for data_sample in data: - if 'file' in data_sample and os.path.exists(data_sample['file']): - os.remove(data_sample['file']) - - class DataSampleViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, - # mixins.UpdateModelMixin, - # mixins.DestroyModelMixin, - # mixins.ListModelMixin, GenericViewSet): queryset = DataSample.objects.all() serializer_class = DataSampleSerializer @@ -150,7 +52,7 @@ def check_datamanagers(data_manager_keys): @staticmethod def commit(serializer, ledger_data): - instances = serializer.save() # can raise + instances = serializer.save() # init ledger serializer ledger_data.update({'instances': instances}) ledger_serializer = LedgerDataSampleSerializer(data=ledger_data) @@ -360,3 +262,87 @@ def bulk_update(self, request): } st = status.HTTP_202_ACCEPTED return Response(data, status=st) + + +def path_leaf(path): + head, tail = ntpath.split(path) + return tail or ntpath.basename(head) + + +@app.task(bind=True, ignore_result=False) +def compute_dryrun(self, data_samples, data_manager_keys): + from shutil import copy + from substrapp.models import DataManager + + client = docker.from_env() + + # Name of the dry-run subtuple (not important) + pkhash = data_samples[0]['pkhash'] + dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' + subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) + data_path = os.path.join(subtuple_directory, 'data') + volumes = {} + + try: + for data_sample in data_samples: + # uncompress only for file + if 'file' in data_sample: + uncompress_path(data_sample['file'], os.path.join(data_path, data_sample['pkhash'])) + # for all data paths, we need to create symbolic links inside data_path + # and add real path to volume bind docker + elif 'path' in data_sample: + os.symlink(data_sample['path'], os.path.join(data_path, data_sample['pkhash'])) + volumes.update({ + data_sample['path']: {'bind': data_sample['path'], 'mode': 'ro'} + }) + + for datamanager_key in data_manager_keys: + datamanager = DataManager.objects.get(pk=datamanager_key) + copy(datamanager.data_opener.path, os.path.join(subtuple_directory, 'opener/opener.py')) + + opener_file = os.path.join(subtuple_directory, 'opener/opener.py') + data_sample_docker_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/dryrun_data_sample') + + data_docker = 'data_dry_run' + data_docker_name = f'{data_docker}_{dryrun_uuid}' + + volumes.update({ + data_path: {'bind': '/sandbox/data', 'mode': 'rw'}, + opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'} + }) + + client.images.build(path=data_sample_docker_path, + tag=data_docker, + rm=False) + + job_args = { + 'image': data_docker, + 'name': data_docker_name, + 'cpuset_cpus': '0-0', + 'mem_limit': '1G', + 'command': None, + 'volumes': volumes, + 'shm_size': '8G', + 'labels': ['dryrun'], + 'detach': False, + 'auto_remove': False, + 'remove': False, + } + + client.containers.run(**job_args) + + except ContainerError as e: + raise Exception(e.stderr) + + finally: + try: + container = client.containers.get(data_docker_name) + container.remove() + except Exception: + logger.error('Could not remove containers') + + remove_subtuple_materials(subtuple_directory) + + for data_sample in data_samples: + if 'file' in data_sample and os.path.exists(data_sample['file']): + os.remove(data_sample['file']) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index b865f17f9..c174c6111 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -88,3 +88,18 @@ def validate_pk(pk): int(pk, 16) # test if pk is correct (hexadecimal) except ValueError: raise Exception(f'Wrong pk {pk}') + + +class LedgerException(Exception): + def __init__(self, data, st): + self.data = data + self.st = st + super(LedgerException).__init__() + + +class ValidationException(Exception): + def __init__(self, data, pkhash, st): + self.data = data + self.pkhash = pkhash + self.st = st + super(ValidationException).__init__() From fa794a969e18803a09ac36972472f8c9043d5ce8 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 4 Jun 2019 11:20:01 +0200 Subject: [PATCH 066/457] Clean algo view. --- substrabac/substrapp/views/algo.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 94ee7f8dd..693890796 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -140,11 +140,12 @@ def retrieve(self, request, *args, **kwargs): logging.exception(e) return Response(str(e), status=status.HTTP_400_BAD_REQUEST) - # do not give access to local files address - serializer = self.get_serializer( - instance, - fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date ? + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) data.update(serializer.data) + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): From 1ad67f7d48f744ba6981eba573f9678bd1d949a6 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 4 Jun 2019 11:58:29 +0200 Subject: [PATCH 067/457] Rename ledger functions and add get_from_node function. --- substrabac/substrapp/ledger_utils.py | 18 +- .../substrapp/serializers/ledger/algo/util.py | 4 +- .../serializers/ledger/datamanager/util.py | 6 +- .../serializers/ledger/datasample/util.py | 6 +- .../serializers/ledger/objective/util.py | 4 +- .../serializers/ledger/testtuple/util.py | 4 +- .../serializers/ledger/traintuple/util.py | 4 +- substrabac/substrapp/tasks/tasks.py | 24 +- substrabac/substrapp/tests/tests_query.py | 16 +- substrabac/substrapp/tests/tests_tasks.py | 24 +- substrabac/substrapp/tests/tests_views.py | 222 +++++++++--------- substrabac/substrapp/utils.py | 32 ++- substrabac/substrapp/views/algo.py | 21 +- substrabac/substrapp/views/datamanager.py | 32 +-- substrabac/substrapp/views/filters_utils.py | 4 +- substrabac/substrapp/views/model.py | 24 +- substrabac/substrapp/views/objective.py | 24 +- substrabac/substrapp/views/testtuple.py | 10 +- substrabac/substrapp/views/traintuple.py | 10 +- substrabac/substrapp/views/utils.py | 4 +- 20 files changed, 239 insertions(+), 254 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index f563210d0..8438a6eef 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -12,8 +12,8 @@ asyncio.set_event_loop(LEDGER['hfc']['loop']) -# careful, passing invoke parameters to queryLedger will NOT fail -def queryLedger(fcn, args=None): +# careful, passing invoke parameters to query_ledger will NOT fail +def query_ledger(fcn, args=None): if args is None: args = [] @@ -81,12 +81,15 @@ def queryLedger(fcn, args=None): st = status.HTTP_409_CONFLICT data['pkhash'] = pkhash + if 'permissions' in data and data['permissions'] != 'all': + raise Exception('Not Allowed') + return data, st -def getObjectFromLedger(pk, query): +def get_object_from_ledger(pk, query): # get instance from remote node - data, st = queryLedger(fcn=query, args=[f'{pk}']) + data, st = query_ledger(fcn=query, args=[f'{pk}']) if st == status.HTTP_404_NOT_FOUND: raise Http404('Not found') @@ -94,13 +97,10 @@ def getObjectFromLedger(pk, query): if st != status.HTTP_200_OK: raise JsonException(data) - if 'permissions' not in data or data['permissions'] == 'all': - return data - else: - raise Exception('Not Allowed') + return data -def invokeLedger(fcn, args=None, cc_pattern=None, sync=False): +def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): if args is None: args = [] diff --git a/substrabac/substrapp/serializers/ledger/algo/util.py b/substrabac/substrapp/serializers/ledger/algo/util.py index 7d4c9f71d..ab50a74f2 100644 --- a/substrabac/substrapp/serializers/ledger/algo/util.py +++ b/substrabac/substrapp/serializers/ledger/algo/util.py @@ -3,12 +3,12 @@ from django.core.exceptions import ObjectDoesNotExist from substrapp.models import Algo -from substrapp.ledger_utils import invokeLedger +from substrapp.ledger_utils import invoke_ledger def createLedgerAlgo(args, pkhash, sync=False): - data, st = invokeLedger(fcn='registerAlgo', args=args, sync=sync) + data, st = invoke_ledger(fcn='registerAlgo', args=args, sync=sync) try: instance = Algo.objects.get(pk=pkhash) diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substrabac/substrapp/serializers/ledger/datamanager/util.py index c8a1103a0..88fac77b9 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/util.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/util.py @@ -3,12 +3,12 @@ from django.core.exceptions import ObjectDoesNotExist from substrapp.models import DataManager -from substrapp.ledger_utils import invokeLedger +from substrapp.ledger_utils import invoke_ledger def createLedgerDataManager(args, pkhash, sync=False): - data, st = invokeLedger(fcn='registerDataManager', args=args, sync=sync) + data, st = invoke_ledger(fcn='registerDataManager', args=args, sync=sync) try: instance = DataManager.objects.get(pk=pkhash) @@ -29,4 +29,4 @@ def createLedgerDataManager(args, pkhash, sync=False): def updateLedgerDataManager(args, sync=False): - return invokeLedger(fcn='updateDataManager', args=args, sync=sync) + return invoke_ledger(fcn='updateDataManager', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substrabac/substrapp/serializers/ledger/datasample/util.py index 53f9f22f4..573744892 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/util.py +++ b/substrabac/substrapp/serializers/ledger/datasample/util.py @@ -3,12 +3,12 @@ from django.core.exceptions import ObjectDoesNotExist from substrapp.models import DataSample -from substrapp.ledger_utils import invokeLedger +from substrapp.ledger_utils import invoke_ledger def createLedgerDataSample(args, pkhashes, sync=False): - data, st = invokeLedger(fcn='registerDataSample', args=args, sync=sync) + data, st = invoke_ledger(fcn='registerDataSample', args=args, sync=sync) try: instances = DataSample.objects.filter(pk__in=pkhashes) @@ -28,4 +28,4 @@ def createLedgerDataSample(args, pkhashes, sync=False): def updateLedgerDataSample(args, sync=False): - return invokeLedger(fcn='updateDataSample', args=args, sync=sync) + return invoke_ledger(fcn='updateDataSample', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/objective/util.py b/substrabac/substrapp/serializers/ledger/objective/util.py index f311bd6ad..a3befdc43 100644 --- a/substrabac/substrapp/serializers/ledger/objective/util.py +++ b/substrabac/substrapp/serializers/ledger/objective/util.py @@ -3,12 +3,12 @@ from django.core.exceptions import ObjectDoesNotExist from substrapp.models import Objective -from substrapp.ledger_utils import invokeLedger +from substrapp.ledger_utils import invoke_ledger def createLedgerObjective(args, pkhash, sync=False): - data, st = invokeLedger(fcn='registerObjective', args=args, sync=sync) + data, st = invoke_ledger(fcn='registerObjective', args=args, sync=sync) try: instance = Objective.objects.get(pk=pkhash) diff --git a/substrabac/substrapp/serializers/ledger/testtuple/util.py b/substrabac/substrapp/serializers/ledger/testtuple/util.py index ecb441011..62b9a1eb3 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/util.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/util.py @@ -1,8 +1,8 @@ from __future__ import absolute_import, unicode_literals -from substrapp.ledger_utils import invokeLedger +from substrapp.ledger_utils import invoke_ledger def createLedgerTesttuple(args, sync=False): - return invokeLedger(fcn='createTesttuple', args=args, sync=sync) + return invoke_ledger(fcn='createTesttuple', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/traintuple/util.py b/substrabac/substrapp/serializers/ledger/traintuple/util.py index 5ea3c58b0..a910516e6 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/util.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/util.py @@ -1,8 +1,8 @@ from __future__ import absolute_import, unicode_literals -from substrapp.ledger_utils import invokeLedger +from substrapp.ledger_utils import invoke_ledger def createLedgerTraintuple(args, sync=False): - return invokeLedger(fcn='createTraintuple', args=args, sync=sync) + return invoke_ledger(fcn='createTraintuple', args=args, sync=sync) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 93d56bca5..0b552b621 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -12,7 +12,7 @@ from rest_framework.reverse import reverse from substrabac.celery import app -from substrapp.ledger_utils import queryLedger, invokeLedger +from substrapp.ledger_utils import query_ledger, invoke_ledger from substrapp.utils import get_hash, create_directory, get_remote_file, uncompress_content from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code @@ -181,9 +181,10 @@ def remove_subtuple_materials(subtuple_directory): def log_fail_subtuple(key, err_msg, tuple_type): err_msg = str(err_msg).replace('"', "'").replace('\\', "").replace('\\n', "")[:200] fail_type = 'logFailTrain' if tuple_type == 'traintuple' else 'logFailTest' - data, st = invokeLedger(fcn=fail_type, - args=[f'{key}', f'{err_msg}'], - sync=True) + data, st = invoke_ledger( + fcn=fail_type, + args=[f'{key}', f'{err_msg}'], + sync=True) if st != status.HTTP_201_CREATED: logging.error(data, exc_info=True) @@ -224,9 +225,10 @@ def prepareTuple(subtuple, tuple_type, model_type): elif tuple_type == 'testtuple': start_type = 'logStartTest' - data, st = invokeLedger(fcn=start_type, - args=[f'{subtuple["key"]}'], - sync=True) + data, st = invoke_ledger( + fcn=start_type, + args=[f'{subtuple["key"]}'], + sync=True) if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): logging.error( @@ -249,9 +251,9 @@ def prepareTask(tuple_type, model_type): logging.error(e, exc_info=True) else: - subtuples, st = queryLedger(fcn="queryFilter", - args=[f'{tuple_type}~worker~status', - f'{data_owner},todo']) + subtuples, st = query_ledger( + fcn="queryFilter", + args=[f'{tuple_type}~worker~status', f'{data_owner},todo']) if st == status.HTTP_200_OK and subtuples is not None: for subtuple in subtuples: @@ -313,7 +315,7 @@ def computeTask(self, tuple_type, subtuple, model_type, fltask): f'{res["global_perf"]}', f'Test - {res["job_task_log"]};'] - data, st = invokeLedger(fcn=invoke_fcn, args=invoke_args, sync=True) + data, st = invoke_ledger(fcn=invoke_fcn, args=invoke_args, sync=True) if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): logging.error('Failed to invoke ledger on logSuccess') diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index 0a074813d..fcafd0277 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -227,8 +227,8 @@ def test_get_objective_metrics(self): description=self.objective_description, metrics=self.objective_metrics) with mock.patch( - 'substrapp.views.utils.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.return_value = self.objective_metrics + 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = self.objective_metrics extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } @@ -876,8 +876,8 @@ def test_bulk_update_data(self): } with mock.patch( - 'substrapp.serializers.ledger.datasample.util.invokeLedger') as minvokeLedger: - minvokeLedger.return_value = {'keys': [ + 'substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'keys': [ d.pkhash]}, status.HTTP_200_OK response = self.client.post(url, data, format='multipart', **extra) @@ -1054,8 +1054,8 @@ def test_add_algo_wrong_version(self): def test_get_algo_files(self): algo = Algo.objects.create(file=self.algo) with mock.patch( - 'substrapp.views.utils.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.return_value = self.algo + 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = self.algo extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } @@ -1120,10 +1120,10 @@ def test_add_traintuple_ok(self): } with mock.patch.object(LedgerTrainTupleSerializer, 'create') as mcreate, \ - mock.patch('substrapp.views.traintuple.queryLedger') as mqueryLedger: + mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: raw_pkhash = 'traintuple_pkhash'.encode('utf-8').hex() - mqueryLedger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) + mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) mcreate.return_value = ({ 'message': 'Traintuple added in local db waiting for validation.' 'The substra network has been notified for adding this Traintuple' diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index ce9c4f523..7426ce4eb 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -424,7 +424,7 @@ def __init__(self): with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash, \ - mock.patch('substrapp.tasks.tasks.queryLedger') as mqueryLedger, \ + mock.patch('substrapp.tasks.tasks.query_ledger') as mquery_ledger, \ mock.patch('substrapp.tasks.tasks.get_objective') as mget_objective, \ mock.patch('substrapp.tasks.tasks.get_algo') as mget_algo, \ mock.patch('substrapp.tasks.tasks.get_model') as mget_model, \ @@ -437,7 +437,7 @@ def __init__(self): msettings.return_value = FakeSettings() mget_hash.return_value = 'owkinhash' - mqueryLedger.return_value = subtuple, 200 + mquery_ledger.return_value = subtuple, 200 mget_objective.return_value = 'objective' mget_algo.return_value = 'algo', 'algo_hash' mget_model.return_value = 'model', 'model_hash' @@ -448,13 +448,13 @@ def __init__(self): mput_algo.return_value = 'algo' mput_model.return_value = 'model' - with mock.patch('substrapp.tasks.tasks.queryLedger') as mqueryLedger: - mqueryLedger.return_value = 'data', 404 + with mock.patch('substrapp.tasks.tasks.query_ledger') as mquery_ledger: + mquery_ledger.return_value = 'data', 404 prepareTask('traintuple', 'inModels') - with mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger, \ + with mock.patch('substrapp.tasks.tasks.invoke_ledger') as minvoke_ledger, \ mock.patch('substrapp.tasks.tasks.computeTask.apply_async') as mapply_async: - minvokeLedger.return_value = 'data', 201 + minvoke_ledger.return_value = 'data', 201 mapply_async.return_value = 'doTask' prepareTask('traintuple', 'inModels') @@ -474,10 +474,10 @@ def __init__(self): with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ mock.patch('substrapp.tasks.tasks.getattr') as mgetattr, \ - mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger: + mock.patch('substrapp.tasks.tasks.invoke_ledger') as minvoke_ledger: msettings.return_value = FakeSettings() mgetattr.return_value = self.subtuple_path - minvokeLedger.return_value = 'data', 200 + minvoke_ledger.return_value = 'data', 200 for name in ['opener', 'metrics']: with open(os.path.join(subtuple_directory, f'{name}/{name}.py'), 'w') as f: @@ -510,10 +510,10 @@ def __init__(self): with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ mock.patch('substrapp.tasks.tasks.getattr') as mgetattr, \ - mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger: + mock.patch('substrapp.tasks.tasks.invoke_ledger') as minvoke_ledger: msettings.return_value = FakeSettings() mgetattr.return_value = self.subtuple_path - minvokeLedger.return_value = 'data', 200 + minvoke_ledger.return_value = 'data', 200 for name in ['opener', 'metrics']: with open(os.path.join(subtuple_directory, f'{name}/{name}.py'), 'w') as f: @@ -528,10 +528,10 @@ def __init__(self): with mock.patch('substrapp.tasks.tasks.compute_docker') as mcompute_docker, \ mock.patch('substrapp.tasks.tasks.prepareMaterials') as mprepareMaterials, \ - mock.patch('substrapp.tasks.tasks.invokeLedger') as minvokeLedger: + mock.patch('substrapp.tasks.tasks.invoke_ledger') as minvoke_ledger: mcompute_docker.return_value = 'DONE' mprepareMaterials.return_value = 'DONE' - minvokeLedger.return_value = 'data', 201 + minvoke_ledger.return_value = 'data', 201 computeTask('traintuple', subtuple, 'inModels', None) diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py index ca888964b..e1547798a 100644 --- a/substrabac/substrapp/tests/tests_views.py +++ b/substrabac/substrapp/tests/tests_views.py @@ -19,7 +19,7 @@ from substrapp.views.datasample import path_leaf, compute_dryrun as data_sample_compute_dryrun from substrapp.views.objective import compute_dryrun as objective_compute_dryrun from substrapp.utils import compute_hash, get_hash -from substrapp.ledger_utils import getObjectFromLedger +from substrapp.ledger_utils import get_object_from_ledger from substrapp.models import DataManager @@ -48,18 +48,18 @@ def test_utils_ComputeHashMixin(self): self.assertEqual(myfilehash, compute.compute_hash(myfile)) self.assertEqual(myfilehashwithkey, compute.compute_hash(myfile, key)) - def test_utils_getObjectFromLedger(self): + def test_utils_get_object_from_ledger(self): - with mock.patch('substrapp.ledger_utils.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] - data = getObjectFromLedger('', 'queryObjective') + with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + data = get_object_from_ledger('', 'queryObjective') self.assertEqual(data, objective) - with mock.patch('substrapp.ledger_utils.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [('', status.HTTP_400_BAD_REQUEST)] + with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [('', status.HTTP_400_BAD_REQUEST)] with self.assertRaises(JsonException): - getObjectFromLedger('', 'queryAllObjective') + get_object_from_ledger('', 'queryAllObjective') # APITestCase @@ -97,9 +97,9 @@ def tearDown(self): def test_objective_list_empty(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(None, status.HTTP_200_OK), + (['ISIC'], status.HTTP_200_OK)] response = self.client.get(url, **self.extra) r = response.json() @@ -111,8 +111,8 @@ def test_objective_list_empty(self): def test_objective_list_filter_fail(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=challenERRORge' response = self.client.get(url + search_params, **self.extra) @@ -122,8 +122,8 @@ def test_objective_list_filter_fail(self): def test_objective_list_filter_name(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -133,8 +133,8 @@ def test_objective_list_filter_name(self): def test_objective_list_filter_metrics(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=objective%253Ametrics%253Amacro-average%2520recall' response = self.client.get(url + search_params, **self.extra) @@ -144,10 +144,10 @@ def test_objective_list_filter_metrics(self): def test_objective_list_filter_datamanager(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -157,10 +157,10 @@ def test_objective_list_filter_datamanager(self): def test_objective_list_filter_model(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(objective, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' @@ -172,9 +172,9 @@ def test_objective_list_filter_model(self): def test_objective_retrieve(self): url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.getObjectFromLedger') as mgetObjectFromLedger, \ - mock.patch('substrapp.views.objective.requests.get') as mrequestsget: - mgetObjectFromLedger.return_value = objective[0] + with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger, \ + mock.patch('substrapp.views.objective.get_from_node') as mrequestsget: + mget_object_from_ledger.return_value = objective[0] with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../../fixtures/owkin/objectives/objective0/description.md'), 'rb') as f: @@ -204,8 +204,8 @@ def test_objective_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - with mock.patch('substrapp.views.objective.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.side_effect = JsonException('TEST') + with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) search_params = f'{file_hash}/' @@ -303,7 +303,7 @@ def test_objective_compute_dryrun(self): test_data_manager_key = compute_hash(opener_content) - with mock.patch('substrapp.views.objective.getObjectFromLedger') as mdatamanager,\ + with mock.patch('substrapp.views.objective.get_object_from_ledger') as mdatamanager,\ mock.patch('substrapp.views.objective.get_computed_hash') as mopener: mdatamanager.return_value = {'opener': {'storageAddress': 'test'}} mopener.return_value = (opener_content, pkhash) @@ -337,9 +337,9 @@ def tearDown(self): def test_algo_list_empty(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(None, status.HTTP_200_OK), + (['ISIC'], status.HTTP_200_OK)] response = self.client.get(url, **self.extra) r = response.json() @@ -351,8 +351,8 @@ def test_algo_list_empty(self): def test_algo_list_filter_fail(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] search_params = '?search=algERRORo' response = self.client.get(url + search_params, **self.extra) @@ -362,8 +362,8 @@ def test_algo_list_filter_fail(self): def test_algo_list_filter_name(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] search_params = '?search=algo%253Aname%253ALogistic%2520regression' response = self.client.get(url + search_params, **self.extra) @@ -373,10 +373,10 @@ def test_algo_list_filter_name(self): def test_algo_list_filter_datamanager_fail(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -386,10 +386,10 @@ def test_algo_list_filter_datamanager_fail(self): def test_algo_list_filter_objective_fail(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -399,10 +399,10 @@ def test_algo_list_filter_objective_fail(self): def test_algo_list_filter_model(self): url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(algo, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' @@ -416,13 +416,13 @@ def test_algo_retrieve(self): algo_hash = get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo4/algo.tar.gz')) url = reverse('substrapp:algo-list') algo_response = [a for a in algo if a['key'] == algo_hash][0] - with mock.patch('substrapp.views.algo.getObjectFromLedger') as mgetObjectFromLedger, \ - mock.patch('substrapp.views.algo.requests.get') as mrequestsget: + with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger, \ + mock.patch('substrapp.views.algo.get_from_node') as mrequestsget: with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo4/description.md'), 'rb') as f: content = f.read() - mgetObjectFromLedger.return_value = algo_response + mget_object_from_ledger.return_value = algo_response mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, content=content) @@ -448,8 +448,8 @@ def test_algo_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - with mock.patch('substrapp.views.algo.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.side_effect = JsonException('TEST') + with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) search_params = f'{file_hash}/' @@ -513,9 +513,9 @@ def tearDown(self): def test_model_list_empty(self): url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(None, status.HTTP_200_OK), + (['ISIC'], status.HTTP_200_OK)] response = self.client.get(url, **self.extra) r = response.json() @@ -527,8 +527,8 @@ def test_model_list_empty(self): def test_model_list_filter_fail(self): - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] url = reverse('substrapp:model-list') search_params = '?search=modeERRORl' @@ -538,8 +538,8 @@ def test_model_list_filter_fail(self): def test_model_list_filter_hash(self): - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] pkhash = model[0]['traintuple']['outModel']['hash'] url = reverse('substrapp:model-list') @@ -550,10 +550,10 @@ def test_model_list_filter_hash(self): def test_model_list_filter_datamanager(self): url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(datamanager, status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] search_params = '?search=dataset%253Aname%253AISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -563,10 +563,10 @@ def test_model_list_filter_datamanager(self): def test_model_list_filter_objective(self): url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -576,10 +576,10 @@ def test_model_list_filter_objective(self): def test_model_list_filter_algo(self): url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(model, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(algo, status.HTTP_200_OK)] + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(algo, status.HTTP_200_OK)] search_params = '?search=algo%253Aname%253ALogistic%2520regression' response = self.client.get(url + search_params, **self.extra) @@ -589,10 +589,10 @@ def test_model_list_filter_algo(self): def test_model_retrieve(self): - with mock.patch('substrapp.views.model.getObjectFromLedger') as mgetObjectFromLedger, \ - mock.patch('substrapp.views.model.requests.get') as mrequestsget, \ + with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger, \ + mock.patch('substrapp.views.model.get_from_node') as mrequestsget, \ mock.patch('substrapp.views.model.ModelViewSet.compute_hash') as mcomputed_hash: - mgetObjectFromLedger.return_value = model[0] + mget_object_from_ledger.return_value = model[0] mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, content=self.model.read().encode()) @@ -621,8 +621,8 @@ def test_model_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - with mock.patch('substrapp.views.model.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.side_effect = JsonException('TEST') + with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) search_params = f'{file_hash}/' @@ -658,9 +658,9 @@ def tearDown(self): def test_datamanager_list_empty(self): url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(None, status.HTTP_200_OK), + (['ISIC'], status.HTTP_200_OK)] response = self.client.get(url, **self.extra) r = response.json() @@ -672,8 +672,8 @@ def test_datamanager_list_empty(self): def test_datamanager_list_filter_fail(self): url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK)] + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] search_params = '?search=dataseERRORt' response = self.client.get(url + search_params, **self.extra) @@ -683,8 +683,8 @@ def test_datamanager_list_filter_fail(self): def test_datamanager_list_filter_name(self): url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger: - mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK)] + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -694,10 +694,10 @@ def test_datamanager_list_filter_name(self): def test_datamanager_list_filter_objective(self): url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(objective, status.HTTP_200_OK)] + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -707,10 +707,10 @@ def test_datamanager_list_filter_objective(self): def test_datamanager_list_filter_model(self): url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.queryLedger') as mqueryLedger, \ - mock.patch('substrapp.views.filters_utils.queryLedger') as mqueryLedger2: - mqueryLedger.side_effect = [(datamanager, status.HTTP_200_OK)] - mqueryLedger2.side_effect = [(traintuple, status.HTTP_200_OK)] + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' response = self.client.get(url + search_params, **self.extra) @@ -722,9 +722,9 @@ def test_datamanager_retrieve(self): url = reverse('substrapp:data_manager-list') datamanager_response = [d for d in datamanager if d['key'] == '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7'][0] - with mock.patch('substrapp.views.datamanager.getObjectFromLedger') as mgetObjectFromLedger, \ - mock.patch('substrapp.views.datamanager.requests.get') as mrequestsget: - mgetObjectFromLedger.return_value = datamanager_response + with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger, \ + mock.patch('substrapp.views.datamanager.get_from_node') as mrequestsget: + mget_object_from_ledger.return_value = datamanager_response with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), 'rb') as f: @@ -760,8 +760,8 @@ def test_datamanager_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - with mock.patch('substrapp.views.datamanager.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.side_effect = JsonException('TEST') + with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) search_params = f'{file_hash}/' @@ -824,8 +824,8 @@ def test_traintuple_queryset(self): def test_traintuple_list_empty(self): url = reverse('substrapp:traintuple-list') - with mock.patch('substrapp.views.traintuple.queryLedger') as mqueryLedger: - mqueryLedger.return_value = ([[]], status.HTTP_200_OK) + with mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: + mquery_ledger.return_value = ([[]], status.HTTP_200_OK) response = self.client.get(url, **self.extra) r = response.json() @@ -833,8 +833,8 @@ def test_traintuple_list_empty(self): def test_traintuple_retrieve(self): - with mock.patch('substrapp.views.traintuple.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.return_value = traintuple[0] + with mock.patch('substrapp.views.traintuple.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = traintuple[0] url = reverse('substrapp:traintuple-list') search_params = 'c164f4c714a78c7e2ba2016de231cdd41e3eac61289e08c1f711e74915a0868f/' response = self.client.get(url + search_params, **self.extra) @@ -856,8 +856,8 @@ def test_traintuple_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - with mock.patch('substrapp.views.traintuple.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.side_effect = JsonException('TEST') + with mock.patch('substrapp.views.traintuple.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) search_params = f'{file_hash}/' @@ -894,8 +894,8 @@ def test_testtuple_queryset(self): def test_testtuple_list_empty(self): url = reverse('substrapp:testtuple-list') - with mock.patch('substrapp.views.testtuple.queryLedger') as mqueryLedger: - mqueryLedger.return_value = ([[]], status.HTTP_200_OK) + with mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: + mquery_ledger.return_value = ([[]], status.HTTP_200_OK) response = self.client.get(url, **self.extra) r = response.json() @@ -903,8 +903,8 @@ def test_testtuple_list_empty(self): def test_testtuple_retrieve(self): - with mock.patch('substrapp.views.testtuple.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.return_value = testtuple[0] + with mock.patch('substrapp.views.testtuple.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = testtuple[0] url = reverse('substrapp:testtuple-list') search_params = 'c164f4c714a78c7e2ba2016de231cdd41e3eac61289e08c1f711e74915a0868f/' response = self.client.get(url + search_params, **self.extra) @@ -926,8 +926,8 @@ def test_testtuple_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - with mock.patch('substrapp.views.testtuple.getObjectFromLedger') as mgetObjectFromLedger: - mgetObjectFromLedger.side_effect = JsonException('TEST') + with mock.patch('substrapp.views.testtuple.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) search_params = f'{file_hash}/' diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 650d8024c..69b3e52ad 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -13,6 +13,7 @@ from checksumdir import dirhash from django.conf import settings +from rest_framework import status class JsonException(Exception): @@ -80,18 +81,11 @@ def get_computed_hash(url, key=None): if settings.DEBUG: kwargs.update({'verify': False}) - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}, **kwargs) - except Exception: - raise Exception(f'Failed to check hash due to failed file fetching {url}') - else: - if r.status_code != 200: - raise Exception( - f'Url: {url} to fetch file returned status code: {r.status_code}') + response = get_from_node(url, **kwargs) - computedHash = compute_hash(r.content, key) + computedHash = compute_hash(response.content, key) - return r.content, computedHash + return response.content, computedHash def get_remote_file(object, key=None): @@ -135,3 +129,21 @@ def uncompress_content(archive_content, to_directory): tar.close() except tarfile.TarError: raise Exception('Archive must be zip or tar.*') + + +class NodeError(Exception): + pass + + +def get_from_node(url, **kwargs): + + try: + response = requests.get(url, headers={'Accept': 'application/json;version=0.0'}, **kwargs) + except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: + raise NodeError(f'Failed to fetch {url}') from e + else: + if response.status_code != status.HTTP_200_OK: + logging.error(response.text) + raise NodeError(f'Url: {url} returned status code: {response.status_code}') + + return response diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 693890796..f28907556 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -1,6 +1,5 @@ import tempfile import logging -import requests from django.http import Http404 from rest_framework import status, mixins @@ -11,8 +10,8 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer -from substrapp.utils import get_hash, JsonException -from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.utils import get_hash, JsonException, get_from_node +from substrapp.ledger_utils import query_ledger, get_object_from_ledger from substrapp.views.utils import (ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk) from substrapp.views.filters_utils import filter_list @@ -81,17 +80,11 @@ def create(self, request, *args, **kwargs): def create_or_update_algo(self, algo, pk): # get algo description from remote node url = algo['description']['storageAddress'] - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) # TODO pass cert - except Exception as e: - raise Exception(f'Failed to fetch {url}') from e - if r.status_code != status.HTTP_200_OK: - logging.error(f'Request failed: {r.text}') - raise Exception(f'Failed to fetch {url}: invalid status code {r.status_code}') + response = get_from_node(url) try: - computed_hash = self.compute_hash(r.content) + computed_hash = self.compute_hash(response.content) except Exception as e: raise Exception('Failed to fetch description file') from e @@ -101,7 +94,7 @@ def create_or_update_algo(self, algo, pk): raise Exception(msg) f = tempfile.TemporaryFile() - f.write(r.content) + f.write(response.content) # save/update objective in local db for later use instance, created = Algo.objects.update_or_create(pkhash=pk, validated=True) @@ -120,7 +113,7 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: - data = getObjectFromLedger(pk, self.ledger_query_call) + data = get_object_from_ledger(pk, self.ledger_query_call) except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: @@ -149,7 +142,7 @@ def retrieve(self, request, *args, **kwargs): return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): - data, st = queryLedger(fcn='queryAlgos', args=[]) + data, st = query_ledger(fcn='queryAlgos', args=[]) data = data if data else [] algos_list = [data] diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index eea59c0f9..164427f05 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -1,7 +1,6 @@ import ast import tempfile import logging -import requests from django.conf import settings from django.http import Http404 from rest_framework import status, mixins @@ -16,8 +15,8 @@ from substrapp.serializers import DataManagerSerializer, LedgerDataManagerSerializer from substrapp.serializers.ledger.datamanager.util import updateLedgerDataManager from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync -from substrapp.utils import get_hash, JsonException -from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.utils import get_hash, JsonException, get_from_node +from substrapp.ledger_utils import query_ledger, get_object_from_ledger from substrapp.views.utils import (ManageFileMixin, ComputeHashMixin, find_primary_key_error, validate_pk) from substrapp.views.filters_utils import filter_list @@ -120,16 +119,11 @@ def create_or_update_datamanager(self, instance, datamanager, pk): if not instance.data_opener: url = datamanager['opener']['storageAddress'] - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) - except Exception as e: - raise Exception(f'Failed to fetch {url}') from e - if r.status_code != 200: - raise Exception(f'end to end node report {r.text}') + response = get_from_node(url) try: - computed_hash = self.compute_hash(r.content) + computed_hash = self.compute_hash(response.content) except Exception as e: raise Exception('Failed to fetch opener file') from e @@ -139,7 +133,7 @@ def create_or_update_datamanager(self, instance, datamanager, pk): raise Exception(msg) f = tempfile.TemporaryFile() - f.write(r.content) + f.write(response.content) # save/update data_opener in local db for later use instance.data_opener.save('opener.py', f) @@ -147,15 +141,11 @@ def create_or_update_datamanager(self, instance, datamanager, pk): # do the same for description if not instance.description: url = datamanager['description']['storageAddress'] - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) - except Exception as e: - raise Exception(f'Failed to fetch {url}') from e - if r.status_code != status.HTTP_200_OK: - raise Exception(f'end to end node report {r.text}') + + response = get_from_node(url) try: - computed_hash = self.compute_hash(r.content) + computed_hash = self.compute_hash(response.content) except Exception as e: raise Exception('Failed to fetch description file') from e @@ -165,7 +155,7 @@ def create_or_update_datamanager(self, instance, datamanager, pk): raise Exception(msg) f = tempfile.TemporaryFile() - f.write(r.content) + f.write(response.content) # save/update description in local db for later use instance.description.save('description.md', f) @@ -183,7 +173,7 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: - data = getObjectFromLedger(pk, 'queryDataset') + data = get_object_from_ledger(pk, 'queryDataset') except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: @@ -212,7 +202,7 @@ def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): - data, st = queryLedger(fcn='queryDataManagers', args=[]) + data, st = query_ledger(fcn='queryDataManagers', args=[]) data = data if data else [] data_managers_list = [data] diff --git a/substrabac/substrapp/views/filters_utils.py b/substrabac/substrapp/views/filters_utils.py index bed30ef4b..ca68bf3e6 100644 --- a/substrabac/substrapp/views/filters_utils.py +++ b/substrabac/substrapp/views/filters_utils.py @@ -3,7 +3,7 @@ from rest_framework import status from rest_framework.response import Response -from substrapp.ledger_utils import queryLedger +from substrapp.ledger_utils import query_ledger FILTER_QUERIES = { @@ -96,7 +96,7 @@ def filter_list(object_type, data, query_params): # Filter by other asset # Get other asset list - filtering_data, st = queryLedger(fcn=FILTER_QUERIES[filter_key], args=[]) + filtering_data, st = query_ledger(fcn=FILTER_QUERIES[filter_key], args=[]) if st != status.HTTP_200_OK: return Response(filtering_data, status=st) filtering_data = filtering_data if filtering_data else [] diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 90fae5838..1c023f4dd 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -1,7 +1,6 @@ import os import tempfile import logging -import requests from django.http import Http404 from rest_framework import status, mixins from rest_framework.decorators import action @@ -11,8 +10,8 @@ from substrapp.models import Model from substrapp.serializers import ModelSerializer -from substrapp.utils import JsonException -from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.utils import JsonException, get_from_node +from substrapp.ledger_utils import query_ledger, get_object_from_ledger from substrapp.views.utils import ComputeHashMixin, CustomFileResponse, validate_pk from substrapp.views.filters_utils import filter_list @@ -32,17 +31,12 @@ def create_or_update_model(self, traintuple, pk): # get model from remote node url = traintuple['outModel']['storageAddress'] - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) - except Exception: - raise Exception(f'Failed to fetch {url}') - else: - if r.status_code != 200: - raise Exception(f'end to end node report {r.text}') + + response = get_from_node(url) # verify model received has a good pkhash try: - computed_hash = self.compute_hash(r.content, traintuple['key']) + computed_hash = self.compute_hash(response.content, traintuple['key']) except Exception: raise Exception('Failed to fetch outModel file') else: @@ -53,7 +47,7 @@ def create_or_update_model(self, traintuple, pk): # write model in local db for later use tmp_model = tempfile.TemporaryFile() - tmp_model.write(r.content) + tmp_model.write(response.content) instance, created = Model.objects.update_or_create(pkhash=pk, validated=True) instance.file.save('model', tmp_model) @@ -70,7 +64,7 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: - data = getObjectFromLedger(pk, self.ledger_query_call) + data = get_object_from_ledger(pk, self.ledger_query_call) except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: @@ -99,7 +93,7 @@ def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): - data, st = queryLedger(fcn='queryModels', args=[]) + data, st = query_ledger(fcn='queryModels', args=[]) data = data if data else [] models_list = [data] @@ -130,5 +124,5 @@ def file(self, request, *args, **kwargs): def details(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - data, st = queryLedger(fcn='queryModelDetails', args=[f'{pk}']) + data, st = query_ledger(fcn='queryModelDetails', args=[f'{pk}']) return Response(data, st) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index a31d969f5..ba947b8aa 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -6,7 +6,6 @@ import tempfile import uuid -import requests from django.conf import settings from django.db import IntegrityError from django.http import Http404 @@ -23,8 +22,8 @@ from substrapp.models import Objective from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer -from substrapp.ledger_utils import queryLedger, getObjectFromLedger -from substrapp.utils import get_hash, get_computed_hash, JsonException +from substrapp.ledger_utils import query_ledger, get_object_from_ledger +from substrapp.utils import get_hash, get_computed_hash, JsonException, get_from_node from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk from substrapp.views.filters_utils import filter_list @@ -128,17 +127,12 @@ def create_or_update_objective(self, objective, pk): # get description from remote node url = objective['description']['storageAddress'] - try: - r = requests.get(url, headers={'Accept': 'application/json;version=0.0'}) - except (requests.exceptions.ConnectionError, requests.exceptions.Timeout): - raise Exception(f'Failed to fetch {url}') - else: - if r.status_code != status.HTTP_200_OK: - raise Exception(f'end to end node report {r.text}') + + response = get_from_node(url) # verify description received has a good pkhash try: - computed_hash = self.compute_hash(r.content) + computed_hash = self.compute_hash(response.content) except Exception: raise Exception('Failed to fetch description file') else: @@ -149,7 +143,7 @@ def create_or_update_objective(self, objective, pk): # write objective with description in local db for later use tmp_description = tempfile.TemporaryFile() - tmp_description.write(r.content) + tmp_description.write(response.content) instance, created = Objective.objects.update_or_create(pkhash=pk, validated=True) instance.description.save('description.md', tmp_description) @@ -166,7 +160,7 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: - data = getObjectFromLedger(pk, self.ledger_query_call) + data = get_object_from_ledger(pk, self.ledger_query_call) except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: @@ -194,7 +188,7 @@ def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): - data, st = queryLedger(fcn='queryObjectives', args=[]) + data, st = query_ledger(fcn='queryObjectives', args=[]) data = data if data else [] objectives_list = [data] @@ -249,7 +243,7 @@ def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): if not test_data_manager_key: raise Exception('Cannot do a objective dryrun without a data manager key.') - datamanager = getObjectFromLedger(test_data_manager_key, 'queryDataManager') + datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') opener_content, opener_computed_hash = get_computed_hash(datamanager['opener']['storageAddress']) with open(os.path.join(subtuple_directory, 'opener/opener.py'), 'wb') as file: file.write(opener_content) diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 19cf1edf6..d908e4425 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -4,7 +4,7 @@ from rest_framework.viewsets import GenericViewSet from substrapp.serializers import LedgerTestTupleSerializer -from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.ledger_utils import query_ledger, get_object_from_ledger from substrapp.utils import JsonException from substrapp.views.utils import validate_pk @@ -34,9 +34,9 @@ def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) - # Get testtuple pkhash to handle 408 timeout in invokeLedger + # Get testtuple pkhash to handle 408 timeout in invoke_ledger args = serializer.get_args(serializer.validated_data) - data, st = queryLedger(fcn='createTesttuple', args=args) + data, st = query_ledger(fcn='createTesttuple', args=args) if st == status.HTTP_409_CONFLICT: return Response({'message': data['message'], 'pkhash': data['pkhash']}, status=st) @@ -53,7 +53,7 @@ def create(self, request, *args, **kwargs): return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): - data, st = queryLedger(fcn='queryTesttuples', args=[]) + data, st = query_ledger(fcn='queryTesttuples', args=[]) data = data if data else [] return Response(data, status=st) @@ -68,7 +68,7 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: - data = getObjectFromLedger(pk, self.ledger_query_call) + data = get_object_from_ledger(pk, self.ledger_query_call) except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 31ac9f1fa..db47ab628 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -4,7 +4,7 @@ from rest_framework.viewsets import GenericViewSet from substrapp.serializers import LedgerTrainTupleSerializer -from substrapp.ledger_utils import queryLedger, getObjectFromLedger +from substrapp.ledger_utils import query_ledger, get_object_from_ledger from substrapp.utils import JsonException from substrapp.views.utils import validate_pk @@ -38,9 +38,9 @@ def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) - # Get traintuple pkhash to handle 408 timeout in invokeLedger + # Get traintuple pkhash to handle 408 timeout in invoke_ledger args = serializer.get_args(serializer.validated_data) - data, st = queryLedger(fcn='createTraintuple', args=args) + data, st = query_ledger(fcn='createTraintuple', args=args) if st == status.HTTP_409_CONFLICT: return Response({'message': data['message'], 'pkhash': data['pkhash']}, status=st) @@ -57,7 +57,7 @@ def create(self, request, *args, **kwargs): return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): - data, st = queryLedger(fcn='queryTraintuples', args=[]) + data, st = query_ledger(fcn='queryTraintuples', args=[]) data = data if data else [] return Response(data, status=st) @@ -72,7 +72,7 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: - data = getObjectFromLedger(pk, self.ledger_query_call) + data = get_object_from_ledger(pk, self.ledger_query_call) except JsonException as e: return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) except Http404: diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index c174c6111..796c5ba38 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -5,7 +5,7 @@ from rest_framework import status from rest_framework.response import Response -from substrapp.ledger_utils import getObjectFromLedger +from substrapp.ledger_utils import get_object_from_ledger class ComputeHashMixin(object): @@ -39,7 +39,7 @@ def manage_file(self, field): # TODO get cert for permissions check try: - getObjectFromLedger(pk, self.ledger_query_call) + get_object_from_ledger(pk, self.ledger_query_call) except Exception as e: return Response(e, status=status.HTTP_400_BAD_REQUEST) except Http404: From ac1f63f504436646bb0a32045fdad21758144d79 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 4 Jun 2019 14:50:47 +0200 Subject: [PATCH 068/457] Move and ignore deprecated test commands. --- substrabac/.coveragerc | 1 + .../{ => management}/tests/tests_bulkcreatedatasample.py | 0 .../substrapp/{ => management}/tests/tests_createdatamanager.py | 0 .../substrapp/{ => management}/tests/tests_createobjective.py | 0 4 files changed, 1 insertion(+) rename substrabac/substrapp/{ => management}/tests/tests_bulkcreatedatasample.py (100%) rename substrabac/substrapp/{ => management}/tests/tests_createdatamanager.py (100%) rename substrabac/substrapp/{ => management}/tests/tests_createobjective.py (100%) diff --git a/substrabac/.coveragerc b/substrabac/.coveragerc index 46ae5d5cf..6b884c5d7 100644 --- a/substrabac/.coveragerc +++ b/substrabac/.coveragerc @@ -6,6 +6,7 @@ source = omit = #./substrapp/serializers/ledger/* ./substrapp/tests/generate_assets.py + ./substrapp/management/* [report] # Regexes for lines to exclude from consideration diff --git a/substrabac/substrapp/tests/tests_bulkcreatedatasample.py b/substrabac/substrapp/management/tests/tests_bulkcreatedatasample.py similarity index 100% rename from substrabac/substrapp/tests/tests_bulkcreatedatasample.py rename to substrabac/substrapp/management/tests/tests_bulkcreatedatasample.py diff --git a/substrabac/substrapp/tests/tests_createdatamanager.py b/substrabac/substrapp/management/tests/tests_createdatamanager.py similarity index 100% rename from substrabac/substrapp/tests/tests_createdatamanager.py rename to substrabac/substrapp/management/tests/tests_createdatamanager.py diff --git a/substrabac/substrapp/tests/tests_createobjective.py b/substrabac/substrapp/management/tests/tests_createobjective.py similarity index 100% rename from substrabac/substrapp/tests/tests_createobjective.py rename to substrabac/substrapp/management/tests/tests_createobjective.py From b03d026362325fc15d8586576e8e1713c41cb168 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 4 Jun 2019 16:05:32 +0200 Subject: [PATCH 069/457] (WIP) Refacto task. One test does not pass. --- substrabac/.coveragerc | 4 +- substrabac/events/apps.py | 19 +- substrabac/substrabac/celery.py | 6 +- substrabac/substrapp/ledger_utils.py | 63 ++++ substrabac/substrapp/tasks/tasks.py | 419 ++++++++++------------ substrabac/substrapp/tests/tests_tasks.py | 51 ++- 6 files changed, 299 insertions(+), 263 deletions(-) diff --git a/substrabac/.coveragerc b/substrabac/.coveragerc index 6b884c5d7..ae10b6470 100644 --- a/substrabac/.coveragerc +++ b/substrabac/.coveragerc @@ -29,5 +29,5 @@ exclude_lines = if 'environment' in job_args # Ignore functions - def prepareTrainingTask - def prepareTestingTask + def prepare_training_task + def prepare_testing_task diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index d49068bca..14abb25d5 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -16,7 +16,7 @@ from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore -from substrapp.tasks.tasks import prepareTuple +from substrapp.tasks.tasks import prepare_tuple from substrapp.utils import get_hash LEDGER = getattr(settings, 'LEDGER', None) @@ -38,8 +38,7 @@ def get_block_payload(block): 'extension']['events']['payload']) return payload - -def onTupleEvent(block): +_edef on_tupleEvent(block): payload = get_block_payload(block) worker_queue = f"{LEDGER['name']}.worker" @@ -49,14 +48,14 @@ def onTupleEvent(block): logging.error(e, exc_info=True) else: if data_owner == payload['dataset']['worker']: - tuple_type, model_type = (None, None) + tuple_type = None if 'inModels' in payload: - tuple_type, model_type = ('traintuple', 'inModels') + tuple_type = 'traintuple' elif 'model' in payload: - tuple_type, model_type = ('testtuple', 'model') + tuple_type = 'testtuple' - if tuple_type is not None and model_type is not None: - prepareTuple.apply_async((payload, tuple_type, model_type), queue=worker_queue) + if tuple_type is not None: + prepare_tuple.apply_async((payload, tuple_type), queue=worker_queue) def wait(): @@ -106,10 +105,10 @@ def wait(): channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-creation', - onEvent=onTupleEvent) + onEvent=on_tuple_event) channel_event_hub.registerChaincodeEvent(chaincode_name, 'testtuple-creation', - onEvent=onTupleEvent) + onEvent=on_tuple_event) loop.run_until_complete(stream) diff --git a/substrabac/substrabac/celery.py b/substrabac/substrabac/celery.py index 7eccee6d4..b862eb821 100644 --- a/substrabac/substrabac/celery.py +++ b/substrabac/substrabac/celery.py @@ -20,10 +20,10 @@ @app.on_after_configure.connect def setup_periodic_tasks(sender, **kwargs): - from substrapp.tasks.tasks import prepareTrainingTask, prepareTestingTask + from substrapp.tasks.tasks import prepare_training_task, prepare_testing_task period = 3 * 3600 - sender.add_periodic_task(period, prepareTrainingTask.s(), queue='scheduler', + sender.add_periodic_task(period, prepare_training_task.s(), queue='scheduler', name='query Traintuples to prepare train task on todo traintuples') - sender.add_periodic_task(period, prepareTestingTask.s(), queue='scheduler', + sender.add_periodic_task(period, prepare_testing_task.s(), queue='scheduler', name='query Testuples to prepare test task on todo testuples') diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 8438a6eef..f519089bc 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -1,4 +1,5 @@ import asyncio +import logging import json from rest_framework import status @@ -171,3 +172,65 @@ def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): data['pkhash'] = pkhash return data, st + + +def log_fail_tuple(tuple_type, tuple_key, err_msg): + err_msg = str(err_msg).replace('"', "'").replace('\\', "").replace('\\n', "")[:200] + + fail_type = 'logFailTrain' if tuple_type == 'traintuple' else 'logFailTest' + + data, st = invoke_ledger( + fcn=fail_type, + args=[f'{tuple_key}', f'{err_msg}'], + sync=True) + + return data, st + + +def log_success_tuple(tuple_type, tuple_key, res): + if tuple_type == 'traintuple': + invoke_fcn = 'logSuccessTrain' + # TODO: will be replace by a dict + invoke_args = [f'{tuple_key}', + f'{res["end_model_file_hash"]}, {res["end_model_file"]}', + f'{res["global_perf"]}', + f'Train - {res["job_task_log"]};'] + + elif tuple_type == 'testtuple': + invoke_fcn = 'logSuccessTest' + # TODO: will be replace by a dict + invoke_args = [f'{tuple_key}', + f'{res["global_perf"]}', + f'Test - {res["job_task_log"]};'] + else: + raise NotImplementedError() + + data, st = invoke_ledger(fcn=invoke_fcn, args=invoke_args, sync=True) + + return data, st + + +def log_start_tuple(tuple_type, tuple_key): + start_type = None + + if tuple_type == 'traintuple': + start_type = 'logStartTrain' + elif tuple_type == 'testtuple': + start_type = 'logStartTest' + else: + raise NotImplementedError() + + data, st = invoke_ledger( + fcn=start_type, + args=[f'{tuple_key}'], + sync=True) + + return data, st + + +def query_tuples(tuple_type, data_owner): + tuples, st = query_ledger( + fcn="queryFilter", + args=[f'{tuple_type}~worker~status', f'{data_owner},todo']) + + return tuples, st diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 0b552b621..f5083396f 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -12,8 +12,9 @@ from rest_framework.reverse import reverse from substrabac.celery import app -from substrapp.ledger_utils import query_ledger, invoke_ledger from substrapp.utils import get_hash, create_directory, get_remote_file, uncompress_content +from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, + query_tuples) from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code @@ -162,9 +163,10 @@ def put_algo(subtuple_directory, algo_content): def build_subtuple_folders(subtuple): - # create a folder named subtuple['key'] im /medias/subtuple with 5 folders opener, data, model, pred, metrics + # create a folder named `subtuple['key']` in /medias/subtuple/ with 5 subfolders opener, data, model, pred, metrics subtuple_directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'subtuple', subtuple['key']) create_directory(subtuple_directory) + for folder in ['opener', 'data', 'model', 'pred', 'metrics']: create_directory(path.join(subtuple_directory, folder)) @@ -178,21 +180,6 @@ def remove_subtuple_materials(subtuple_directory): logging.exception(e) -def log_fail_subtuple(key, err_msg, tuple_type): - err_msg = str(err_msg).replace('"', "'").replace('\\', "").replace('\\n', "")[:200] - fail_type = 'logFailTrain' if tuple_type == 'traintuple' else 'logFailTest' - data, st = invoke_ledger( - fcn=fail_type, - args=[f'{key}', f'{err_msg}'], - sync=True) - - if st != status.HTTP_201_CREATED: - logging.error(data, exc_info=True) - else: - logging.info('Successfully passed the subtuple to failed') - return data - - # Instatiate Ressource Manager in BaseManager to share it between celery concurrent tasks BaseManager.register('ResourcesManager', ResourcesManager) manager = BaseManager() @@ -200,8 +187,32 @@ def log_fail_subtuple(key, err_msg, tuple_type): resources_manager = manager.ResourcesManager() +@app.task(bind=True, ignore_result=True) +def prepare_training_task(self): + prepare_task('traintuple', 'inModels') + + +@app.task(ignore_result=True) +def prepare_testing_task(): + prepare_task('testtuple', 'model') + + +def prepare_task(tuple_type): + try: + data_owner = get_hash(settings.LEDGER['signcert']) + except Exception as e: + logging.exception(e) + else: + + tuples, st = query_tuples(tuple_type, data_owner) + + if st == status.HTTP_200_OK and tuples is not None: + for subtuple in tuples: + prepare_tuple(subtuple, tuple_type) + + @app.task(ignore_result=False) -def prepareTuple(subtuple, tuple_type, model_type): +def prepare_tuple(subtuple, tuple_type): from django_celery_results.models import TaskResult fltask = None @@ -210,68 +221,36 @@ def prepareTuple(subtuple, tuple_type, model_type): if 'fltask' in subtuple and subtuple['fltask']: fltask = subtuple['fltask'] flresults = TaskResult.objects.filter( - task_name='substrapp.tasks.tasks.computeTask', + task_name='substrapp.tasks.tasks.compute_task', result__icontains=f'"fltask": "{fltask}"') if flresults and flresults.count() > 0: worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] try: - # Log Start of the Subtuple - - start_type = None - if tuple_type == 'traintuple': - start_type = 'logStartTrain' - elif tuple_type == 'testtuple': - start_type = 'logStartTest' - - data, st = invoke_ledger( - fcn=start_type, - args=[f'{subtuple["key"]}'], - sync=True) + data, st = log_start_tuple(tuple_type, subtuple['key']) if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - logging.error( - f'Failed to invoke ledger on prepareTask {tuple_type}. Error: {data}') + raise Exception( + f'Failed to invoke ledger on prepare_task {tuple_type}. Error: {data}') else: - computeTask.apply_async( - (tuple_type, subtuple, model_type, fltask), + compute_task.apply_async( + (tuple_type, subtuple, fltask), queue=worker_queue) except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - return log_fail_subtuple(subtuple['key'], error_code, tuple_type) - - -def prepareTask(tuple_type, model_type): - try: - data_owner = get_hash(settings.LEDGER['signcert']) - except Exception as e: - logging.error(e, exc_info=True) - else: + data, st = log_fail_tuple(tuple_type, subtuple['key'], error_code) - subtuples, st = query_ledger( - fcn="queryFilter", - args=[f'{tuple_type}~worker~status', f'{data_owner},todo']) + if st != status.HTTP_201_CREATED: + logging.error(data, exc_info=True) - if st == status.HTTP_200_OK and subtuples is not None: - for subtuple in subtuples: - prepareTuple(subtuple, tuple_type, model_type) - - -@app.task(bind=True, ignore_result=True) -def prepareTrainingTask(self): - prepareTask('traintuple', 'inModels') - - -@app.task(ignore_result=True) -def prepareTestingTask(): - prepareTask('testtuple', 'model') + return data, st @app.task(bind=True, ignore_result=False) -def computeTask(self, tuple_type, subtuple, model_type, fltask): +def compute_task(self, tuple_type, subtuple, fltask): try: worker = self.request.hostname.split('@')[1] @@ -282,70 +261,56 @@ def computeTask(self, tuple_type, subtuple, model_type, fltask): result = {'worker': worker, 'queue': queue, 'fltask': fltask} - # Get materials try: - prepareMaterials(subtuple, model_type) + prepare_materials(subtuple, tuple_type) + res = do_task(subtuple, tuple_type) except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - log_fail_subtuple(subtuple['key'], error_code, tuple_type) - return result - logging.info(f'Prepare Task success {tuple_type}') + data, st = log_fail_tuple(tuple_type, subtuple['key'], error_code) + + if st != status.HTTP_201_CREATED: + logging.error(data, exc_info=True) - try: - res = doTask(subtuple, tuple_type) - except Exception as e: - error_code = compute_error_code(e) - logging.error(error_code, exc_info=True) - log_fail_subtuple(subtuple['key'], error_code, tuple_type) return result - else: - # Invoke ledger to log success - if tuple_type == 'traintuple': - invoke_fcn = 'logSuccessTrain' - invoke_args = [f'{subtuple["key"]}', - f'{res["end_model_file_hash"]}, {res["end_model_file"]}', - f'{res["global_perf"]}', - f'Train - {res["job_task_log"]};'] - - elif tuple_type == 'testtuple': - invoke_fcn = 'logSuccessTest' - invoke_args = [f'{subtuple["key"]}', - f'{res["global_perf"]}', - f'Test - {res["job_task_log"]};'] - - data, st = invoke_ledger(fcn=invoke_fcn, args=invoke_args, sync=True) - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - logging.error('Failed to invoke ledger on logSuccess') - logging.error(data) + data, st = log_success_tuple(tuple_type, subtuple['key'], res) + + if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): + logging.error('Failed to invoke ledger on logSuccess') + logging.error(data) return result -def prepareMaterials(subtuple, model_type): +def prepare_materials(subtuple, tuple_type): + # get subtuple components objective = get_objective(subtuple) algo_content = get_algo(subtuple) - if model_type == 'model': + if tuple_type == 'testtuple': model_content = get_model(subtuple) - elif model_type == 'inModels': + elif tuple_type == 'traintuple': models_content = get_models(subtuple) + else: + raise NotImplementedError() # create subtuple - subtuple_directory = build_subtuple_folders(subtuple) # do not put anything in pred folder + subtuple_directory = build_subtuple_folders(subtuple) put_opener(subtuple, subtuple_directory) put_data_sample(subtuple, subtuple_directory) put_metric(subtuple_directory, objective) put_algo(subtuple_directory, algo_content) - if model_type == 'model': # testtuple + if tuple_type == 'testtuple': put_model(subtuple, subtuple_directory, model_content) - elif model_type == 'inModels' and models_content: # traintuple + elif tuple_type == 'traintuple' and models_content: put_models(subtuple, subtuple_directory, models_content) + logging.info(f'Prepare materials for {tuple_type} task: success ') + -def doTask(subtuple, tuple_type): +def do_task(subtuple, tuple_type): subtuple_directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'subtuple', subtuple['key']) org_name = getattr(settings, 'ORG_NAME') @@ -357,136 +322,23 @@ def doTask(subtuple, tuple_type): fltask = subtuple['fltask'] flrank = int(subtuple['rank']) - # Computation - try: - # Job log - job_task_log = '' - - # Setup Docker Client - client = docker.from_env() - - # subtuple setup - model_path = path.join(subtuple_directory, 'model') - data_path = path.join(subtuple_directory, 'data') - - ########################################## - # RESOLVE SYMLINKS - # TO DO: - # - Verify that real paths are safe - # - Try to see if it's clean to do that - ########################################## - symlinks_volume = {} - for subfolder in os.listdir(data_path): - real_path = os.path.realpath(os.path.join(data_path, subfolder)) - symlinks_volume[real_path] = {'bind': f'{real_path}', 'mode': 'ro'} - - ########################################## - - pred_path = path.join(subtuple_directory, 'pred') - opener_file = path.join(subtuple_directory, 'opener/opener.py') - metrics_file = path.join(subtuple_directory, 'metrics/metrics.py') - volumes = {data_path: {'bind': '/sandbox/data', 'mode': 'ro'}, - pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, - metrics_file: {'bind': '/sandbox/metrics/__init__.py', 'mode': 'ro'}, - opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}} - - # compute algo task - algo_path = path.join(subtuple_directory) - algo_docker = f'algo_{tuple_type}'.lower() # tag must be lowercase for docker - algo_docker_name = f'{algo_docker}_{subtuple["key"]}' - model_volume = {model_path: {'bind': '/sandbox/model', 'mode': 'rw'}} - - if fltask is not None and flrank != -1: - remove_image = False - else: - remove_image = True - - # create the command option for algo - if tuple_type == 'traintuple': - algo_command = 'train' # main command - - # add list of inmodels - if subtuple['inModels'] is not None: - inmodels = [subtuple_model["traintupleKey"] for subtuple_model in subtuple['inModels']] - algo_command = f"{algo_command} {' '.join(inmodels)}" - - # add fltask rank for training - if flrank is not None: - algo_command = f"{algo_command} --rank {flrank}" - - elif tuple_type == 'testtuple': - algo_command = 'predict' # main command - - inmodels = subtuple['model']["traintupleKey"] - algo_command = f'{algo_command} {inmodels}' - - # local volume for fltask - if fltask is not None and tuple_type == 'traintuple': - flvolume = f'local-{fltask}-{org_name}' - if flrank == 0: - client.volumes.create(name=flvolume) - else: - client.volumes.get(volume_id=flvolume) - - model_volume[flvolume] = {'bind': '/sandbox/local', 'mode': 'rw'} - - job_task_log = compute_docker(client=client, - resources_manager=resources_manager, - dockerfile_path=algo_path, - image_name=algo_docker, - container_name=algo_docker_name, - volumes={**volumes, **model_volume, **symlinks_volume}, - command=algo_command, - remove_image=remove_image) - # save model in database - if tuple_type == 'traintuple': - from substrapp.models import Model - end_model_path = path.join(subtuple_directory, 'model/model') - end_model_file_hash = get_hash(end_model_path, subtuple['key']) - try: - instance = Model.objects.create(pkhash=end_model_file_hash, validated=True) - except Exception as e: - error_code = compute_error_code(e) - logging.error(error_code, exc_info=True) - return log_fail_subtuple(subtuple['key'], error_code, tuple_type) - - with open(end_model_path, 'rb') as f: - instance.file.save('model', f) - current_site = getattr(settings, "DEFAULT_DOMAIN") - end_model_file = f'{current_site}{reverse("substrapp:model-file", args=[end_model_file_hash])}' - - # compute metric task - metrics_path = path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/metrics') # comes with substrabac - metrics_docker = f'metrics_{tuple_type}'.lower() # tag must be lowercase for docker - metrics_docker_name = f'{metrics_docker}_{subtuple["key"]}' - compute_docker(client=client, - resources_manager=resources_manager, - dockerfile_path=metrics_path, - image_name=metrics_docker, - container_name=metrics_docker_name, - volumes={**volumes, **symlinks_volume}, - command=None, - remove_image=remove_image) - - # load performance - with open(path.join(pred_path, 'perf.json'), 'r') as perf_file: - perf = json.load(perf_file) - global_perf = perf['all'] + client = docker.from_env() + try: + result = _do_task( + client, + subtuple_directory, + tuple_type, + subtuple, + fltask, + flrank, + org_name + ) except Exception as e: # If an exception is thrown set flrank == -1 (we stop the fl training) if fltask is not None: flrank = -1 - raise e - else: - result = {'global_perf': global_perf, - 'job_task_log': job_task_log} - - if tuple_type == 'traintuple': - result['end_model_file_hash'] = end_model_file_hash - result['end_model_file'] = end_model_file - finally: # Clean subtuple materials remove_subtuple_materials(subtuple_directory) @@ -501,3 +353,126 @@ def doTask(subtuple, tuple_type): logging.error(f'Cannot remove local volume {flvolume}', exc_info=True) return result + + +def _do_task(client, subtuple_directory, tuple_type, subtuple, fltask, flrank, org_name): + # Job log + job_task_log = '' + + # subtuple setup + model_path = path.join(subtuple_directory, 'model') + data_path = path.join(subtuple_directory, 'data') + + ########################################## + # RESOLVE SYMLINKS + # TO DO: + # - Verify that real paths are safe + # - Try to see if it's clean to do that + ########################################## + symlinks_volume = {} + for subfolder in os.listdir(data_path): + real_path = os.path.realpath(os.path.join(data_path, subfolder)) + symlinks_volume[real_path] = {'bind': f'{real_path}', 'mode': 'ro'} + + ########################################## + + pred_path = path.join(subtuple_directory, 'pred') + opener_file = path.join(subtuple_directory, 'opener/opener.py') + metrics_file = path.join(subtuple_directory, 'metrics/metrics.py') + volumes = {data_path: {'bind': '/sandbox/data', 'mode': 'ro'}, + pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, + metrics_file: {'bind': '/sandbox/metrics/__init__.py', 'mode': 'ro'}, + opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}} + + # compute algo task + algo_path = path.join(subtuple_directory) + algo_docker = f'algo_{tuple_type}'.lower() # tag must be lowercase for docker + algo_docker_name = f'{algo_docker}_{subtuple["key"]}' + model_volume = {model_path: {'bind': '/sandbox/model', 'mode': 'rw'}} + + if fltask is not None and flrank != -1: + remove_image = False + else: + remove_image = True + + # create the command option for algo + if tuple_type == 'traintuple': + algo_command = 'train' # main command + + # add list of inmodels + if subtuple['inModels'] is not None: + inmodels = [subtuple_model["traintupleKey"] for subtuple_model in subtuple['inModels']] + algo_command = f"{algo_command} {' '.join(inmodels)}" + + # add fltask rank for training + if flrank is not None: + algo_command = f"{algo_command} --rank {flrank}" + + elif tuple_type == 'testtuple': + algo_command = 'predict' # main command + + inmodels = subtuple['model']["traintupleKey"] + algo_command = f'{algo_command} {inmodels}' + + # local volume for fltask + if fltask is not None and tuple_type == 'traintuple': + flvolume = f'local-{fltask}-{org_name}' + if flrank == 0: + client.volumes.create(name=flvolume) + else: + client.volumes.get(volume_id=flvolume) + + model_volume[flvolume] = {'bind': '/sandbox/local', 'mode': 'rw'} + + job_task_log = compute_docker( + client=client, + resources_manager=resources_manager, + dockerfile_path=algo_path, + image_name=algo_docker, + container_name=algo_docker_name, + volumes={**volumes, **model_volume, **symlinks_volume}, + command=algo_command, + remove_image=remove_image + ) + + # save model in database + if tuple_type == 'traintuple': + from substrapp.models import Model + end_model_path = path.join(subtuple_directory, 'model/model') + end_model_file_hash = get_hash(end_model_path, subtuple['key']) + instance = Model.objects.create(pkhash=end_model_file_hash, validated=True) + + with open(end_model_path, 'rb') as f: + instance.file.save('model', f) + current_site = getattr(settings, "DEFAULT_DOMAIN") + end_model_file = f'{current_site}{reverse("substrapp:model-file", args=[end_model_file_hash])}' + + # compute metric task + metrics_path = path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/metrics') # comes with substrabac + metrics_docker = f'metrics_{tuple_type}'.lower() # tag must be lowercase for docker + metrics_docker_name = f'{metrics_docker}_{subtuple["key"]}' + compute_docker( + client=client, + resources_manager=resources_manager, + dockerfile_path=metrics_path, + image_name=metrics_docker, + container_name=metrics_docker_name, + volumes={**volumes, **symlinks_volume}, + command=None, + remove_image=remove_image + ) + + # load performance + with open(path.join(pred_path, 'perf.json'), 'r') as perf_file: + perf = json.load(perf_file) + + global_perf = perf['all'] + + result = {'global_perf': global_perf, + 'job_task_log': job_task_log} + + if tuple_type == 'traintuple': + result['end_model_file_hash'] = end_model_file_hash + result['end_model_file'] = end_model_file + + return result diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 7426ce4eb..1a39d76d5 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -13,8 +13,8 @@ from substrapp.utils import compute_hash, get_computed_hash, get_remote_file, get_hash, create_directory from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, - put_model, put_models, put_algo, put_metric, put_data_sample, prepareTask, doTask, - computeTask) + put_model, put_models, put_algo, put_metric, put_data_sample, prepare_task, do_task, + compute_task) from .common import (get_sample_algo, get_sample_script, get_sample_zip_data_sample, get_sample_tar_data_sample, get_sample_model) @@ -28,6 +28,7 @@ # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) class TasksTests(APITestCase): def setUp(self): @@ -410,7 +411,7 @@ def test_build_subtuple_folders(self): self.assertTrue(5, nb_subfolders) - def test_prepareTasks(self): + def test_prepare_tasks(self): class FakeSettings(object): def __init__(self): @@ -424,7 +425,7 @@ def __init__(self): with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash, \ - mock.patch('substrapp.tasks.tasks.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.tasks.tasks.query_tuples') as mquery_tuples, \ mock.patch('substrapp.tasks.tasks.get_objective') as mget_objective, \ mock.patch('substrapp.tasks.tasks.get_algo') as mget_algo, \ mock.patch('substrapp.tasks.tasks.get_model') as mget_model, \ @@ -437,7 +438,7 @@ def __init__(self): msettings.return_value = FakeSettings() mget_hash.return_value = 'owkinhash' - mquery_ledger.return_value = subtuple, 200 + mquery_tuples.return_value = subtuple, 200 mget_objective.return_value = 'objective' mget_algo.return_value = 'algo', 'algo_hash' mget_model.return_value = 'model', 'model_hash' @@ -448,17 +449,17 @@ def __init__(self): mput_algo.return_value = 'algo' mput_model.return_value = 'model' - with mock.patch('substrapp.tasks.tasks.query_ledger') as mquery_ledger: - mquery_ledger.return_value = 'data', 404 - prepareTask('traintuple', 'inModels') + with mock.patch('substrapp.tasks.tasks.query_tuples') as mquery_tuples: + mquery_tuples.return_value = 'data', 404 + prepare_task('traintuple') - with mock.patch('substrapp.tasks.tasks.invoke_ledger') as minvoke_ledger, \ - mock.patch('substrapp.tasks.tasks.computeTask.apply_async') as mapply_async: - minvoke_ledger.return_value = 'data', 201 - mapply_async.return_value = 'doTask' - prepareTask('traintuple', 'inModels') + with mock.patch('substrapp.tasks.tasks.log_success_tuple') as mlog_success_tuple, \ + mock.patch('substrapp.tasks.tasks.compute_task.apply_async') as mapply_async: + mlog_success_tuple.return_value = 'data', 201 + mapply_async.return_value = 'do_task' + prepare_task('traintuple') - def test_doTask(self): + def test_do_task(self): class FakeSettings(object): def __init__(self): @@ -473,11 +474,9 @@ def __init__(self): subtuple_directory = build_subtuple_folders(subtuple) with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ - mock.patch('substrapp.tasks.tasks.getattr') as mgetattr, \ - mock.patch('substrapp.tasks.tasks.invoke_ledger') as minvoke_ledger: + mock.patch('substrapp.tasks.tasks.getattr') as mgetattr: msettings.return_value = FakeSettings() mgetattr.return_value = self.subtuple_path - minvoke_ledger.return_value = 'data', 200 for name in ['opener', 'metrics']: with open(os.path.join(subtuple_directory, f'{name}/{name}.py'), 'w') as f: @@ -492,9 +491,9 @@ def __init__(self): with mock.patch('substrapp.tasks.tasks.compute_docker') as mcompute_docker: mcompute_docker.return_value = 'DONE' - doTask(subtuple, 'traintuple') + do_task(subtuple, 'traintuple') - def test_computeTask(self): + def test_compute_task(self): class FakeSettings(object): def __init__(self): @@ -510,10 +509,10 @@ def __init__(self): with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ mock.patch('substrapp.tasks.tasks.getattr') as mgetattr, \ - mock.patch('substrapp.tasks.tasks.invoke_ledger') as minvoke_ledger: + mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple: msettings.return_value = FakeSettings() mgetattr.return_value = self.subtuple_path - minvoke_ledger.return_value = 'data', 200 + mlog_start_tuple.return_value = 'data', 200 for name in ['opener', 'metrics']: with open(os.path.join(subtuple_directory, f'{name}/{name}.py'), 'w') as f: @@ -527,11 +526,11 @@ def __init__(self): f.write("MODEL") with mock.patch('substrapp.tasks.tasks.compute_docker') as mcompute_docker, \ - mock.patch('substrapp.tasks.tasks.prepareMaterials') as mprepareMaterials, \ - mock.patch('substrapp.tasks.tasks.invoke_ledger') as minvoke_ledger: + mock.patch('substrapp.tasks.tasks.prepare_materials') as mprepare_materials, \ + mock.patch('substrapp.tasks.tasks.log_success_tuple') as mlog_success_tuple: mcompute_docker.return_value = 'DONE' - mprepareMaterials.return_value = 'DONE' - minvoke_ledger.return_value = 'data', 201 + mprepare_materials.return_value = 'DONE' + mlog_success_tuple.return_value = 'data', 201 - computeTask('traintuple', subtuple, 'inModels', None) + compute_task('traintuple', subtuple, None) From a9af0cb2733a1da1e92b2952d2e029c86b0d8837 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 5 Jun 2019 10:00:10 +0200 Subject: [PATCH 070/457] Fix multiple issues (prepare_tuple and test). --- docker/start.py | 2 +- substrabac/events/apps.py | 32 +++++++++++------------ substrabac/substrapp/ledger_utils.py | 18 ++++++------- substrabac/substrapp/tasks/tasks.py | 31 ++++++++++++---------- substrabac/substrapp/tests/tests_tasks.py | 14 +++++++--- 5 files changed, 53 insertions(+), 44 deletions(-) diff --git a/docker/start.py b/docker/start.py index c9217ad5d..28bafef29 100644 --- a/docker/start.py +++ b/docker/start.py @@ -117,7 +117,7 @@ def generate_docker_compose_file(conf, launch_settings): f'--master --processes {processes} --threads 2' else: django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.events.dev ' \ - f'python3 manage.py runserver 0.0.0.0:{port}' + f'python3 manage.py runserver --noreload 0.0.0.0:{port}' backend_global_env = [ f'ORG={org_name_stripped}', diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 14abb25d5..25b9c54c6 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -1,6 +1,5 @@ import asyncio import json -import logging import multiprocessing import os import contextlib @@ -38,24 +37,25 @@ def get_block_payload(block): 'extension']['events']['payload']) return payload -_edef on_tupleEvent(block): + +def on_tuple_event(block): payload = get_block_payload(block) worker_queue = f"{LEDGER['name']}.worker" - try: - data_owner = get_hash(LEDGER['signcert']) - except Exception as e: - logging.error(e, exc_info=True) - else: - if data_owner == payload['dataset']['worker']: - tuple_type = None - if 'inModels' in payload: - tuple_type = 'traintuple' - elif 'model' in payload: - tuple_type = 'testtuple' - - if tuple_type is not None: - prepare_tuple.apply_async((payload, tuple_type), queue=worker_queue) + data_owner = get_hash(LEDGER['signcert']) + + if data_owner == payload['dataset']['worker']: + tuple_type = None + if 'inModels' in payload: + tuple_type = 'traintuple' + elif 'model' in payload: + tuple_type = 'testtuple' + + if tuple_type is not None: + prepare_tuple.apply_async( + (payload, tuple_type), + task_id=payload['key'], + queue=worker_queue) def wait(): diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index f519089bc..5780549ca 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -1,5 +1,4 @@ import asyncio -import logging import json from rest_framework import status @@ -74,16 +73,17 @@ def query_ledger(fcn, args=None): data = {'message': response} - # TODO: get 409 from the chaincode - if 'message' in data and 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if data is not None: + # TODO: get 409 from the chaincode + if 'message' in data and 'tkey' in data['message']: + pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if len(pkhash) == 64: - st = status.HTTP_409_CONFLICT - data['pkhash'] = pkhash + if len(pkhash) == 64: + st = status.HTTP_409_CONFLICT + data['pkhash'] = pkhash - if 'permissions' in data and data['permissions'] != 'all': - raise Exception('Not Allowed') + if 'permissions' in data and data['permissions'] != 'all': + raise Exception('Not Allowed') return data, st diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index f5083396f..dde1a09ae 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -189,26 +189,25 @@ def remove_subtuple_materials(subtuple_directory): @app.task(bind=True, ignore_result=True) def prepare_training_task(self): - prepare_task('traintuple', 'inModels') + prepare_task('traintuple') @app.task(ignore_result=True) def prepare_testing_task(): - prepare_task('testtuple', 'model') + prepare_task('testtuple') def prepare_task(tuple_type): - try: - data_owner = get_hash(settings.LEDGER['signcert']) - except Exception as e: - logging.exception(e) - else: - - tuples, st = query_tuples(tuple_type, data_owner) + data_owner = get_hash(settings.LEDGER['signcert']) + worker_queue = f"{settings.LEDGER['name']}.worker" + tuples, st = query_tuples(tuple_type, data_owner) - if st == status.HTTP_200_OK and tuples is not None: - for subtuple in tuples: - prepare_tuple(subtuple, tuple_type) + if st == status.HTTP_200_OK and tuples is not None: + for subtuple in tuples: + prepare_tuple.apply_async( + (subtuple, tuple_type), + task_id=subtuple['key'], + queue=worker_queue) @app.task(ignore_result=False) @@ -231,8 +230,12 @@ def prepare_tuple(subtuple, tuple_type): data, st = log_start_tuple(tuple_type, subtuple['key']) if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - raise Exception( - f'Failed to invoke ledger on prepare_task {tuple_type}. Error: {data}') + # Do not log_fail_tuple in this case, because prepare_tuple task are not unique + # in case of multiple instances of substrabac running for the same organisation + # So prepare_tuple tasks are ignored if it cannot log_start_tuple + # TODO: find a way to handle this special case to avoid silent failure in other cases. + e = Exception(f'Failed to invoke ledger on prepare_task {tuple_type}. Error: {data}') + logging.exception(e) else: compute_task.apply_async( (tuple_type, subtuple, fltask), diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 1a39d76d5..4e77163fb 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -411,6 +411,12 @@ def test_build_subtuple_folders(self): self.assertTrue(5, nb_subfolders) + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) def test_prepare_tasks(self): class FakeSettings(object): @@ -449,13 +455,13 @@ def __init__(self): mput_algo.return_value = 'algo' mput_model.return_value = 'model' - with mock.patch('substrapp.tasks.tasks.query_tuples') as mquery_tuples: - mquery_tuples.return_value = 'data', 404 + with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple: + mlog_start_tuple.return_value = 'data', 404 prepare_task('traintuple') - with mock.patch('substrapp.tasks.tasks.log_success_tuple') as mlog_success_tuple, \ + with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple, \ mock.patch('substrapp.tasks.tasks.compute_task.apply_async') as mapply_async: - mlog_success_tuple.return_value = 'data', 201 + mlog_start_tuple.return_value = 'data', 201 mapply_async.return_value = 'do_task' prepare_task('traintuple') From 86b5bc15ce895ed69f2a35a447e5ad42b483039c Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 5 Jun 2019 10:32:17 +0200 Subject: [PATCH 071/457] Disable logging during tests and remove useless print. --- substrabac/substrabac/settings/test.py | 3 +++ substrabac/substrapp/tests/tests_query.py | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/substrabac/substrabac/settings/test.py b/substrabac/substrabac/settings/test.py index 5456b2ff0..7df04facc 100644 --- a/substrabac/substrabac/settings/test.py +++ b/substrabac/substrabac/settings/test.py @@ -2,3 +2,6 @@ from .deps.restframework import * # noqa from .deps.cors import * # noqa + +import logging +logging.disable(logging.CRITICAL) diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py index fcafd0277..143c5d5e9 100644 --- a/substrabac/substrapp/tests/tests_query.py +++ b/substrabac/substrapp/tests/tests_query.py @@ -232,7 +232,6 @@ def test_get_objective_metrics(self): extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } - print(self.objective_metrics) response = self.client.get( f'/objective/{objective.pkhash}/metrics/', **extra) @@ -1131,7 +1130,6 @@ def test_add_traintuple_ok(self): response = self.client.post(url, data, format='multipart', **extra) - print(response.json()) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) def test_add_traintuple_ko(self): From 7fffb87cc7c284c2a633df9c422a14560325d825 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 5 Jun 2019 10:40:42 +0200 Subject: [PATCH 072/457] Remove useless upload_to function in datasample because we use path. --- substrabac/substrapp/models/datasample.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/substrabac/substrapp/models/datasample.py b/substrabac/substrapp/models/datasample.py index 409deab06..41d794b14 100644 --- a/substrabac/substrapp/models/datasample.py +++ b/substrabac/substrapp/models/datasample.py @@ -3,10 +3,6 @@ from substrapp.utils import get_hash -def upload_to(instance, filename): - return 'datasamples/{0}/{1}'.format(instance.pk, filename) - - class DataSample(models.Model): """Storage Data table""" pkhash = models.CharField(primary_key=True, max_length=64, blank=True) From 83bd0f3896b44f3dbc28d3b84a02f49cb44d7d94 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 5 Jun 2019 12:12:42 +0200 Subject: [PATCH 073/457] Update query tests. --- substrabac/substrapp/tests/query/__init__.py | 0 .../substrapp/tests/query/tests_query_algo.py | 227 ++++ .../tests/query/tests_query_datamanager.py | 133 ++ .../tests/query/tests_query_datasample.py | 505 +++++++ .../tests/query/tests_query_objective.py | 250 ++++ .../tests/query/tests_query_tuples.py | 304 +++++ substrabac/substrapp/tests/tests_query.py | 1197 ----------------- 7 files changed, 1419 insertions(+), 1197 deletions(-) create mode 100644 substrabac/substrapp/tests/query/__init__.py create mode 100644 substrabac/substrapp/tests/query/tests_query_algo.py create mode 100644 substrabac/substrapp/tests/query/tests_query_datamanager.py create mode 100644 substrabac/substrapp/tests/query/tests_query_datasample.py create mode 100644 substrabac/substrapp/tests/query/tests_query_objective.py create mode 100644 substrabac/substrapp/tests/query/tests_query_tuples.py delete mode 100644 substrabac/substrapp/tests/tests_query.py diff --git a/substrabac/substrapp/tests/query/__init__.py b/substrabac/substrapp/tests/query/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substrabac/substrapp/tests/query/tests_query_algo.py new file mode 100644 index 000000000..ffd23bf08 --- /dev/null +++ b/substrabac/substrapp/tests/query/tests_query_algo.py @@ -0,0 +1,227 @@ +import os +import shutil +import tempfile + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.models import Objective, Algo +from substrapp.serializers import LedgerAlgoSerializer +from substrapp.utils import get_hash, compute_hash + +from ..common import get_sample_objective, get_sample_datamanager, \ + get_sample_algo + +MEDIA_ROOT = tempfile.mkdtemp() + + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) +class AlgoQueryTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.objective_description, self.objective_description_filename, \ + self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + + self.algo, self.algo_filename = get_sample_algo() + + self.data_description, self.data_description_filename, self.data_data_opener, \ + self.data_opener_filename = get_sample_datamanager() + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + def add_default_objective(self): + Objective.objects.create(description=self.objective_description, + metrics=self.objective_metrics) + + def get_default_algo_data(self): + expected_hash = get_hash(self.algo) + + data = { + 'file': self.algo, + 'description': self.data_description, # fake it + 'name': 'super top algo', + 'objective_key': get_hash(self.objective_description), + 'permissions': 'all' + } + + return expected_hash, data + + def test_add_algo_sync_ok(self): + self.add_default_objective() + pkhash, data = self.get_default_algo_data() + + url = reverse('substrapp:algo-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.algo.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'pkhash': pkhash}, status.HTTP_201_CREATED + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r['pkhash'], pkhash) + self.assertEqual(r['validated'], True) + self.assertEqual(r['description'], + f'http://testserver/media/algos/{r["pkhash"]}/{self.data_description_filename}') + self.assertEqual(r['file'], + f'http://testserver/media/algos/{r["pkhash"]}/{self.algo_filename}') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + @override_settings(LEDGER_SYNC_ENABLED=False) + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) + def test_add_algo_no_sync_ok(self): + self.add_default_objective() + pkhash, data = self.get_default_algo_data() + + url = reverse('substrapp:algo-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + with mock.patch('substrapp.serializers.ledger.algo.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = ({ + 'message': 'Algo added in local db waiting for validation.' + 'The substra network has been notified for adding this Algo' + }, status.HTTP_202_ACCEPTED) + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r['pkhash'], pkhash) + self.assertEqual(r['validated'], False) + self.assertEqual(r['description'], + f'http://testserver/media/algos/{r["pkhash"]}/{self.data_description_filename}') + self.assertEqual(r['file'], + f'http://testserver/media/algos/{r["pkhash"]}/{self.algo_filename}') + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + def test_add_algo_ko(self): + url = reverse('substrapp:algo-list') + + # non existing associated objective + data = { + 'file': self.algo, + 'description': self.data_description, + 'name': 'super top algo', + 'objective_key': 'non existing objectivexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + 'permissions': 'all' + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: + mcreate.return_value = { + 'message': 'Fail to add algo. Objective does not exist'}, status.HTTP_400_BAD_REQUEST + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertIn('does not exist', r['message']) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + Objective.objects.create(description=self.objective_description, + metrics=self.objective_metrics) + + # missing local storage field + data = { + 'name': 'super top algo', + 'objective_key': get_hash(self.objective_description), + 'permissions': 'all' + } + response = self.client.post(url, data, format='multipart', **extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # missing ledger field + data = { + 'file': self.algo, + 'description': self.data_description, + 'objective_key': get_hash(self.objective_description), + } + response = self.client.post(url, data, format='multipart', **extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_algo_no_version(self): + + self.add_default_objective() + + url = reverse('substrapp:algo-list') + + data = { + 'file': self.algo, + 'description': self.data_description, + 'name': 'super top algo', + 'objective_key': get_hash(self.objective_description), + 'permissions': 'all' + } + response = self.client.post(url, data, format='multipart') + r = response.json() + + self.assertEqual(r, {'detail': 'A version is required.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_add_algo_wrong_version(self): + + self.add_default_objective() + + url = reverse('substrapp:algo-list') + + data = { + 'file': self.algo, + 'description': self.data_description, + 'name': 'super top algo', + 'objective_key': get_hash(self.objective_description), + 'permissions': 'all' + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=-1.0', + } + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_get_algo_files(self): + algo = Algo.objects.create(file=self.algo) + with mock.patch( + 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = self.algo + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + response = self.client.get(f'/algo/{algo.pkhash}/file/', **extra) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(algo.pkhash, compute_hash(response.getvalue())) + # self.assertEqual(r, f'http://testserver/media/algos/{algo.pkhash}/{self.algo_filename}') + + def test_get_algo_files_no_version(self): + algo = Algo.objects.create(file=self.algo) + response = self.client.get(f'/algo/{algo.pkhash}/file/') + r = response.json() + self.assertEqual(r, {'detail': 'A version is required.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_get_algo_files_wrong_version(self): + algo = Algo.objects.create(file=self.algo) + extra = { + 'HTTP_ACCEPT': 'application/json;version=-1.0', + } + response = self.client.get(f'/algo/{algo.pkhash}/file/', **extra) + r = response.json() + self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) diff --git a/substrabac/substrapp/tests/query/tests_query_datamanager.py b/substrabac/substrapp/tests/query/tests_query_datamanager.py new file mode 100644 index 000000000..b245d6d02 --- /dev/null +++ b/substrabac/substrapp/tests/query/tests_query_datamanager.py @@ -0,0 +1,133 @@ +import os +import shutil +import tempfile + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + + +from substrapp.utils import get_hash + +from ..common import get_sample_datamanager + +MEDIA_ROOT = tempfile.mkdtemp() + + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) +class DataManagerQueryTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.data_description, self.data_description_filename, self.data_data_opener, \ + self.data_opener_filename = get_sample_datamanager() + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + def get_default_datamanager_data(self): + expected_hash = get_hash(self.data_data_opener) + data = { + 'name': 'slide opener', + 'type': 'images', + 'permissions': 'all', + 'objective_key': '', + 'description': self.data_description, + 'data_opener': self.data_data_opener + } + return expected_hash, data + + def test_add_datamanager_sync_ok(self): + + pkhash, data = self.get_default_datamanager_data() + + url = reverse('substrapp:data_manager-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.datamanager.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = ({'pkhash': pkhash}, status.HTTP_201_CREATED) + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r['pkhash'], pkhash) + self.assertEqual(r['validated'], True) + self.assertEqual(r['description'], + f'http://testserver/media/datamanagers/{r["pkhash"]}/{self.data_description_filename}') + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + @override_settings(LEDGER_SYNC_ENABLED=False) + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) + def test_add_datamanager_no_sync_ok(self): + + pkhash, data = self.get_default_datamanager_data() + + url = reverse('substrapp:data_manager-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.datamanager.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = ({ + 'message': 'DataManager added in local db waiting for validation.' + 'The substra network has been notified for adding this DataManager' + }, status.HTTP_202_ACCEPTED) + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r['pkhash'], pkhash) + self.assertEqual(r['validated'], False) + self.assertEqual(r['description'], + f'http://testserver/media/datamanagers/{r["pkhash"]}/{self.data_description_filename}') + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + def test_add_datamanager_ko(self): + data = {'name': 'toto'} + + url = reverse('substrapp:data_manager-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + response = self.client.post(url, data, format='multipart', **extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_datamanager_no_version(self): + + _, data = self.get_default_datamanager_data() + + url = reverse('substrapp:data_manager-list') + + response = self.client.post(url, data, format='multipart') + r = response.json() + + self.assertEqual(r, {'detail': 'A version is required.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_add_datamanager_wrong_version(self): + + _, data = self.get_default_datamanager_data() + + url = reverse('substrapp:data_manager-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=-1.0', + } + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substrabac/substrapp/tests/query/tests_query_datasample.py new file mode 100644 index 000000000..34bc473b2 --- /dev/null +++ b/substrabac/substrapp/tests/query/tests_query_datasample.py @@ -0,0 +1,505 @@ +import os +import shutil +import tempfile +import zipfile +from unittest.mock import MagicMock + +import mock +from django.core.files import File +from django.core.files.uploadedfile import InMemoryUploadedFile + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.models import DataManager, DataSample +from substrapp.serializers import LedgerDataSampleSerializer, DataSampleSerializer + +from substrapp.utils import get_hash, get_dir_hash +from substrapp.views import DataSampleViewSet + +from ..common import get_sample_datamanager, get_sample_zip_data_sample, get_sample_script, \ + get_sample_datamanager2, get_sample_tar_data_sample, get_sample_zip_data_sample_2 + +MEDIA_ROOT = tempfile.mkdtemp() + + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) +class DataSampleQueryTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.script, self.script_filename = get_sample_script() + self.data_file, self.data_file_filename = get_sample_zip_data_sample() + self.data_file_2, self.data_file_filename_2 = get_sample_zip_data_sample_2() + self.data_tar_file, self.data_tar_file_filename = get_sample_tar_data_sample() + + self.data_description, self.data_description_filename, self.data_data_opener, \ + self.data_opener_filename = get_sample_datamanager() + + self.data_description2, self.data_description_filename2, self.data_data_opener2, \ + self.data_opener_filename2 = get_sample_datamanager2() + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + def add_default_data_manager(self): + DataManager.objects.create(name='slide opener', + description=self.data_description, + data_opener=self.data_data_opener) + + def get_default_datasample_data(self): + expected_hash = get_dir_hash(self.data_file.file) + self.data_file.file.seek(0) + data = { + 'file': self.data_file, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + + return expected_hash, data + + def test_add_data_sample_sync_ok(self): + + self.add_default_data_manager() + pkhash, data = self.get_default_datasample_data() + + url = reverse('substrapp:data_sample-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = ({ + 'pkhash': pkhash, + 'validated': True + }, status.HTTP_201_CREATED) + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r[0]['pkhash'], pkhash) + self.assertEqual(r[0]['validated'], True) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + def test_bulk_add_data_sample_sync_ok(self): + + self.add_default_data_manager() + + url = reverse('substrapp:data_sample-list') + + file_mock = MagicMock(spec=InMemoryUploadedFile) + file_mock2 = MagicMock(spec=InMemoryUploadedFile) + file_mock.name = 'foo.zip' + file_mock2.name = 'bar.zip' + file_mock.read = MagicMock(return_value=self.data_file.read()) + file_mock2.read = MagicMock(return_value=self.data_file_2.read()) + + data = { + file_mock.name: file_mock, + file_mock2.name: file_mock2, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.datasample.DataSampleSerializer.get_validators') as mget_validators, \ + mock.patch('substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: + mget_validators.return_value = [] + self.data_file.seek(0) + self.data_file_2.seek(0) + ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': True} + minvoke_ledger.return_value = ledger_data, status.HTTP_201_CREATED + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(len(r), 2) + self.assertEqual(r[0]['pkhash'], get_dir_hash(file_mock)) + self.assertTrue(r[0]['path'].endswith(f'/datasamples/{get_dir_hash(file_mock)}')) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + @override_settings(LEDGER_SYNC_ENABLED=False) + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) + def test_add_data_sample_no_sync_ok(self): + self.add_default_data_manager() + pkhash, data = self.get_default_datasample_data() + + url = reverse('substrapp:data_sample-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = ({ + 'message': 'Data added in local db waiting for validation.' + 'The substra network has been notified for adding this Data' + }, status.HTTP_202_ACCEPTED) + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r[0]['pkhash'], pkhash) + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + def test_add_data_sample_ko(self): + url = reverse('substrapp:data_sample-list') + + # missing datamanager + data = {'data_manager_keys': ['toto']} + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual( + r['message'], + "One or more datamanager keys provided do not exist in local substrabac database. " + "Please create them before. DataManager keys: ['toto']") + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + self.add_default_data_manager() + + # missing local storage field + data = {'data_manager_keys': [get_hash(self.data_description)], + 'test_only': True, } + response = self.client.post(url, data, format='multipart', **extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # missing ledger field + data = {'data_manager_keys': [get_hash(self.data_description)], + 'file': self.script, } + response = self.client.post(url, data, format='multipart', **extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_data_sample_ko_already_exists(self): + url = reverse('substrapp:data_sample-list') + + self.add_default_data_manager() + + file_mock = MagicMock(spec=InMemoryUploadedFile) + file_mock.name = 'foo.zip' + file_mock.read = MagicMock(return_value=self.data_file.file.read()) + file_mock.open = MagicMock(return_value=file_mock) + + d = DataSample(path=file_mock) + # trigger pre save + d.save() + + data = { + 'file': file_mock, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile: + mis_zipfile.return_value = True + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r['message'], + [[{'pkhash': ['data sample with this pkhash already exists.']}]]) + self.assertEqual(response.status_code, status.HTTP_409_CONFLICT) + + def test_add_data_sample_ko_not_a_zip(self): + url = reverse('substrapp:data_sample-list') + + self.add_default_data_manager() + + file_mock = MagicMock(spec=File) + file_mock.name = 'foo.zip' + file_mock.read = MagicMock(return_value=b'foo') + + data = { + 'file': file_mock, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r['message'], 'Archive must be zip or tar.*') + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_data_sample_ko_408(self): + url = reverse('substrapp:data_sample-list') + + self.add_default_data_manager() + + file_mock = MagicMock(spec=InMemoryUploadedFile) + file_mock.name = 'foo.zip' + file_mock.read = MagicMock(return_value=self.data_file.file.read()) + file_mock.open = MagicMock(return_value=file_mock) + + data = { + 'file': file_mock, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + mcreate.return_value = {'pkhash': get_hash(file_mock), 'validated': False}, status.HTTP_408_REQUEST_TIMEOUT + mis_zipfile.return_value = True + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r['message'], {'pkhash': [get_dir_hash(file_mock)], 'validated': False}) + self.assertEqual(response.status_code, status.HTTP_408_REQUEST_TIMEOUT) + + def test_bulk_add_data_sample_ko_408(self): + + self.add_default_data_manager() + + url = reverse('substrapp:data_sample-list') + + file_mock = MagicMock(spec=InMemoryUploadedFile) + file_mock2 = MagicMock(spec=InMemoryUploadedFile) + file_mock.name = 'foo.zip' + file_mock2.name = 'bar.zip' + file_mock.read = MagicMock(return_value=self.data_file.read()) + file_mock2.read = MagicMock(return_value=self.data_file_2.read()) + + data = { + file_mock.name: file_mock, + file_mock2.name: file_mock2, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.datasample.DataSampleSerializer.get_validators') as mget_validators, \ + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + mget_validators.return_value = [] + self.data_file.seek(0) + self.data_tar_file.seek(0) + ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} + mcreate.return_value = ledger_data, status.HTTP_408_REQUEST_TIMEOUT + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r['message']['validated'], False) + self.assertEqual(DataSample.objects.count(), 2) + self.assertEqual(response.status_code, status.HTTP_408_REQUEST_TIMEOUT) + + def test_bulk_add_data_sample_ko_same_pkhash(self): + + self.add_default_data_manager() + + url = reverse('substrapp:data_sample-list') + + file_mock = MagicMock(spec=InMemoryUploadedFile) + file_mock2 = MagicMock(spec=InMemoryUploadedFile) + file_mock.name = 'foo.zip' + file_mock2.name = 'bar.tar.gz' + file_mock.read = MagicMock(return_value=self.data_file.read()) + file_mock2.read = MagicMock(return_value=self.data_tar_file.read()) + + data = { + file_mock.name: file_mock, + file_mock2.name: file_mock2, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.datasample.DataSampleSerializer.get_validators') as mget_validators, \ + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + mget_validators.return_value = [] + self.data_file.seek(0) + self.data_tar_file.seek(0) + ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} + mcreate.return_value = ledger_data, status.HTTP_408_REQUEST_TIMEOUT + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(DataSample.objects.count(), 0) + self.assertEqual( + r['message'], + f'Your data sample archives contain same files leading to same pkhash, ' + f'please review the content of your achives. ' + f'Archives {file_mock2.name} and {file_mock.name} are the same') + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_data_sample_ko_400(self): + url = reverse('substrapp:data_sample-list') + + self.add_default_data_manager() + + file_mock = MagicMock(spec=InMemoryUploadedFile) + file_mock.name = 'foo.zip' + file_mock.read = MagicMock(return_value=self.data_file.file.read()) + + data = { + 'file': file_mock, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + mcreate.return_value = 'Failed', status.HTTP_400_BAD_REQUEST + mis_zipfile.return_value = True + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r['message'], 'Failed') + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_data_sample_ko_serializer_invalid(self): + url = reverse('substrapp:data_sample-list') + + self.add_default_data_manager() + + file_mock = MagicMock(spec=InMemoryUploadedFile) + file_mock.name = 'foo.zip' + file_mock.read = MagicMock(return_value=self.data_file.read()) + + data = { + 'file': file_mock, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ + mock.patch.object(DataSampleViewSet, 'get_serializer') as mget_serializer: + mocked_serializer = MagicMock(DataSampleSerializer) + mocked_serializer.is_valid.return_value = True + mocked_serializer.save.side_effect = Exception('Failed') + mget_serializer.return_value = mocked_serializer + + mis_zipfile.return_value = True + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r['message'], "Failed") + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_data_sample_ko_ledger_invalid(self): + url = reverse('substrapp:data_sample-list') + + self.add_default_data_manager() + + file_mock = MagicMock(spec=InMemoryUploadedFile) + file_mock.name = 'foo.zip' + file_mock.read = MagicMock(return_value=self.data_file.file.read()) + + data = { + 'file': file_mock, + 'data_manager_keys': [get_hash(self.data_data_opener)], + 'test_only': True, + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ + mock.patch('substrapp.views.datasample.LedgerDataSampleSerializer', + spec=True) as mLedgerDataSampleSerializer: + mocked_LedgerDataSampleSerializer = MagicMock() + mocked_LedgerDataSampleSerializer.is_valid.return_value = False + mocked_LedgerDataSampleSerializer.errors = 'Failed' + mLedgerDataSampleSerializer.return_value = mocked_LedgerDataSampleSerializer + + mis_zipfile.return_value = True + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r['message'], "[ErrorDetail(string='Failed', code='invalid')]") + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_data_sample_no_version(self): + + self.add_default_data_manager() + + url = reverse('substrapp:data_sample-list') + + data = { + 'file': self.data_file, + 'data_manager_keys': [get_hash(self.data_description)], + 'test_only': True, + } + response = self.client.post(url, data, format='multipart') + r = response.json() + + self.assertEqual(r, {'detail': 'A version is required.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_add_data_sample_wrong_version(self): + + self.add_default_data_manager() + + url = reverse('substrapp:data_sample-list') + + data = { + 'file': self.script, + 'data_manager_keys': ['XXXX'], + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=-1.0', + } + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_bulk_update_data(self): + + # add associated data opener + datamanager = DataManager.objects.create(name='slide opener', + description=self.data_description, + data_opener=self.data_data_opener) + datamanager2 = DataManager.objects.create(name='slide opener 2', + description=self.data_description2, + data_opener=self.data_data_opener2) + + d = DataSample(path=self.data_file) + # trigger pre save + d.save() + + url = reverse('substrapp:data_sample-bulk-update') + + data = { + 'data_manager_keys': [datamanager.pkhash, datamanager2.pkhash], + 'data_sample_keys': [d.pkhash], + } + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch( + 'substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'keys': [ + d.pkhash]}, status.HTTP_200_OK + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r['keys'], [d.pkhash]) + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/substrabac/substrapp/tests/query/tests_query_objective.py b/substrabac/substrapp/tests/query/tests_query_objective.py new file mode 100644 index 000000000..2cbf8e1e6 --- /dev/null +++ b/substrabac/substrapp/tests/query/tests_query_objective.py @@ -0,0 +1,250 @@ +import os +import shutil +import tempfile + +import mock + + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.models import Objective, DataManager +from substrapp.utils import get_hash, compute_hash + +from ..common import get_sample_objective, get_sample_datamanager, \ + get_temporary_text_file + +MEDIA_ROOT = tempfile.mkdtemp() + + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) +class ObjectiveQueryTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.objective_description, self.objective_description_filename, \ + self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + + self.data_description, self.data_description_filename, self.data_data_opener, \ + self.data_opener_filename = get_sample_datamanager() + + self.test_data_sample_keys = [ + '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379', + '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389'] + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + def add_default_data_manager(self): + DataManager.objects.create(name='slide opener', + description=self.data_description, + data_opener=self.data_data_opener) + + def get_default_objective_data(self): + expected_hash = get_hash(self.objective_description) + data = { + 'name': 'tough objective', + 'test_data_manager_key': get_hash(self.data_data_opener), + 'test_data_sample_keys': self.test_data_sample_keys, + 'description': self.objective_description, + 'metrics': self.objective_metrics, + 'permissions': 'all', + 'metrics_name': 'accuracy' + } + return expected_hash, data + + def test_add_objective_sync_ok(self): + self.add_default_data_manager() + pkhash, data = self.get_default_objective_data() + + url = reverse('substrapp:objective-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.objective.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'pkhash': pkhash}, status.HTTP_201_CREATED + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r['pkhash'], pkhash) + self.assertEqual(r['validated'], True) + self.assertEqual(r['description'], + f'http://testserver/media/objectives/{r["pkhash"]}/{self.objective_description_filename}') + self.assertEqual(r['metrics'], + f'http://testserver/media/objectives/{r["pkhash"]}/{self.objective_metrics_filename}') + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + @override_settings(LEDGER_SYNC_ENABLED=False) + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) + def test_add_objective_no_sync_ok(self): + self.add_default_data_manager() + pkhash, data = self.get_default_objective_data() + + url = reverse('substrapp:objective-list') + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + with mock.patch('substrapp.serializers.ledger.objective.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = ({ + 'message': 'Objective added in local db waiting for validation.' + 'The substra network has been notified for adding this Objective' + }, status.HTTP_202_ACCEPTED) + response = self.client.post(url, data, format='multipart', **extra) + + r = response.json() + + self.assertEqual(r['pkhash'], pkhash) + self.assertEqual(r['validated'], False) + self.assertEqual(r['description'], + f'http://testserver/media/objectives/{r["pkhash"]}/{self.objective_description_filename}') + self.assertEqual(r['metrics'], + f'http://testserver/media/objectives/{r["pkhash"]}/{self.objective_metrics_filename}') + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + def test_add_objective_conflict(self): + self.add_default_data_manager() + + pkhash, data = self.get_default_objective_data() + + url = reverse('substrapp:objective-list') + + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.objective.util.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'pkhash': pkhash}, status.HTTP_201_CREATED + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r['pkhash'], pkhash) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + # XXX reload data as the previous call to post change it + _, data = self.get_default_objective_data() + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(response.status_code, status.HTTP_409_CONFLICT) + self.assertEqual(r['pkhash'], pkhash) + + def test_add_objective_ko(self): + url = reverse('substrapp:objective-list') + + data = {'name': 'empty objective'} + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + response = self.client.post(url, data, format='multipart', **extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + data = {'metrics': self.objective_metrics, + 'description': self.objective_description} + response = self.client.post(url, data, format='multipart', **extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_objective_no_version(self): + url = reverse('substrapp:objective-list') + + description_content = 'My Super top objective' + metrics_content = 'def metrics():\n\tpass' + + description = get_temporary_text_file(description_content, + 'description.md') + metrics = get_temporary_text_file(metrics_content, 'metrics.py') + + data = { + 'name': 'tough objective', + 'test_data_sample_keys': self.test_data_sample_keys, + 'description': description, + 'metrics': metrics, + } + + response = self.client.post(url, data, format='multipart') + r = response.json() + + self.assertEqual(r, {'detail': 'A version is required.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_add_objective_wrong_version(self): + url = reverse('substrapp:objective-list') + + description_content = 'My Super top objective' + metrics_content = 'def metrics():\n\tpass' + + description = get_temporary_text_file(description_content, + 'description.md') + metrics = get_temporary_text_file(metrics_content, 'metrics.py') + + data = { + 'name': 'tough objective', + 'test_data_sample_keys': self.test_data_sample_keys, + 'description': description, + 'metrics': metrics, + } + + extra = { + 'HTTP_ACCEPT': 'application/json;version=-1.0', + } + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + + self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_get_objective_metrics(self): + objective = Objective.objects.create( + description=self.objective_description, + metrics=self.objective_metrics) + + with mock.patch( + 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = self.objective_metrics + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + response = self.client.get( + f'/objective/{objective.pkhash}/metrics/', **extra) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertNotEqual(objective.pkhash, + compute_hash(response.getvalue())) + self.assertEqual(self.objective_metrics_filename, + response.filename) + + def test_get_objective_metrics_no_version(self): + objective = Objective.objects.create( + description=self.objective_description, + metrics=self.objective_metrics) + response = self.client.get(f'/objective/{objective.pkhash}/metrics/') + r = response.json() + self.assertEqual(r, {'detail': 'A version is required.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_get_objective_metrics_wrong_version(self): + objective = Objective.objects.create( + description=self.objective_description, + metrics=self.objective_metrics) + extra = { + 'HTTP_ACCEPT': 'application/json;version=-1.0', + } + response = self.client.get(f'/objective/{objective.pkhash}/metrics/', + **extra) + r = response.json() + self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) diff --git a/substrabac/substrapp/tests/query/tests_query_tuples.py b/substrabac/substrapp/tests/query/tests_query_tuples.py new file mode 100644 index 000000000..2486d7268 --- /dev/null +++ b/substrabac/substrapp/tests/query/tests_query_tuples.py @@ -0,0 +1,304 @@ +import os +import shutil +import tempfile + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.models import Objective +from substrapp.utils import get_hash + +from ..common import get_sample_objective + +MEDIA_ROOT = tempfile.mkdtemp() + + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) +class TraintupleQueryTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.objective_description, self.objective_description_filename, \ + self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + + self.train_data_sample_keys = ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'] + self.fake_key = '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088' + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + def test_add_traintuple_sync_ok(self): + # Add associated objective + description, _, metrics, _ = get_sample_objective() + Objective.objects.create(description=description, + metrics=metrics) + # post data + url = reverse('substrapp:traintuple-list') + + data = { + 'train_data_sample_keys': self.train_data_sample_keys, + 'algo_key': self.fake_key, + 'data_manager_key': self.fake_key, + 'objective_key': self.fake_key, + 'rank': -1, + 'FLtask_key': self.fake_key, + 'in_models_keys': [self.fake_key]} + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.traintuple.util.invoke_ledger') as minvoke_ledger, \ + mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: + + raw_pkhash = 'traintuple_pkhash'.encode('utf-8').hex() + mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) + minvoke_ledger.return_value = ({'pkhash': raw_pkhash}, status.HTTP_201_CREATED) + + response = self.client.post(url, data, format='multipart', **extra) + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + @override_settings(LEDGER_SYNC_ENABLED=False) + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) + def test_add_traintuple_no_sync_ok(self): + # Add associated objective + description, _, metrics, _ = get_sample_objective() + Objective.objects.create(description=description, + metrics=metrics) + # post data + url = reverse('substrapp:traintuple-list') + + data = { + 'train_data_sample_keys': self.train_data_sample_keys, + 'algo_key': self.fake_key, + 'data_manager_key': self.fake_key, + 'objective_key': self.fake_key, + 'rank': -1, + 'FLtask_key': self.fake_key, + 'in_models_keys': [self.fake_key]} + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.traintuple.util.invoke_ledger') as minvoke_ledger, \ + mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: + + raw_pkhash = 'traintuple_pkhash'.encode('utf-8').hex() + mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) + minvoke_ledger.return_value = None + + response = self.client.post(url, data, format='multipart', **extra) + + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + def test_add_traintuple_ko(self): + url = reverse('substrapp:traintuple-list') + + data = { + 'train_data_sample_keys': self.train_data_sample_keys, + 'model_key': self.fake_key + } + + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertIn('This field may not be null.', r['algo_key']) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + Objective.objects.create(description=self.objective_description, + metrics=self.objective_metrics) + data = {'objective': get_hash(self.objective_description)} + response = self.client.post(url, data, format='multipart', **extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_traintuple_no_version(self): + # Add associated objective + description, _, metrics, _ = get_sample_objective() + Objective.objects.create(description=description, + metrics=metrics) + # post data + url = reverse('substrapp:traintuple-list') + + data = { + 'train_data_sample_keys': self.train_data_sample_keys, + 'datamanager_key': self.fake_key, + 'model_key': self.fake_key, + 'algo_key': self.fake_key} + + response = self.client.post(url, data, format='multipart') + r = response.json() + self.assertEqual(r, {'detail': 'A version is required.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_add_traintuple_wrong_version(self): + # Add associated objective + description, _, metrics, _ = get_sample_objective() + Objective.objects.create(description=description, + metrics=metrics) + # post data + url = reverse('substrapp:traintuple-list') + + data = { + 'train_data_sample_keys': self.train_data_sample_keys, + 'datamanager_key': self.fake_key, + 'model_key': self.fake_key, + 'algo_key': self.fake_key} + extra = { + 'HTTP_ACCEPT': 'application/json;version=-1.0', + } + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER_SYNC_ENABLED=True) +class TesttupleQueryTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.objective_description, self.objective_description_filename, \ + self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + + self.test_data_sample_keys = ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'] + self.fake_key = '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088' + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + def test_add_testtuple_sync_ok(self): + # Add associated objective + description, _, metrics, _ = get_sample_objective() + Objective.objects.create(description=description, + metrics=metrics) + # post data + url = reverse('substrapp:testtuple-list') + + data = { + 'test_data_sample_keys': self.test_data_sample_keys, + 'traintuple_key': self.fake_key, + 'data_manager_key': self.fake_key} + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.testtuple.util.invoke_ledger') as minvoke_ledger, \ + mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: + + raw_pkhash = 'testtuple_pkhash'.encode('utf-8').hex() + mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) + minvoke_ledger.return_value = ({'pkhash': raw_pkhash}, status.HTTP_201_CREATED) + + response = self.client.post(url, data, format='multipart', **extra) + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + @override_settings(LEDGER_SYNC_ENABLED=False) + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) + def test_add_testtuple_no_sync_ok(self): + # Add associated objective + description, _, metrics, _ = get_sample_objective() + Objective.objects.create(description=description, + metrics=metrics) + # post data + url = reverse('substrapp:testtuple-list') + + data = { + 'test_data_sample_keys': self.test_data_sample_keys, + 'traintuple_key': self.fake_key, + 'data_manager_key': self.fake_key} + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + with mock.patch('substrapp.serializers.ledger.testtuple.util.invoke_ledger') as minvoke_ledger, \ + mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: + + raw_pkhash = 'testtuple_pkhash'.encode('utf-8').hex() + mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) + minvoke_ledger.return_value = None + + response = self.client.post(url, data, format='multipart', **extra) + + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + def test_add_testtuple_ko(self): + url = reverse('substrapp:testtuple-list') + + data = { + 'test_data_sample_keys': self.test_data_sample_keys, + } + + extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0', + } + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertIn('This field may not be null.', r['traintuple_key']) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_add_testtuple_no_version(self): + # Add associated objective + description, _, metrics, _ = get_sample_objective() + Objective.objects.create(description=description, + metrics=metrics) + # post data + url = reverse('substrapp:testtuple-list') + + data = { + 'test_data_sample_keys': self.test_data_sample_keys, + 'traintuple_key': self.fake_key, + 'data_manager_key': self.fake_key} + + response = self.client.post(url, data, format='multipart') + r = response.json() + self.assertEqual(r, {'detail': 'A version is required.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) + + def test_add_testtuple_wrong_version(self): + # Add associated objective + description, _, metrics, _ = get_sample_objective() + Objective.objects.create(description=description, + metrics=metrics) + # post data + url = reverse('substrapp:testtuple-list') + + data = { + 'test_data_sample_keys': self.test_data_sample_keys, + 'traintuple_key': self.fake_key, + 'data_manager_key': self.fake_key} + + extra = { + 'HTTP_ACCEPT': 'application/json;version=-1.0', + } + + response = self.client.post(url, data, format='multipart', **extra) + r = response.json() + self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) + self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) diff --git a/substrabac/substrapp/tests/tests_query.py b/substrabac/substrapp/tests/tests_query.py deleted file mode 100644 index 143c5d5e9..000000000 --- a/substrabac/substrapp/tests/tests_query.py +++ /dev/null @@ -1,1197 +0,0 @@ -import os -import shutil -import tempfile -import zipfile -from unittest.mock import MagicMock - -import mock -from django.core.files import File -from django.core.files.uploadedfile import InMemoryUploadedFile - -from django.urls import reverse -from django.test import override_settings - -from rest_framework import status -from rest_framework.test import APITestCase - -from substrapp.models import Objective, DataManager, Algo, DataSample -from substrapp.serializers import LedgerObjectiveSerializer, \ - LedgerDataManagerSerializer, LedgerAlgoSerializer, \ - LedgerDataSampleSerializer, LedgerTrainTupleSerializer, DataSampleSerializer -from substrapp.utils import get_hash, compute_hash, get_dir_hash -from substrapp.views import DataSampleViewSet - -from .common import get_sample_objective, get_sample_datamanager, \ - get_sample_zip_data_sample, get_sample_script, \ - get_temporary_text_file, get_sample_datamanager2, get_sample_algo, \ - get_sample_tar_data_sample, get_sample_zip_data_sample_2 - -MEDIA_ROOT = tempfile.mkdtemp() - - -# APITestCase - -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER_SYNC_ENABLED=True) -class ObjectiveQueryTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.objective_description, self.objective_description_filename, \ - self.objective_metrics, self.objective_metrics_filename = get_sample_objective() - - self.data_description, self.data_description_filename, self.data_data_opener, \ - self.data_opener_filename = get_sample_datamanager() - - self.test_data_sample_keys = [ - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379', - '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b389'] - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - def add_default_data_manager(self): - DataManager.objects.create(name='slide opener', - description=self.data_description, - data_opener=self.data_data_opener) - - def get_default_objective_data(self): - # XXX reload fixtures as it is an opened buffer and a post will - # modify the objects - desc, _, metrics, _ = get_sample_objective() - - expected_hash = get_hash(self.objective_description) - data = { - 'name': 'tough objective', - 'test_data_manager_key': get_hash(self.data_data_opener), - 'test_data_sample_keys': self.test_data_sample_keys, - 'description': desc, - 'metrics': metrics, - 'permissions': 'all', - 'metrics_name': 'accuracy' - } - return expected_hash, data - - def test_add_objective_sync_ok(self): - self.add_default_data_manager() - - pkhash, data = self.get_default_objective_data() - - url = reverse('substrapp:objective-list') - - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(LedgerObjectiveSerializer, 'create') as mcreate: - mcreate.return_value = {'pkhash': pkhash}, status.HTTP_201_CREATED - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(r['pkhash'], pkhash) - self.assertEqual(r['validated'], False) - self.assertEqual(r['description'], - f'http://testserver/media/objectives/{r["pkhash"]}/{self.objective_description_filename}') - self.assertEqual(r['metrics'], - f'http://testserver/media/objectives/{r["pkhash"]}/{self.objective_metrics_filename}') - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - def test_add_objective_conflict(self): - self.add_default_data_manager() - - pkhash, data = self.get_default_objective_data() - - url = reverse('substrapp:objective-list') - - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(LedgerObjectiveSerializer, 'create') as mcreate: - mcreate.return_value = {'pkhash': pkhash}, status.HTTP_201_CREATED - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(r['pkhash'], pkhash) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - # XXX reload data as the previous call to post change it - _, data = self.get_default_objective_data() - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(response.status_code, status.HTTP_409_CONFLICT) - self.assertEqual(r['pkhash'], pkhash) - - def test_add_objective_no_sync_ok(self): - # add associated data opener - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - url = reverse('substrapp:objective-list') - - data = { - 'name': 'tough objective', - 'test_data_manager_key': get_hash(self.data_data_opener), - 'test_data_sample_keys': self.test_data_sample_keys, - 'description': self.objective_description, - 'metrics': self.objective_metrics, - 'permissions': 'all', - 'metrics_name': 'accuracy' - } - - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - with mock.patch.object(LedgerObjectiveSerializer, 'create') as mcreate: - mcreate.return_value = ({ - 'message': 'Objective added in local db waiting for validation.' - 'The substra network has been notified for adding this Objective' - }, status.HTTP_202_ACCEPTED) - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - def test_add_objective_ko(self): - url = reverse('substrapp:objective-list') - - data = {'name': 'empty objective'} - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - data = {'metrics': self.objective_metrics, - 'description': self.objective_description} - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_objective_no_version(self): - url = reverse('substrapp:objective-list') - - description_content = 'My Super top objective' - metrics_content = 'def metrics():\n\tpass' - - description = get_temporary_text_file(description_content, - 'description.md') - metrics = get_temporary_text_file(metrics_content, 'metrics.py') - - data = { - 'name': 'tough objective', - 'test_data_sample_keys': self.test_data_sample_keys, - 'description': description, - 'metrics': metrics, - } - - response = self.client.post(url, data, format='multipart') - r = response.json() - - self.assertEqual(r, {'detail': 'A version is required.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_add_objective_wrong_version(self): - url = reverse('substrapp:objective-list') - - description_content = 'My Super top objective' - metrics_content = 'def metrics():\n\tpass' - - description = get_temporary_text_file(description_content, - 'description.md') - metrics = get_temporary_text_file(metrics_content, 'metrics.py') - - data = { - 'name': 'tough objective', - 'test_data_sample_keys': self.test_data_sample_keys, - 'description': description, - 'metrics': metrics, - } - - extra = { - 'HTTP_ACCEPT': 'application/json;version=-1.0', - } - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_get_objective_metrics(self): - objective = Objective.objects.create( - description=self.objective_description, - metrics=self.objective_metrics) - with mock.patch( - 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.return_value = self.objective_metrics - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - response = self.client.get( - f'/objective/{objective.pkhash}/metrics/', **extra) - - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertNotEqual(objective.pkhash, - compute_hash(response.getvalue())) - self.assertEqual(self.objective_metrics_filename, - response.filename) - - def test_get_objective_metrics_no_version(self): - objective = Objective.objects.create( - description=self.objective_description, - metrics=self.objective_metrics) - response = self.client.get(f'/objective/{objective.pkhash}/metrics/') - r = response.json() - self.assertEqual(r, {'detail': 'A version is required.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_get_objective_metrics_wrong_version(self): - objective = Objective.objects.create( - description=self.objective_description, - metrics=self.objective_metrics) - extra = { - 'HTTP_ACCEPT': 'application/json;version=-1.0', - } - response = self.client.get(f'/objective/{objective.pkhash}/metrics/', - **extra) - r = response.json() - self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER_SYNC_ENABLED=True) -class DataManagerQueryTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.data_description, self.data_description_filename, self.data_data_opener, \ - self.data_opener_filename = get_sample_datamanager() - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - def test_add_datamanager_sync_ok(self): - url = reverse('substrapp:data_manager-list') - - data = { - 'name': 'slide opener', - 'type': 'images', - 'permissions': 'all', - 'objective_key': '', - 'description': self.data_description, - 'data_opener': self.data_data_opener - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(LedgerDataManagerSerializer, 'create') as mcreate: - mcreate.return_value = ({ - 'pkhash': 'da920c804c4724f1ce7bd0484edcf4aafa209d5bd54e2e89972c087a487cbe02' - }, status.HTTP_201_CREATED) - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(r['pkhash'], get_hash(self.data_data_opener)) - self.assertEqual(r['description'], - f'http://testserver/media/datamanagers/{r["pkhash"]}/{self.data_description_filename}') - - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - def test_add_datamanager_no_sync_ok(self): - url = reverse('substrapp:data_manager-list') - data = { - 'name': 'slide opener', - 'type': 'images', - 'permissions': 'all', - 'objective_key': '', - 'description': self.data_description, - 'data_opener': self.data_data_opener - } - - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - with mock.patch.object(LedgerDataManagerSerializer, 'create') as mcreate: - mcreate.return_value = ({ - 'message': 'DataManager added in local db waiting for validation.' - 'The substra network has been notified for adding this DataManager' - }, status.HTTP_202_ACCEPTED) - response = self.client.post(url, data, format='multipart', **extra) - - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - def test_add_datamanager_ko(self): - url = reverse('substrapp:data_manager-list') - - data = {'name': 'toto'} - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_datamanager_no_version(self): - url = reverse('substrapp:data_manager-list') - - data = { - 'name': 'slide opener', - 'description': self.data_description, - 'data_opener': self.data_data_opener - } - response = self.client.post(url, data, format='multipart') - r = response.json() - - self.assertEqual(r, {'detail': 'A version is required.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_add_datamanager_wrong_version(self): - url = reverse('substrapp:data_manager-list') - - data = { - 'name': 'slide opener', - 'type': 'images', - 'permissions': 'all', - 'objective_key': '', - 'description': self.data_description, - 'data_opener': self.data_data_opener - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=-1.0', - } - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER_SYNC_ENABLED=True) -class DataSampleQueryTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.script, self.script_filename = get_sample_script() - self.data_file, self.data_file_filename = get_sample_zip_data_sample() - self.data_file_2, self.data_file_filename_2 = get_sample_zip_data_sample_2() - self.data_tar_file, self.data_tar_file_filename = get_sample_tar_data_sample() - - self.data_description, self.data_description_filename, self.data_data_opener, \ - self.data_opener_filename = get_sample_datamanager() - - self.data_description2, self.data_description_filename2, self.data_data_opener2, \ - self.data_opener_filename2 = get_sample_datamanager2() - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - def test_add_data_sample_sync_ok(self): - - # add associated data opener - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - url = reverse('substrapp:data_sample-list') - - data = { - 'file': self.data_file, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mcreate.return_value = ({ - 'pkhash': '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553', - 'validated': True - }, status.HTTP_201_CREATED) - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.data_file.file.seek(0) - self.assertEqual(r[0]['pkhash'], get_dir_hash(self.data_file.file)) - - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - def test_bulk_add_data_sample_sync_ok(self): - - # add associated data opener - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - url = reverse('substrapp:data_sample-list') - - file_mock = MagicMock(spec=InMemoryUploadedFile) - file_mock2 = MagicMock(spec=InMemoryUploadedFile) - file_mock.name = 'foo.zip' - file_mock2.name = 'bar.zip' - file_mock.read = MagicMock(return_value=self.data_file.read()) - file_mock2.read = MagicMock(return_value=self.data_file_2.read()) - - data = { - file_mock.name: file_mock, - file_mock2.name: file_mock2, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch('substrapp.serializers.datasample.DataSampleSerializer.get_validators') as mget_validators, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mget_validators.return_value = [] - self.data_file.seek(0) - self.data_file_2.seek(0) - ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': True} - mcreate.return_value = ledger_data, status.HTTP_201_CREATED - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(len(r), 2) - self.assertEqual(r[0]['pkhash'], get_dir_hash(file_mock)) - self.assertTrue(r[0]['path'].endswith(f'/datasamples/{get_dir_hash(file_mock)}')) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - def test_add_data_sample_no_sync_ok(self): - # add associated data opener - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - url = reverse('substrapp:data_sample-list') - data = { - 'file': self.data_file, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - with mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mcreate.return_value = ({ - 'message': 'Data added in local db waiting for validation.' - 'The substra network has been notified for adding this Data' - }, status.HTTP_202_ACCEPTED) - response = self.client.post(url, data, format='multipart', **extra) - - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - def test_add_data_sample_ko(self): - url = reverse('substrapp:data_sample-list') - - # missing datamanager - data = {'data_manager_keys': ['toto']} - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual( - r['message'], - "One or more datamanager keys provided do not exist in local substrabac database. " - "Please create them before. DataManager keys: ['toto']") - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - # missing local storage field - data = {'data_manager_keys': [get_hash(self.data_description)], - 'test_only': True, } - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - # missing ledger field - data = {'data_manager_keys': [get_hash(self.data_description)], - 'file': self.script, } - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_data_sample_ko_already_exists(self): - url = reverse('substrapp:data_sample-list') - - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - file_mock = MagicMock(spec=InMemoryUploadedFile) - file_mock.name = 'foo.zip' - file_mock.read = MagicMock(return_value=self.data_file.file.read()) - file_mock.open = MagicMock(return_value=file_mock) - - d = DataSample(path=file_mock) - # trigger pre save - d.save() - - data = { - 'file': file_mock, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile: - mis_zipfile.return_value = True - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r['message'], - [[{'pkhash': ['data sample with this pkhash already exists.']}]]) - self.assertEqual(response.status_code, status.HTTP_409_CONFLICT) - - def test_add_data_sample_ko_not_a_zip(self): - url = reverse('substrapp:data_sample-list') - - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - file_mock = MagicMock(spec=File) - file_mock.name = 'foo.zip' - file_mock.read = MagicMock(return_value=b'foo') - - data = { - 'file': file_mock, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r['message'], 'Archive must be zip or tar.*') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_data_sample_ko_408(self): - url = reverse('substrapp:data_sample-list') - - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - file_mock = MagicMock(spec=InMemoryUploadedFile) - file_mock.name = 'foo.zip' - file_mock.read = MagicMock(return_value=self.data_file.file.read()) - file_mock.open = MagicMock(return_value=file_mock) - - data = { - 'file': file_mock, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mcreate.return_value = {'pkhash': get_hash(file_mock), 'validated': False}, status.HTTP_408_REQUEST_TIMEOUT - mis_zipfile.return_value = True - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r['message'], {'pkhash': [get_dir_hash(file_mock)], 'validated': False}) - self.assertEqual(response.status_code, status.HTTP_408_REQUEST_TIMEOUT) - - def test_bulk_add_data_sample_ko_408(self): - - # add associated data opener - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - url = reverse('substrapp:data_sample-list') - - file_mock = MagicMock(spec=InMemoryUploadedFile) - file_mock2 = MagicMock(spec=InMemoryUploadedFile) - file_mock.name = 'foo.zip' - file_mock2.name = 'bar.zip' - file_mock.read = MagicMock(return_value=self.data_file.read()) - file_mock2.read = MagicMock(return_value=self.data_file_2.read()) - - data = { - file_mock.name: file_mock, - file_mock2.name: file_mock2, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch('substrapp.serializers.datasample.DataSampleSerializer.get_validators') as mget_validators, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mget_validators.return_value = [] - self.data_file.seek(0) - self.data_tar_file.seek(0) - ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} - mcreate.return_value = ledger_data, status.HTTP_408_REQUEST_TIMEOUT - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r['message']['validated'], False) - self.assertEqual(DataSample.objects.count(), 2) - self.assertEqual(response.status_code, status.HTTP_408_REQUEST_TIMEOUT) - - def test_bulk_add_data_sample_ko_same_pkhash(self): - - # add associated data opener - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - url = reverse('substrapp:data_sample-list') - - file_mock = MagicMock(spec=InMemoryUploadedFile) - file_mock2 = MagicMock(spec=InMemoryUploadedFile) - file_mock.name = 'foo.zip' - file_mock2.name = 'bar.tar.gz' - file_mock.read = MagicMock(return_value=self.data_file.read()) - file_mock2.read = MagicMock(return_value=self.data_tar_file.read()) - - data = { - file_mock.name: file_mock, - file_mock2.name: file_mock2, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch('substrapp.serializers.datasample.DataSampleSerializer.get_validators') as mget_validators, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mget_validators.return_value = [] - self.data_file.seek(0) - self.data_tar_file.seek(0) - ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} - mcreate.return_value = ledger_data, status.HTTP_408_REQUEST_TIMEOUT - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(DataSample.objects.count(), 0) - self.assertEqual( - r['message'], - f'Your data sample archives contain same files leading to same pkhash, ' - f'please review the content of your achives. ' - f'Archives {file_mock2.name} and {file_mock.name} are the same') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_data_sample_ko_400(self): - url = reverse('substrapp:data_sample-list') - - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - file_mock = MagicMock(spec=InMemoryUploadedFile) - file_mock.name = 'foo.zip' - file_mock.read = MagicMock(return_value=self.data_file.file.read()) - - data = { - 'file': file_mock, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mcreate.return_value = 'Failed', status.HTTP_400_BAD_REQUEST - mis_zipfile.return_value = True - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r['message'], 'Failed') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_data_sample_ko_serializer_invalid(self): - url = reverse('substrapp:data_sample-list') - - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - file_mock = MagicMock(spec=InMemoryUploadedFile) - file_mock.name = 'foo.zip' - file_mock.read = MagicMock(return_value=self.data_file.read()) - - data = { - 'file': file_mock, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ - mock.patch.object(DataSampleViewSet, 'get_serializer') as mget_serializer: - mocked_serializer = MagicMock(DataSampleSerializer) - mocked_serializer.is_valid.return_value = True - mocked_serializer.save.side_effect = Exception('Failed') - mget_serializer.return_value = mocked_serializer - - mis_zipfile.return_value = True - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r['message'], "Failed") - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_data_sample_ko_ledger_invalid(self): - url = reverse('substrapp:data_sample-list') - - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - file_mock = MagicMock(spec=InMemoryUploadedFile) - file_mock.name = 'foo.zip' - file_mock.read = MagicMock(return_value=self.data_file.file.read()) - - data = { - 'file': file_mock, - 'data_manager_keys': [get_hash(self.data_data_opener)], - 'test_only': True, - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ - mock.patch('substrapp.views.datasample.LedgerDataSampleSerializer', - spec=True) as mLedgerDataSampleSerializer: - mocked_LedgerDataSampleSerializer = MagicMock() - mocked_LedgerDataSampleSerializer.is_valid.return_value = False - mocked_LedgerDataSampleSerializer.errors = 'Failed' - mLedgerDataSampleSerializer.return_value = mocked_LedgerDataSampleSerializer - - mis_zipfile.return_value = True - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r['message'], "[ErrorDetail(string='Failed', code='invalid')]") - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_data_sample_no_version(self): - - # add associated data opener - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - url = reverse('substrapp:data_sample-list') - - data = { - 'file': self.data_file, - 'data_manager_keys': [get_hash(self.data_description)], - 'test_only': True, - } - response = self.client.post(url, data, format='multipart') - r = response.json() - - self.assertEqual(r, {'detail': 'A version is required.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_add_data_sample_wrong_version(self): - - # add associated data opener - datamanager_name = 'slide opener' - DataManager.objects.create(name=datamanager_name, - description=self.data_description, - data_opener=self.data_data_opener) - - url = reverse('substrapp:data_sample-list') - - data = { - 'file': self.script, - 'data_manager_keys': [datamanager_name], - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=-1.0', - } - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_bulk_update_data(self): - - # add associated data opener - datamanager = DataManager.objects.create(name='slide opener', - description=self.data_description, - data_opener=self.data_data_opener) - datamanager2 = DataManager.objects.create(name='slide opener 2', - description=self.data_description2, - data_opener=self.data_data_opener2) - - d = DataSample(path=self.data_file) - # trigger pre save - d.save() - - url = reverse('substrapp:data_sample-bulk-update') - - data = { - 'data_manager_keys': [datamanager.pkhash, datamanager2.pkhash], - 'data_sample_keys': [d.pkhash], - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch( - 'substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = {'keys': [ - d.pkhash]}, status.HTTP_200_OK - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r['keys'], [d.pkhash]) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER_SYNC_ENABLED=True) -class AlgoQueryTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.objective_description, self.objective_description_filename, \ - self.objective_metrics, self.objective_metrics_filename = get_sample_objective() - - self.algo, self.algo_filename = get_sample_algo() - - self.data_description, self.data_description_filename, self.data_data_opener, \ - self.data_opener_filename = get_sample_datamanager() - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - def test_add_algo_sync_ok(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/algo.tar.gz'), 'rb') as tar_file: - algo_content = tar_file.read() - - # add associated objective - Objective.objects.create(description=self.objective_description, - metrics=self.objective_metrics) - - url = reverse('substrapp:algo-list') - - data = { - 'file': self.algo, - 'description': self.data_description, - 'name': 'super top algo', - 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: - mcreate.return_value = {'pkhash': compute_hash(algo_content)}, status.HTTP_201_CREATED - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(r['pkhash'], compute_hash(algo_content)) - - def test_add_algo_no_sync_ok(self): - # add associated objective - Objective.objects.create(description=self.objective_description, - metrics=self.objective_metrics) - url = reverse('substrapp:algo-list') - data = { - 'file': self.algo, - 'description': self.data_description, - 'name': 'super top algo', - 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' - } - - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: - mcreate.return_value = ({ - 'message': 'Algo added in local db waiting for validation.' - 'The substra network has been notified for adding this Algo' - }, status.HTTP_202_ACCEPTED) - response = self.client.post(url, data, format='multipart', **extra) - - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - def test_add_algo_ko(self): - url = reverse('substrapp:algo-list') - - # non existing associated objective - data = { - 'file': self.algo, - 'description': self.data_description, - 'name': 'super top algo', - 'objective_key': 'non existing objectivexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - 'permissions': 'all' - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: - mcreate.return_value = { - 'message': 'Fail to add algo. Objective does not exist'}, status.HTTP_400_BAD_REQUEST - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertIn('does not exist', r['message']) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - Objective.objects.create(description=self.objective_description, - metrics=self.objective_metrics) - - # missing local storage field - data = { - 'name': 'super top algo', - 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' - } - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - # missing ledger field - data = { - 'file': self.algo, - 'description': self.data_description, - 'objective_key': get_hash(self.objective_description), - } - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_algo_no_version(self): - - # add associated objective - Objective.objects.create(description=self.objective_description, - metrics=self.objective_metrics) - - url = reverse('substrapp:algo-list') - - data = { - 'file': self.algo, - 'description': self.data_description, - 'name': 'super top algo', - 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' - } - response = self.client.post(url, data, format='multipart') - r = response.json() - - self.assertEqual(r, {'detail': 'A version is required.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_add_algo_wrong_version(self): - - # add associated objective - Objective.objects.create(description=self.objective_description, - metrics=self.objective_metrics) - - url = reverse('substrapp:algo-list') - - data = { - 'file': self.algo, - 'description': self.data_description, - 'name': 'super top algo', - 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' - } - extra = { - 'HTTP_ACCEPT': 'application/json;version=-1.0', - } - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - - self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_get_algo_files(self): - algo = Algo.objects.create(file=self.algo) - with mock.patch( - 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.return_value = self.algo - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - response = self.client.get(f'/algo/{algo.pkhash}/file/', **extra) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(algo.pkhash, compute_hash(response.getvalue())) - # self.assertEqual(r, f'http://testserver/media/algos/{algo.pkhash}/{self.algo_filename}') - - def test_get_algo_files_no_version(self): - algo = Algo.objects.create(file=self.algo) - response = self.client.get(f'/algo/{algo.pkhash}/file/') - r = response.json() - self.assertEqual(r, {'detail': 'A version is required.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_get_algo_files_wrong_version(self): - algo = Algo.objects.create(file=self.algo) - extra = { - 'HTTP_ACCEPT': 'application/json;version=-1.0', - } - response = self.client.get(f'/algo/{algo.pkhash}/file/', **extra) - r = response.json() - self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER_SYNC_ENABLED=True) -class TraintupleQueryTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.objective_description, self.objective_description_filename, \ - self.objective_metrics, self.objective_metrics_filename = get_sample_objective() - - self.train_data_sample_keys = ['5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b422'] - self.fake_key = '5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0a088' - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - def test_add_traintuple_ok(self): - # Add associated objective - description, _, metrics, _ = get_sample_objective() - Objective.objects.create(description=description, - metrics=metrics) - # post data - url = reverse('substrapp:traintuple-list') - - data = { - 'train_data_sample_keys': self.train_data_sample_keys, - 'algo_key': self.fake_key, - 'data_manager_key': self.fake_key, - 'objective_key': self.fake_key, - 'rank': -1, - 'FLtask_key': self.fake_key, - 'in_models_keys': [self.fake_key]} - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - with mock.patch.object(LedgerTrainTupleSerializer, 'create') as mcreate, \ - mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: - - raw_pkhash = 'traintuple_pkhash'.encode('utf-8').hex() - mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) - mcreate.return_value = ({ - 'message': 'Traintuple added in local db waiting for validation.' - 'The substra network has been notified for adding this Traintuple' - }, status.HTTP_202_ACCEPTED) - - response = self.client.post(url, data, format='multipart', **extra) - - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - def test_add_traintuple_ko(self): - url = reverse('substrapp:traintuple-list') - - data = { - 'train_data_sample_keys': self.train_data_sample_keys, - 'model_key': self.fake_key - } - - extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0', - } - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertIn('This field may not be null.', r['algo_key']) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - Objective.objects.create(description=self.objective_description, - metrics=self.objective_metrics) - data = {'objective': get_hash(self.objective_description)} - response = self.client.post(url, data, format='multipart', **extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_add_traintuple_no_version(self): - # Add associated objective - description, _, metrics, _ = get_sample_objective() - Objective.objects.create(description=description, - metrics=metrics) - # post data - url = reverse('substrapp:traintuple-list') - - data = { - 'train_data_sample_keys': self.train_data_sample_keys, - 'datamanager_key': self.fake_key, - 'model_key': self.fake_key, - 'algo_key': self.fake_key} - - response = self.client.post(url, data, format='multipart') - r = response.json() - self.assertEqual(r, {'detail': 'A version is required.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - - def test_add_traintuple_wrong_version(self): - # Add associated objective - description, _, metrics, _ = get_sample_objective() - Objective.objects.create(description=description, - metrics=metrics) - # post data - url = reverse('substrapp:traintuple-list') - - data = { - 'train_data_sample_keys': self.train_data_sample_keys, - 'datamanager_key': self.fake_key, - 'model_key': self.fake_key, - 'algo_key': self.fake_key} - extra = { - 'HTTP_ACCEPT': 'application/json;version=-1.0', - } - - response = self.client.post(url, data, format='multipart', **extra) - r = response.json() - self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) - self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) From e050e39fe3482f8a1c56718b2925238bfbb447d2 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 5 Jun 2019 13:47:23 +0200 Subject: [PATCH 074/457] Improve tests. --- substrabac/substrapp/tests/common.py | 22 ++++++++++++------- .../substrapp/tests/query/tests_query_algo.py | 20 ++++++++++++++--- .../tests/query/tests_query_datasample.py | 10 +++++---- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 1ce7838b9..5b70dc342 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -168,14 +168,6 @@ def get_sample_datamanager2(): return description, description_filename, data_opener, data_opener_filename -def get_sample_data_sample(): - file_content = "0\n1\n2" - file_filename = "file.csv" - file = get_temporary_text_file(file_content, file_filename) - - return file, file_filename - - def get_sample_zip_data_sample(): dir_path = os.path.dirname(os.path.realpath(__file__)) file_filename = "file.zip" @@ -233,6 +225,20 @@ def get_sample_algo(): return file, file_filename +def get_sample_algo_zip(): + dir_path = os.path.dirname(os.path.realpath(__file__)) + file_filename = "file.tar.gz" + f = BytesIO() + with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo0/algo.zip'), 'rb') as tar_file: + flength = f.write(tar_file.read()) + + file = InMemoryUploadedFile(f, None, file_filename, + 'application/tar+gzip', flength, None) + file.seek(0) + + return file, file_filename + + def get_sample_model(): model_content = "0.1, 0.2, -1.0" model_filename = "model.bin" diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substrabac/substrapp/tests/query/tests_query_algo.py index ffd23bf08..5198e18dd 100644 --- a/substrabac/substrapp/tests/query/tests_query_algo.py +++ b/substrabac/substrapp/tests/query/tests_query_algo.py @@ -15,7 +15,7 @@ from substrapp.utils import get_hash, compute_hash from ..common import get_sample_objective, get_sample_datamanager, \ - get_sample_algo + get_sample_algo, get_sample_algo_zip MEDIA_ROOT = tempfile.mkdtemp() @@ -32,6 +32,7 @@ def setUp(self): self.objective_metrics, self.objective_metrics_filename = get_sample_objective() self.algo, self.algo_filename = get_sample_algo() + self.algo_zip, self.algo_filename_zip = get_sample_algo_zip() self.data_description, self.data_description_filename, self.data_data_opener, \ self.data_opener_filename = get_sample_datamanager() @@ -56,9 +57,22 @@ def get_default_algo_data(self): return expected_hash, data + def get_default_algo_data_zip(self): + expected_hash = get_hash(self.algo_zip) + + data = { + 'file': self.algo_zip, + 'description': self.data_description, # fake it + 'name': 'super top algo', + 'objective_key': get_hash(self.objective_description), + 'permissions': 'all' + } + + return expected_hash, data + def test_add_algo_sync_ok(self): self.add_default_objective() - pkhash, data = self.get_default_algo_data() + pkhash, data = self.get_default_algo_data_zip() url = reverse('substrapp:algo-list') extra = { @@ -76,7 +90,7 @@ def test_add_algo_sync_ok(self): self.assertEqual(r['description'], f'http://testserver/media/algos/{r["pkhash"]}/{self.data_description_filename}') self.assertEqual(r['file'], - f'http://testserver/media/algos/{r["pkhash"]}/{self.algo_filename}') + f'http://testserver/media/algos/{r["pkhash"]}/{self.algo_filename_zip}') self.assertEqual(response.status_code, status.HTTP_201_CREATED) @override_settings(LEDGER_SYNC_ENABLED=False) diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substrabac/substrapp/tests/query/tests_query_datasample.py index 34bc473b2..cde04d252 100644 --- a/substrabac/substrapp/tests/query/tests_query_datasample.py +++ b/substrabac/substrapp/tests/query/tests_query_datasample.py @@ -53,6 +53,10 @@ def add_default_data_manager(self): description=self.data_description, data_opener=self.data_data_opener) + DataManager.objects.create(name='slide opener', + description=self.data_description2, + data_opener=self.data_data_opener2) + def get_default_datasample_data(self): expected_hash = get_dir_hash(self.data_file.file) self.data_file.file.seek(0) @@ -103,16 +107,14 @@ def test_bulk_add_data_sample_sync_ok(self): data = { file_mock.name: file_mock, file_mock2.name: file_mock2, - 'data_manager_keys': [get_hash(self.data_data_opener)], + 'data_manager_keys': [get_hash(self.data_data_opener), get_hash(self.data_data_opener2)], 'test_only': True, } extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.datasample.DataSampleSerializer.get_validators') as mget_validators, \ - mock.patch('substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: - mget_validators.return_value = [] + with mock.patch('substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: self.data_file.seek(0) self.data_file_2.seek(0) ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': True} From 1773cc97bd61092241e681b2cdb630e5b38138f1 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 5 Jun 2019 14:23:52 +0200 Subject: [PATCH 075/457] Move and split tests views. --- substrabac/substrapp/tests/tests_views.py | 1176 ----------------- substrabac/substrapp/tests/views/__init__.py | 0 .../substrapp/tests/views/tests_views.py | 47 + .../substrapp/tests/views/tests_views_algo.py | 201 +++ .../tests/views/tests_views_datamanager.py | 188 +++ .../tests/views/tests_views_datasample.py | 216 +++ .../tests/views/tests_views_model.py | 165 +++ .../tests/views/tests_views_objective.py | 274 ++++ .../substrapp/tests/views/tests_views_task.py | 63 + .../tests/views/tests_views_tuples.py | 163 +++ 10 files changed, 1317 insertions(+), 1176 deletions(-) delete mode 100644 substrabac/substrapp/tests/tests_views.py create mode 100644 substrabac/substrapp/tests/views/__init__.py create mode 100644 substrabac/substrapp/tests/views/tests_views.py create mode 100644 substrabac/substrapp/tests/views/tests_views_algo.py create mode 100644 substrabac/substrapp/tests/views/tests_views_datamanager.py create mode 100644 substrabac/substrapp/tests/views/tests_views_datasample.py create mode 100644 substrabac/substrapp/tests/views/tests_views_model.py create mode 100644 substrabac/substrapp/tests/views/tests_views_objective.py create mode 100644 substrabac/substrapp/tests/views/tests_views_task.py create mode 100644 substrabac/substrapp/tests/views/tests_views_tuples.py diff --git a/substrabac/substrapp/tests/tests_views.py b/substrabac/substrapp/tests/tests_views.py deleted file mode 100644 index e1547798a..000000000 --- a/substrabac/substrapp/tests/tests_views.py +++ /dev/null @@ -1,1176 +0,0 @@ -import os -import shutil -import logging - -import mock - -from django.urls import reverse -from django.test import override_settings - -from rest_framework import status -from rest_framework.test import APITestCase - -from substrapp.views import TrainTupleViewSet, TestTupleViewSet, DataSampleViewSet - -from substrapp.serializers import LedgerDataSampleSerializer, LedgerObjectiveSerializer, LedgerAlgoSerializer - -from substrapp.utils import JsonException -from substrapp.views.utils import ComputeHashMixin -from substrapp.views.datasample import path_leaf, compute_dryrun as data_sample_compute_dryrun -from substrapp.views.objective import compute_dryrun as objective_compute_dryrun -from substrapp.utils import compute_hash, get_hash -from substrapp.ledger_utils import get_object_from_ledger - -from substrapp.models import DataManager - -from .common import get_sample_objective, get_sample_datamanager, get_sample_algo, get_sample_model -from .common import FakeAsyncResult, FakeRequest, FakeFilterDataManager, FakeTask, FakeDataManager -from .assets import objective, datamanager, algo, traintuple, model, testtuple - -MEDIA_ROOT = "/tmp/unittests_views/" - - -# APITestCase -class ViewTests(APITestCase): - def test_data_sample_path_view(self): - self.assertEqual('tutu', path_leaf('/toto/tata/tutu')) - self.assertEqual('toto', path_leaf('/toto/')) - - def test_utils_ComputeHashMixin(self): - - compute = ComputeHashMixin() - myfile = 'toto' - key = 'tata' - - myfilehash = compute_hash(myfile) - myfilehashwithkey = compute_hash(myfile, key) - - self.assertEqual(myfilehash, compute.compute_hash(myfile)) - self.assertEqual(myfilehashwithkey, compute.compute_hash(myfile, key)) - - def test_utils_get_object_from_ledger(self): - - with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] - data = get_object_from_ledger('', 'queryObjective') - - self.assertEqual(data, objective) - - with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [('', status.HTTP_400_BAD_REQUEST)] - with self.assertRaises(JsonException): - get_object_from_ledger('', 'queryAllObjective') - - -# APITestCase -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(DRYRUN_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -@override_settings(DEFAULT_DOMAIN='https://localhost') -class ObjectiveViewTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.objective_description, self.objective_description_filename, \ - self.objective_metrics, self.objective_metrics_filename = get_sample_objective() - - self.test_data_sample_keys = [ - "2d0f943aa81a9cb3fe84b162559ce6aff068ccb04e0cb284733b8f9d7e06517e", - "533ee6e7b9d8b247e7e853b24547f57e6ef351852bac0418f13a0666173448f1" - ] - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_objective_list_empty(self): - url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [[]]) - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [['ISIC']]) - - def test_objective_list_filter_fail(self): - url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] - - search_params = '?search=challenERRORge' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertIn('Malformed search filters', r['message']) - - def test_objective_list_filter_name(self): - url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] - - search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 2) - - def test_objective_list_filter_metrics(self): - url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] - - search_params = '?search=objective%253Ametrics%253Amacro-average%2520recall' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), len(objective)) - - def test_objective_list_filter_datamanager(self): - url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] - - search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 1) - - def test_objective_list_filter_model(self): - url = reverse('substrapp:objective-list') - with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] - - pkhash = model[0]['traintuple']['outModel']['hash'] - search_params = f'?search=model%253Ahash%253A{pkhash}' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 1) - - def test_objective_retrieve(self): - url = reverse('substrapp:objective-list') - - with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.objective.get_from_node') as mrequestsget: - mget_object_from_ledger.return_value = objective[0] - - with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), - '../../../fixtures/owkin/objectives/objective0/description.md'), 'rb') as f: - content = f.read() - - mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, - content=content) - - search_params = f'{compute_hash(content)}/' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(r, objective[0]) - - def test_objective_retrieve_fail(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - url = reverse('substrapp:objective-list') - - # PK hash < 64 chars - search_params = '42303efa663015e729159833a12ffb510ff/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - # PK hash not hexa - search_params = 'X' * 64 + '/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') - - file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) - search_params = f'{file_hash}/' - response = self.client.get(url + search_params, **self.extra) - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_objective_create(self): - url = reverse('substrapp:objective-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - description_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/description.md') - metrics_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/metrics.py') - - pkhash = get_hash(description_path) - - test_data_manager_key = get_hash(os.path.join( - dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) - - data = { - 'name': 'Simplified skin lesion classification', - 'description': open(description_path, 'rb'), - 'metrics_name': 'macro-average recall', - 'metrics': open(metrics_path, 'rb'), - 'permissions': 'all', - 'test_data_sample_keys': self.test_data_sample_keys, - 'test_data_manager_key': test_data_manager_key - } - - with mock.patch.object(LedgerObjectiveSerializer, 'create') as mcreate: - - mcreate.return_value = ({}, - status.HTTP_201_CREATED) - - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertEqual(response.data['pkhash'], pkhash) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - data['description'].close() - data['metrics'].close() - - def test_objective_create_dryrun(self): - - url = reverse('substrapp:objective-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - description_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/description.md') - metrics_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/metrics.py') - - test_data_manager_key = get_hash(os.path.join( - dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) - - data = { - 'name': 'Simplified skin lesion classification', - 'description': open(description_path, 'rb'), - 'metrics_name': 'macro-average recall', - 'metrics': open(metrics_path, 'rb'), - 'permissions': 'all', - 'test_data_sample_keys': self.test_data_sample_keys, - 'test_data_manager_key': test_data_manager_key, - 'dryrun': True - } - - with mock.patch('substrapp.views.objective.compute_dryrun.apply_async') as mdryrun_task: - - mdryrun_task.return_value = FakeTask('42') - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], - 'Your dry-run has been taken in account. ' - 'You can follow the task execution on https://localhost/task/42/') - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - data['description'].close() - data['metrics'].close() - - def test_objective_compute_dryrun(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - metrics_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/metrics.py') - description_path = os.path.join(dir_path, '../../../fixtures/owkin/objectives/objective0/description.md') - shutil.copy(metrics_path, os.path.join(MEDIA_ROOT, 'metrics.py')) - - opener_path = os.path.join(dir_path, '../../../fixtures/owkin/datamanagers/datamanager0/opener.py') - - with open(opener_path, 'rb') as f: - opener_content = f.read() - - pkhash = get_hash(description_path) - - test_data_manager_key = compute_hash(opener_content) - - with mock.patch('substrapp.views.objective.get_object_from_ledger') as mdatamanager,\ - mock.patch('substrapp.views.objective.get_computed_hash') as mopener: - mdatamanager.return_value = {'opener': {'storageAddress': 'test'}} - mopener.return_value = (opener_content, pkhash) - objective_compute_dryrun(os.path.join(MEDIA_ROOT, 'metrics.py'), test_data_manager_key, pkhash) - - -# APITestCase -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(DRYRUN_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -class AlgoViewTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.algo, self.algo_filename = get_sample_algo() - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_algo_list_empty(self): - url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [[]]) - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [['ISIC']]) - - def test_algo_list_filter_fail(self): - url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] - - search_params = '?search=algERRORo' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertIn('Malformed search filters', r['message']) - - def test_algo_list_filter_name(self): - url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] - - search_params = '?search=algo%253Aname%253ALogistic%2520regression' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 1) - - def test_algo_list_filter_datamanager_fail(self): - url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] - - search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertIn('Malformed search filters', r['message']) - - def test_algo_list_filter_objective_fail(self): - url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] - - search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertIn('Malformed search filters', r['message']) - - def test_algo_list_filter_model(self): - url = reverse('substrapp:algo-list') - with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] - - pkhash = model[0]['traintuple']['outModel']['hash'] - search_params = f'?search=model%253Ahash%253A{pkhash}' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 1) - - def test_algo_retrieve(self): - dir_path = os.path.dirname(os.path.realpath(__file__)) - algo_hash = get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo4/algo.tar.gz')) - url = reverse('substrapp:algo-list') - algo_response = [a for a in algo if a['key'] == algo_hash][0] - with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.algo.get_from_node') as mrequestsget: - - with open(os.path.join(dir_path, - '../../../fixtures/chunantes/algos/algo4/description.md'), 'rb') as f: - content = f.read() - mget_object_from_ledger.return_value = algo_response - - mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, - content=content) - - search_params = f'{algo_hash}/' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(r, algo_response) - - def test_algo_retrieve_fail(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - url = reverse('substrapp:algo-list') - - # PK hash < 64 chars - search_params = '42303efa663015e729159833a12ffb510ff/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - # PK hash not hexa - search_params = 'X' * 64 + '/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') - - file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) - search_params = f'{file_hash}/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_algo_create(self): - url = reverse('substrapp:algo-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - algo_path = os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/algo.tar.gz') - description_path = os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/description.md') - - pkhash = get_hash(algo_path) - - data = {'name': 'Logistic regression', - 'file': open(algo_path, 'rb'), - 'description': open(description_path, 'rb'), - 'objective_key': get_hash(os.path.join( - dir_path, '../../../fixtures/chunantes/objectives/objective0/description.md')), - 'permissions': 'all'} - - with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: - - mcreate.return_value = ({}, - status.HTTP_201_CREATED) - - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertEqual(response.data['pkhash'], pkhash) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - data['description'].close() - data['file'].close() - - -# APITestCase -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -class ModelViewTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.model, self.model_filename = get_sample_model() - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_model_list_empty(self): - url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [[]]) - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [['ISIC']]) - - def test_model_list_filter_fail(self): - - with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] - - url = reverse('substrapp:model-list') - search_params = '?search=modeERRORl' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - self.assertIn('Malformed search filters', r['message']) - - def test_model_list_filter_hash(self): - - with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] - - pkhash = model[0]['traintuple']['outModel']['hash'] - url = reverse('substrapp:model-list') - search_params = f'?search=model%253Ahash%253A{pkhash}' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - self.assertEqual(len(r[0]), 1) - - def test_model_list_filter_datamanager(self): - url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] - - search_params = '?search=dataset%253Aname%253AISIC%25202018' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 1) - - def test_model_list_filter_objective(self): - url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] - - search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 1) - - def test_model_list_filter_algo(self): - url = reverse('substrapp:model-list') - with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(algo, status.HTTP_200_OK)] - - search_params = '?search=algo%253Aname%253ALogistic%2520regression' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 1) - - def test_model_retrieve(self): - - with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.model.get_from_node') as mrequestsget, \ - mock.patch('substrapp.views.model.ModelViewSet.compute_hash') as mcomputed_hash: - mget_object_from_ledger.return_value = model[0] - - mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, - content=self.model.read().encode()) - - mcomputed_hash.return_value = model[0]['traintuple']['outModel']['hash'] - - url = reverse('substrapp:model-list') - search_params = model[0]['traintuple']['outModel']['hash'] + '/' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - self.assertEqual(r, model[0]) - - def test_model_retrieve_fail(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - url = reverse('substrapp:model-list') - - # PK hash < 64 chars - search_params = '42303efa663015e729159833a12ffb510ff/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - # PK hash not hexa - search_params = 'X' * 64 + '/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') - - file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) - search_params = f'{file_hash}/' - response = self.client.get(url + search_params, **self.extra) - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - -# APITestCase -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -class DataManagerViewTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.data_description, self.data_description_filename, \ - self.data_data_opener, self.data_opener_filename = get_sample_datamanager() - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_datamanager_list_empty(self): - url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [[]]) - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [['ISIC']]) - - def test_datamanager_list_filter_fail(self): - url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] - - search_params = '?search=dataseERRORt' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertIn('Malformed search filters', r['message']) - - def test_datamanager_list_filter_name(self): - url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] - - search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 1) - - def test_datamanager_list_filter_objective(self): - url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] - - search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 2) - - def test_datamanager_list_filter_model(self): - url = reverse('substrapp:data_manager-list') - with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] - pkhash = model[0]['traintuple']['outModel']['hash'] - search_params = f'?search=model%253Ahash%253A{pkhash}' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(len(r[0]), 2) - - def test_datamanager_retrieve(self): - url = reverse('substrapp:data_manager-list') - datamanager_response = [d for d in datamanager - if d['key'] == '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7'][0] - with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.datamanager.get_from_node') as mrequestsget: - mget_object_from_ledger.return_value = datamanager_response - - with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), - '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), 'rb') as f: - opener_content = f.read() - - with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), - '../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), 'rb') as f: - description_content = f.read() - - mrequestsget.side_effect = [FakeRequest(status=status.HTTP_200_OK, - content=opener_content), - FakeRequest(status=status.HTTP_200_OK, - content=description_content)] - - search_params = '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7/' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - - self.assertEqual(r, datamanager_response) - - def test_datamanager_retrieve_fail(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - url = reverse('substrapp:data_manager-list') - - # PK hash < 64 chars - search_params = '42303efa663015e729159833a12ffb510ff/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - # PK hash not hexa - search_params = 'X' * 64 + '/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') - - file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) - search_params = f'{file_hash}/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_datamanager_create_dryrun(self): - url = reverse('substrapp:data_manager-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - files = { - 'data_opener': open( - os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), - 'rb'), - - 'description': open( - os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), - 'rb')} - - data = { - 'name': 'ISIC 2018', - 'type': 'Images', - 'permissions': 'all', - 'dryrun': True - } - - response = self.client.post(url, {**data, **files}, format='multipart', **self.extra) - self.assertEqual(response.data, {'message': f'Your data opener is valid. You can remove the dryrun option.'}) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - for x in files: - files[x].close() - - -# APITestCase -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -class TraintupleViewTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_traintuple_queryset(self): - traintuple_view = TrainTupleViewSet() - self.assertFalse(traintuple_view.get_queryset()) - - def test_traintuple_list_empty(self): - url = reverse('substrapp:traintuple-list') - with mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: - mquery_ledger.return_value = ([[]], status.HTTP_200_OK) - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [[]]) - - def test_traintuple_retrieve(self): - - with mock.patch('substrapp.views.traintuple.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.return_value = traintuple[0] - url = reverse('substrapp:traintuple-list') - search_params = 'c164f4c714a78c7e2ba2016de231cdd41e3eac61289e08c1f711e74915a0868f/' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - self.assertEqual(r, traintuple[0]) - - def test_traintuple_retrieve_fail(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - url = reverse('substrapp:traintuple-list') - - # PK hash < 64 chars - search_params = '42303efa663015e729159833a12ffb510ff/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - # PK hash not hexa - search_params = 'X' * 64 + '/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - with mock.patch('substrapp.views.traintuple.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') - - file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) - search_params = f'{file_hash}/' - response = self.client.get(url + search_params, **self.extra) - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - -# APITestCase -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -class TesttupleViewTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_testtuple_queryset(self): - testtuple_view = TestTupleViewSet() - self.assertFalse(testtuple_view.get_queryset()) - - def test_testtuple_list_empty(self): - url = reverse('substrapp:testtuple-list') - with mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: - mquery_ledger.return_value = ([[]], status.HTTP_200_OK) - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [[]]) - - def test_testtuple_retrieve(self): - - with mock.patch('substrapp.views.testtuple.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.return_value = testtuple[0] - url = reverse('substrapp:testtuple-list') - search_params = 'c164f4c714a78c7e2ba2016de231cdd41e3eac61289e08c1f711e74915a0868f/' - response = self.client.get(url + search_params, **self.extra) - r = response.json() - self.assertEqual(r, testtuple[0]) - - def test_testtuple_retrieve_fail(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - url = reverse('substrapp:testtuple-list') - - # PK hash < 64 chars - search_params = '42303efa663015e729159833a12ffb510ff/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - # PK hash not hexa - search_params = 'X' * 64 + '/' - response = self.client.get(url + search_params, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - with mock.patch('substrapp.views.testtuple.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') - - file_hash = get_hash(os.path.join(dir_path, "../../../fixtures/owkin/objectives/objective0/description.md")) - search_params = f'{file_hash}/' - response = self.client.get(url + search_params, **self.extra) - - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - -# APITestCase -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -class TaskViewTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_task_retrieve(self): - - url = reverse('substrapp:task-detail', kwargs={'pk': 'pk'}) - with mock.patch('substrapp.views.task.AsyncResult') as mAsyncResult: - mAsyncResult.return_value = FakeAsyncResult(status='SUCCESS') - response = self.client.get(url, **self.extra) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - def test_task_retrieve_fail(self): - url = reverse('substrapp:task-detail', kwargs={'pk': 'pk'}) - with mock.patch('substrapp.views.task.AsyncResult') as mAsyncResult: - mAsyncResult.return_value = FakeAsyncResult() - response = self.client.get(url, **self.extra) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - - def test_task_retrieve_pending(self): - url = reverse('substrapp:task-detail', kwargs={'pk': 'pk'}) - with mock.patch('substrapp.views.task.AsyncResult') as mAsyncResult: - mAsyncResult.return_value = FakeAsyncResult(status='PENDING', successful=False) - response = self.client.get(url, **self.extra) - self.assertEqual(response.data['message'], - 'Task is either waiting, does not exist in this context or has been removed after 24h') - - self.assertEqual(response.status_code, status.HTTP_200_OK) - - -# APITestCase -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(DRYRUN_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -@override_settings(DEFAULT_DOMAIN='https://localhost') -class DataViewTests(APITestCase): - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.data_description, self.data_description_filename, \ - self.data_data_opener, self.data_opener_filename = get_sample_datamanager() - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_data_create_bulk(self): - url = reverse('substrapp:data_sample-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - data_path1 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - data_path2 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') - - # dir hash - pkhash1 = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' - pkhash2 = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' - - data_manager_keys = [ - get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] - - data = { - 'files': [path_leaf(data_path1), path_leaf(data_path2)], - path_leaf(data_path1): open(data_path1, 'rb'), - path_leaf(data_path2): open(data_path2, 'rb'), - 'data_manager_keys': data_manager_keys, - 'test_only': False - } - - with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - - mdatamanager.return_value = FakeFilterDataManager(1) - mcreate.return_value = ({'keys': [pkhash1, pkhash2]}, - status.HTTP_201_CREATED) - response = self.client.post(url, data=data, format='multipart', **self.extra) - self.assertEqual([r['pkhash'] for r in response.data], [pkhash1, pkhash2]) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - for x in data['files']: - data[x].close() - - def test_data_create_bulk_dryrun(self): - url = reverse('substrapp:data_sample-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - data_path1 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - data_path2 = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') - - data_manager_keys = [ - get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] - - data = { - 'files': [path_leaf(data_path1), path_leaf(data_path2)], - path_leaf(data_path1): open(data_path1, 'rb'), - path_leaf(data_path2): open(data_path2, 'rb'), - 'data_manager_keys': data_manager_keys, - 'test_only': False, - 'dryrun': True - } - - with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ - mock.patch.object(DataSampleViewSet, 'dryrun_task') as mdryrun_task: - - mdatamanager.return_value = FakeFilterDataManager(1) - mdryrun_task.return_value = ( - FakeTask('42'), - 'Your dry-run has been taken in account. You can follow the task execution on localhost') - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], - 'Your dry-run has been taken in account. You can follow the task execution on localhost') - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - for x in data['files']: - data[x].close() - - def test_data_create(self): - url = reverse('substrapp:data_sample-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - data_path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - - # dir hash - pkhash = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' - - data_manager_keys = [ - get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] - - data = { - 'file': open(data_path, 'rb'), - 'data_manager_keys': data_manager_keys, - 'test_only': False - } - - with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ - mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - - mdatamanager.return_value = FakeFilterDataManager(1) - mcreate.return_value = ({'keys': [pkhash]}, - status.HTTP_201_CREATED) - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertEqual(response.data[0]['pkhash'], pkhash) - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - - data['file'].close() - - def test_data_create_dryrun(self): - - url = reverse('substrapp:data_sample-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - data_path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - - data_manager_keys = [ - get_hash(os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] - - data = { - 'file': open(data_path, 'rb'), - 'data_manager_keys': data_manager_keys, - 'test_only': False, - 'dryrun': True - } - - with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ - mock.patch.object(DataSampleViewSet, 'dryrun_task') as mdryrun_task: - - mdatamanager.return_value = FakeFilterDataManager(1) - mdryrun_task.return_value = ( - FakeTask('42'), - 'Your dry-run has been taken in account. You can follow the task execution on localhost') - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], - 'Your dry-run has been taken in account. You can follow the task execution on localhost') - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - data['file'].close() - - def test_data_sample_compute_dryrun(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - data_path = os.path.join(dir_path, '../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - - shutil.copy(data_path, os.path.join(MEDIA_ROOT, '0024700.zip')) - - opener_path = os.path.join(dir_path, '../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') - - pkhash = get_hash(data_path) - - data = { - 'filepath': os.path.join(MEDIA_ROOT, '0024700.zip'), - 'pkhash': pkhash, - } - - data_files = [data] - data_manager_keys = [get_hash(opener_path)] - - with mock.patch.object(DataManager.objects, 'get') as mdatamanager: - mdatamanager.return_value = FakeDataManager(opener_path) - data_sample_compute_dryrun(data_files, data_manager_keys) diff --git a/substrabac/substrapp/tests/views/__init__.py b/substrabac/substrapp/tests/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/substrapp/tests/views/tests_views.py b/substrabac/substrapp/tests/views/tests_views.py new file mode 100644 index 000000000..38392fe25 --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views.py @@ -0,0 +1,47 @@ +import mock + + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.utils import JsonException +from substrapp.views.utils import ComputeHashMixin +from substrapp.views.datasample import path_leaf +from substrapp.utils import compute_hash +from substrapp.ledger_utils import get_object_from_ledger + +from ..assets import objective + +MEDIA_ROOT = "/tmp/unittests_views/" + + +# APITestCase +class ViewTests(APITestCase): + def test_data_sample_path_view(self): + self.assertEqual('tutu', path_leaf('/toto/tata/tutu')) + self.assertEqual('toto', path_leaf('/toto/')) + + def test_utils_ComputeHashMixin(self): + + compute = ComputeHashMixin() + myfile = 'toto' + key = 'tata' + + myfilehash = compute_hash(myfile) + myfilehashwithkey = compute_hash(myfile, key) + + self.assertEqual(myfilehash, compute.compute_hash(myfile)) + self.assertEqual(myfilehashwithkey, compute.compute_hash(myfile, key)) + + def test_utils_get_object_from_ledger(self): + + with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + data = get_object_from_ledger('', 'queryObjective') + + self.assertEqual(data, objective) + + with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [('', status.HTTP_400_BAD_REQUEST)] + with self.assertRaises(JsonException): + get_object_from_ledger('', 'queryAllObjective') diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py new file mode 100644 index 000000000..68755c13c --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -0,0 +1,201 @@ +import os +import shutil +import logging + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + + +from substrapp.serializers import LedgerAlgoSerializer + +from substrapp.utils import JsonException +from substrapp.utils import get_hash + +from ..common import get_sample_algo +from ..common import FakeRequest +from ..assets import objective, datamanager, algo, traintuple, model + +MEDIA_ROOT = "/tmp/unittests_views/" + + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(DRYRUN_ROOT=MEDIA_ROOT) +@override_settings(SITE_HOST='localhost') +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +class AlgoViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.algo, self.algo_filename = get_sample_algo() + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_algo_list_empty(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(None, status.HTTP_200_OK), + (['ISIC'], status.HTTP_200_OK)] + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [[]]) + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [['ISIC']]) + + def test_algo_list_filter_fail(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + + search_params = '?search=algERRORo' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertIn('Malformed search filters', r['message']) + + def test_algo_list_filter_name(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + + search_params = '?search=algo%253Aname%253ALogistic%2520regression' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_algo_list_filter_datamanager_fail(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] + + search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertIn('Malformed search filters', r['message']) + + def test_algo_list_filter_objective_fail(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] + + search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertIn('Malformed search filters', r['message']) + + def test_algo_list_filter_model(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] + + pkhash = model[0]['traintuple']['outModel']['hash'] + search_params = f'?search=model%253Ahash%253A{pkhash}' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_algo_retrieve(self): + dir_path = os.path.dirname(os.path.realpath(__file__)) + algo_hash = get_hash(os.path.join(dir_path, '../../../../fixtures/chunantes/algos/algo4/algo.tar.gz')) + url = reverse('substrapp:algo-list') + algo_response = [a for a in algo if a['key'] == algo_hash][0] + with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger, \ + mock.patch('substrapp.views.algo.get_from_node') as mrequestsget: + + with open(os.path.join(dir_path, + '../../../../fixtures/chunantes/algos/algo4/description.md'), 'rb') as f: + content = f.read() + mget_object_from_ledger.return_value = algo_response + + mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, + content=content) + + search_params = f'{algo_hash}/' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(r, algo_response) + + def test_algo_retrieve_fail(self): + + dir_path = os.path.dirname(os.path.realpath(__file__)) + url = reverse('substrapp:algo-list') + + # PK hash < 64 chars + search_params = '42303efa663015e729159833a12ffb510ff/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # PK hash not hexa + search_params = 'X' * 64 + '/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') + + file_hash = get_hash(os.path.join(dir_path, + "../../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_algo_create(self): + url = reverse('substrapp:algo-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + algo_path = os.path.join(dir_path, '../../../../fixtures/chunantes/algos/algo3/algo.tar.gz') + description_path = os.path.join(dir_path, '../../../../fixtures/chunantes/algos/algo3/description.md') + + pkhash = get_hash(algo_path) + + data = {'name': 'Logistic regression', + 'file': open(algo_path, 'rb'), + 'description': open(description_path, 'rb'), + 'objective_key': get_hash(os.path.join( + dir_path, '../../../../fixtures/chunantes/objectives/objective0/description.md')), + 'permissions': 'all'} + + with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: + + mcreate.return_value = ({}, + status.HTTP_201_CREATED) + + response = self.client.post(url, data=data, format='multipart', **self.extra) + + self.assertEqual(response.data['pkhash'], pkhash) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + data['description'].close() + data['file'].close() diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py new file mode 100644 index 000000000..c3c7a8e07 --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -0,0 +1,188 @@ +import os +import shutil +import logging + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.utils import JsonException +from substrapp.utils import get_hash + + +from ..common import get_sample_datamanager +from ..common import FakeRequest +from ..assets import objective, datamanager, traintuple, model + +MEDIA_ROOT = "/tmp/unittests_views/" + + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +class DataManagerViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.data_description, self.data_description_filename, \ + self.data_data_opener, self.data_opener_filename = get_sample_datamanager() + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_datamanager_list_empty(self): + url = reverse('substrapp:data_manager-list') + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(None, status.HTTP_200_OK), + (['ISIC'], status.HTTP_200_OK)] + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [[]]) + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [['ISIC']]) + + def test_datamanager_list_filter_fail(self): + url = reverse('substrapp:data_manager-list') + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] + + search_params = '?search=dataseERRORt' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertIn('Malformed search filters', r['message']) + + def test_datamanager_list_filter_name(self): + url = reverse('substrapp:data_manager-list') + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] + + search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_datamanager_list_filter_objective(self): + url = reverse('substrapp:data_manager-list') + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] + + search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 2) + + def test_datamanager_list_filter_model(self): + url = reverse('substrapp:data_manager-list') + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] + pkhash = model[0]['traintuple']['outModel']['hash'] + search_params = f'?search=model%253Ahash%253A{pkhash}' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 2) + + def test_datamanager_retrieve(self): + url = reverse('substrapp:data_manager-list') + datamanager_response = [d for d in datamanager + if d['key'] == '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7'][0] + with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger, \ + mock.patch('substrapp.views.datamanager.get_from_node') as mrequestsget: + mget_object_from_ledger.return_value = datamanager_response + + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), + '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), 'rb') as f: + opener_content = f.read() + + with open(os.path.join( + os.path.dirname(os.path.realpath(__file__)), + '../../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), 'rb') as f: + description_content = f.read() + + mrequestsget.side_effect = [FakeRequest(status=status.HTTP_200_OK, + content=opener_content), + FakeRequest(status=status.HTTP_200_OK, + content=description_content)] + + search_params = '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7/' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(r, datamanager_response) + + def test_datamanager_retrieve_fail(self): + + dir_path = os.path.dirname(os.path.realpath(__file__)) + url = reverse('substrapp:data_manager-list') + + # PK hash < 64 chars + search_params = '42303efa663015e729159833a12ffb510ff/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # PK hash not hexa + search_params = 'X' * 64 + '/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') + + file_hash = get_hash(os.path.join(dir_path, + "../../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_datamanager_create_dryrun(self): + url = reverse('substrapp:data_manager-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + files = { + 'data_opener': open( + os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), + 'rb'), + + 'description': open( + os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), + 'rb')} + + data = { + 'name': 'ISIC 2018', + 'type': 'Images', + 'permissions': 'all', + 'dryrun': True + } + + response = self.client.post(url, {**data, **files}, format='multipart', **self.extra) + self.assertEqual(response.data, {'message': f'Your data opener is valid. You can remove the dryrun option.'}) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + for x in files: + files[x].close() diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py new file mode 100644 index 000000000..65fc6f220 --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -0,0 +1,216 @@ +import os +import shutil +import logging + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.views import DataSampleViewSet + +from substrapp.serializers import LedgerDataSampleSerializer + +from substrapp.views.datasample import path_leaf, compute_dryrun as data_sample_compute_dryrun +from substrapp.utils import get_hash + +from substrapp.models import DataManager + +from ..common import get_sample_datamanager +from ..common import FakeFilterDataManager, FakeTask, FakeDataManager + +MEDIA_ROOT = "/tmp/unittests_views/" + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(DRYRUN_ROOT=MEDIA_ROOT) +@override_settings(SITE_HOST='localhost') +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +@override_settings(DEFAULT_DOMAIN='https://localhost') +class DataSampleViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.data_description, self.data_description_filename, \ + self.data_data_opener, self.data_opener_filename = get_sample_datamanager() + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_data_create_bulk(self): + url = reverse('substrapp:data_sample-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + data_path1 = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_path2 = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') + + # dir hash + pkhash1 = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' + pkhash2 = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' + + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + + data = { + 'files': [path_leaf(data_path1), path_leaf(data_path2)], + path_leaf(data_path1): open(data_path1, 'rb'), + path_leaf(data_path2): open(data_path2, 'rb'), + 'data_manager_keys': data_manager_keys, + 'test_only': False + } + + with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + + mdatamanager.return_value = FakeFilterDataManager(1) + mcreate.return_value = ({'keys': [pkhash1, pkhash2]}, + status.HTTP_201_CREATED) + response = self.client.post(url, data=data, format='multipart', **self.extra) + self.assertEqual([r['pkhash'] for r in response.data], [pkhash1, pkhash2]) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + for x in data['files']: + data[x].close() + + def test_data_create_bulk_dryrun(self): + url = reverse('substrapp:data_sample-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + data_path1 = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_path2 = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') + + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + + data = { + 'files': [path_leaf(data_path1), path_leaf(data_path2)], + path_leaf(data_path1): open(data_path1, 'rb'), + path_leaf(data_path2): open(data_path2, 'rb'), + 'data_manager_keys': data_manager_keys, + 'test_only': False, + 'dryrun': True + } + + with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ + mock.patch.object(DataSampleViewSet, 'dryrun_task') as mdryrun_task: + + mdatamanager.return_value = FakeFilterDataManager(1) + mdryrun_task.return_value = ( + FakeTask('42'), + 'Your dry-run has been taken in account. You can follow the task execution on localhost') + response = self.client.post(url, data=data, format='multipart', **self.extra) + + self.assertEqual(response.data['id'], '42') + self.assertEqual(response.data['message'], + 'Your dry-run has been taken in account. You can follow the task execution on localhost') + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + for x in data['files']: + data[x].close() + + def test_data_create(self): + url = reverse('substrapp:data_sample-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + data_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + + # dir hash + pkhash = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' + + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + + data = { + 'file': open(data_path, 'rb'), + 'data_manager_keys': data_manager_keys, + 'test_only': False + } + + with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + + mdatamanager.return_value = FakeFilterDataManager(1) + mcreate.return_value = ({'keys': [pkhash]}, + status.HTTP_201_CREATED) + response = self.client.post(url, data=data, format='multipart', **self.extra) + + self.assertEqual(response.data[0]['pkhash'], pkhash) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + data['file'].close() + + def test_data_create_dryrun(self): + + url = reverse('substrapp:data_sample-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + data_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + + data = { + 'file': open(data_path, 'rb'), + 'data_manager_keys': data_manager_keys, + 'test_only': False, + 'dryrun': True + } + + with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ + mock.patch.object(DataSampleViewSet, 'dryrun_task') as mdryrun_task: + + mdatamanager.return_value = FakeFilterDataManager(1) + mdryrun_task.return_value = ( + FakeTask('42'), + 'Your dry-run has been taken in account. You can follow the task execution on localhost') + response = self.client.post(url, data=data, format='multipart', **self.extra) + + self.assertEqual(response.data['id'], '42') + self.assertEqual(response.data['message'], + 'Your dry-run has been taken in account. You can follow the task execution on localhost') + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + data['file'].close() + + def test_data_sample_compute_dryrun(self): + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + data_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + + shutil.copy(data_path, os.path.join(MEDIA_ROOT, '0024700.zip')) + + opener_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') + + pkhash = get_hash(data_path) + + data = { + 'filepath': os.path.join(MEDIA_ROOT, '0024700.zip'), + 'pkhash': pkhash, + } + + data_files = [data] + data_manager_keys = [get_hash(opener_path)] + + with mock.patch.object(DataManager.objects, 'get') as mdatamanager: + mdatamanager.return_value = FakeDataManager(opener_path) + data_sample_compute_dryrun(data_files, data_manager_keys) diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substrabac/substrapp/tests/views/tests_views_model.py new file mode 100644 index 000000000..b08f41e15 --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_model.py @@ -0,0 +1,165 @@ +import os +import shutil +import logging + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.utils import JsonException +from substrapp.utils import get_hash + +from ..common import get_sample_model +from ..common import FakeRequest +from ..assets import objective, datamanager, algo, model + +MEDIA_ROOT = "/tmp/unittests_views/" + + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +class ModelViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.model, self.model_filename = get_sample_model() + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_model_list_empty(self): + url = reverse('substrapp:model-list') + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(None, status.HTTP_200_OK), + (['ISIC'], status.HTTP_200_OK)] + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [[]]) + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [['ISIC']]) + + def test_model_list_filter_fail(self): + + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + + url = reverse('substrapp:model-list') + search_params = '?search=modeERRORl' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + self.assertIn('Malformed search filters', r['message']) + + def test_model_list_filter_hash(self): + + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + + pkhash = model[0]['traintuple']['outModel']['hash'] + url = reverse('substrapp:model-list') + search_params = f'?search=model%253Ahash%253A{pkhash}' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + self.assertEqual(len(r[0]), 1) + + def test_model_list_filter_datamanager(self): + url = reverse('substrapp:model-list') + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] + + search_params = '?search=dataset%253Aname%253AISIC%25202018' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_model_list_filter_objective(self): + url = reverse('substrapp:model-list') + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] + + search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_model_list_filter_algo(self): + url = reverse('substrapp:model-list') + with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(algo, status.HTTP_200_OK)] + + search_params = '?search=algo%253Aname%253ALogistic%2520regression' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_model_retrieve(self): + + with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger, \ + mock.patch('substrapp.views.model.get_from_node') as mrequestsget, \ + mock.patch('substrapp.views.model.ModelViewSet.compute_hash') as mcomputed_hash: + mget_object_from_ledger.return_value = model[0] + + mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, + content=self.model.read().encode()) + + mcomputed_hash.return_value = model[0]['traintuple']['outModel']['hash'] + + url = reverse('substrapp:model-list') + search_params = model[0]['traintuple']['outModel']['hash'] + '/' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + self.assertEqual(r, model[0]) + + def test_model_retrieve_fail(self): + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + url = reverse('substrapp:model-list') + + # PK hash < 64 chars + search_params = '42303efa663015e729159833a12ffb510ff/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # PK hash not hexa + search_params = 'X' * 64 + '/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') + + file_hash = get_hash(os.path.join(dir_path, + "../../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' + response = self.client.get(url + search_params, **self.extra) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py new file mode 100644 index 000000000..232ec610d --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -0,0 +1,274 @@ +import os +import shutil +import logging + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + + +from substrapp.serializers import LedgerObjectiveSerializer + +from substrapp.utils import JsonException +from substrapp.views.objective import compute_dryrun as objective_compute_dryrun +from substrapp.utils import compute_hash, get_hash + + +from ..common import get_sample_objective +from ..common import FakeRequest, FakeTask +from ..assets import objective, datamanager, traintuple, model + +MEDIA_ROOT = "/tmp/unittests_views/" + + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(DRYRUN_ROOT=MEDIA_ROOT) +@override_settings(SITE_HOST='localhost') +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +@override_settings(DEFAULT_DOMAIN='https://localhost') +class ObjectiveViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.objective_description, self.objective_description_filename, \ + self.objective_metrics, self.objective_metrics_filename = get_sample_objective() + + self.test_data_sample_keys = [ + "2d0f943aa81a9cb3fe84b162559ce6aff068ccb04e0cb284733b8f9d7e06517e", + "533ee6e7b9d8b247e7e853b24547f57e6ef351852bac0418f13a0666173448f1" + ] + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_objective_list_empty(self): + url = reverse('substrapp:objective-list') + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(None, status.HTTP_200_OK), + (['ISIC'], status.HTTP_200_OK)] + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [[]]) + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [['ISIC']]) + + def test_objective_list_filter_fail(self): + url = reverse('substrapp:objective-list') + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + + search_params = '?search=challenERRORge' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertIn('Malformed search filters', r['message']) + + def test_objective_list_filter_name(self): + url = reverse('substrapp:objective-list') + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + + search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 2) + + def test_objective_list_filter_metrics(self): + url = reverse('substrapp:objective-list') + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + + search_params = '?search=objective%253Ametrics%253Amacro-average%2520recall' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), len(objective)) + + def test_objective_list_filter_datamanager(self): + url = reverse('substrapp:objective-list') + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] + + search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_objective_list_filter_model(self): + url = reverse('substrapp:objective-list') + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: + mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] + + pkhash = model[0]['traintuple']['outModel']['hash'] + search_params = f'?search=model%253Ahash%253A{pkhash}' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_objective_retrieve(self): + url = reverse('substrapp:objective-list') + + with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger, \ + mock.patch('substrapp.views.objective.get_from_node') as mrequestsget: + mget_object_from_ledger.return_value = objective[0] + + with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), + '../../../../fixtures/owkin/objectives/objective0/description.md'), 'rb') as f: + content = f.read() + + mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, + content=content) + + search_params = f'{compute_hash(content)}/' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(r, objective[0]) + + def test_objective_retrieve_fail(self): + + dir_path = os.path.dirname(os.path.realpath(__file__)) + url = reverse('substrapp:objective-list') + + # PK hash < 64 chars + search_params = '42303efa663015e729159833a12ffb510ff/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # PK hash not hexa + search_params = 'X' * 64 + '/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') + + file_hash = get_hash(os.path.join(dir_path, + "../../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' + response = self.client.get(url + search_params, **self.extra) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_objective_create(self): + url = reverse('substrapp:objective-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + description_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/description.md') + metrics_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/metrics.py') + + pkhash = get_hash(description_path) + + test_data_manager_key = get_hash(os.path.join( + dir_path, '../../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) + + data = { + 'name': 'Simplified skin lesion classification', + 'description': open(description_path, 'rb'), + 'metrics_name': 'macro-average recall', + 'metrics': open(metrics_path, 'rb'), + 'permissions': 'all', + 'test_data_sample_keys': self.test_data_sample_keys, + 'test_data_manager_key': test_data_manager_key + } + + with mock.patch.object(LedgerObjectiveSerializer, 'create') as mcreate: + + mcreate.return_value = ({}, + status.HTTP_201_CREATED) + + response = self.client.post(url, data=data, format='multipart', **self.extra) + + self.assertEqual(response.data['pkhash'], pkhash) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + data['description'].close() + data['metrics'].close() + + def test_objective_create_dryrun(self): + + url = reverse('substrapp:objective-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + description_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/description.md') + metrics_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/metrics.py') + + test_data_manager_key = get_hash(os.path.join( + dir_path, '../../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) + + data = { + 'name': 'Simplified skin lesion classification', + 'description': open(description_path, 'rb'), + 'metrics_name': 'macro-average recall', + 'metrics': open(metrics_path, 'rb'), + 'permissions': 'all', + 'test_data_sample_keys': self.test_data_sample_keys, + 'test_data_manager_key': test_data_manager_key, + 'dryrun': True + } + + with mock.patch('substrapp.views.objective.compute_dryrun.apply_async') as mdryrun_task: + + mdryrun_task.return_value = FakeTask('42') + response = self.client.post(url, data=data, format='multipart', **self.extra) + + self.assertEqual(response.data['id'], '42') + self.assertEqual(response.data['message'], + 'Your dry-run has been taken in account. ' + 'You can follow the task execution on https://localhost/task/42/') + self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) + + data['description'].close() + data['metrics'].close() + + def test_objective_compute_dryrun(self): + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + metrics_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/metrics.py') + description_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/description.md') + shutil.copy(metrics_path, os.path.join(MEDIA_ROOT, 'metrics.py')) + + opener_path = os.path.join(dir_path, '../../../../fixtures/owkin/datamanagers/datamanager0/opener.py') + + with open(opener_path, 'rb') as f: + opener_content = f.read() + + pkhash = get_hash(description_path) + + test_data_manager_key = compute_hash(opener_content) + + with mock.patch('substrapp.views.objective.get_object_from_ledger') as mdatamanager,\ + mock.patch('substrapp.views.objective.get_computed_hash') as mopener: + mdatamanager.return_value = {'opener': {'storageAddress': 'test'}} + mopener.return_value = (opener_content, pkhash) + objective_compute_dryrun(os.path.join(MEDIA_ROOT, 'metrics.py'), test_data_manager_key, pkhash) diff --git a/substrabac/substrapp/tests/views/tests_views_task.py b/substrabac/substrapp/tests/views/tests_views_task.py new file mode 100644 index 000000000..d53a97ff5 --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_task.py @@ -0,0 +1,63 @@ +import os +import shutil +import logging + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from ..common import FakeAsyncResult + +MEDIA_ROOT = "/tmp/unittests_views/" + + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +class TaskViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_task_retrieve(self): + + url = reverse('substrapp:task-detail', kwargs={'pk': 'pk'}) + with mock.patch('substrapp.views.task.AsyncResult') as mAsyncResult: + mAsyncResult.return_value = FakeAsyncResult(status='SUCCESS') + response = self.client.get(url, **self.extra) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_task_retrieve_fail(self): + url = reverse('substrapp:task-detail', kwargs={'pk': 'pk'}) + with mock.patch('substrapp.views.task.AsyncResult') as mAsyncResult: + mAsyncResult.return_value = FakeAsyncResult() + response = self.client.get(url, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_task_retrieve_pending(self): + url = reverse('substrapp:task-detail', kwargs={'pk': 'pk'}) + with mock.patch('substrapp.views.task.AsyncResult') as mAsyncResult: + mAsyncResult.return_value = FakeAsyncResult(status='PENDING', successful=False) + response = self.client.get(url, **self.extra) + self.assertEqual(response.data['message'], + 'Task is either waiting, does not exist in this context or has been removed after 24h') + + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/substrabac/substrapp/tests/views/tests_views_tuples.py b/substrabac/substrapp/tests/views/tests_views_tuples.py new file mode 100644 index 000000000..bc4280939 --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_tuples.py @@ -0,0 +1,163 @@ +import os +import shutil +import logging + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.views import TrainTupleViewSet, TestTupleViewSet + +from substrapp.utils import JsonException +from substrapp.utils import get_hash + + +from ..assets import traintuple, testtuple + +MEDIA_ROOT = "/tmp/unittests_views/" + + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +class TraintupleViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_traintuple_queryset(self): + traintuple_view = TrainTupleViewSet() + self.assertFalse(traintuple_view.get_queryset()) + + def test_traintuple_list_empty(self): + url = reverse('substrapp:traintuple-list') + with mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: + mquery_ledger.return_value = ([[]], status.HTTP_200_OK) + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [[]]) + + def test_traintuple_retrieve(self): + + with mock.patch('substrapp.views.traintuple.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = traintuple[0] + url = reverse('substrapp:traintuple-list') + search_params = 'c164f4c714a78c7e2ba2016de231cdd41e3eac61289e08c1f711e74915a0868f/' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + self.assertEqual(r, traintuple[0]) + + def test_traintuple_retrieve_fail(self): + + dir_path = os.path.dirname(os.path.realpath(__file__)) + url = reverse('substrapp:traintuple-list') + + # PK hash < 64 chars + search_params = '42303efa663015e729159833a12ffb510ff/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # PK hash not hexa + search_params = 'X' * 64 + '/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + with mock.patch('substrapp.views.traintuple.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') + + file_hash = get_hash(os.path.join(dir_path, + "../../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' + response = self.client.get(url + search_params, **self.extra) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +class TesttupleViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_testtuple_queryset(self): + testtuple_view = TestTupleViewSet() + self.assertFalse(testtuple_view.get_queryset()) + + def test_testtuple_list_empty(self): + url = reverse('substrapp:testtuple-list') + with mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: + mquery_ledger.return_value = ([[]], status.HTTP_200_OK) + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [[]]) + + def test_testtuple_retrieve(self): + + with mock.patch('substrapp.views.testtuple.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = testtuple[0] + url = reverse('substrapp:testtuple-list') + search_params = 'c164f4c714a78c7e2ba2016de231cdd41e3eac61289e08c1f711e74915a0868f/' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + self.assertEqual(r, testtuple[0]) + + def test_testtuple_retrieve_fail(self): + + dir_path = os.path.dirname(os.path.realpath(__file__)) + url = reverse('substrapp:testtuple-list') + + # PK hash < 64 chars + search_params = '42303efa663015e729159833a12ffb510ff/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + # PK hash not hexa + search_params = 'X' * 64 + '/' + response = self.client.get(url + search_params, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + with mock.patch('substrapp.views.testtuple.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.side_effect = JsonException('TEST') + + file_hash = get_hash(os.path.join(dir_path, + "../../../../fixtures/owkin/objectives/objective0/description.md")) + search_params = f'{file_hash}/' + response = self.client.get(url + search_params, **self.extra) + + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) From 48abd10400891f3fce17f927341fc203a53aeefd Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Wed, 5 Jun 2019 14:56:20 +0200 Subject: [PATCH 076/457] Update serializers to json format --- .../serializers/ledger/algo/serializer.py | 26 +++++---------- .../ledger/datamanager/serializer.py | 32 ++++++------------- .../ledger/datasample/serializer.py | 17 +++------- .../ledger/objective/serializer.py | 32 ++++++------------- .../ledger/testtuple/serializer.py | 20 ++++-------- .../ledger/traintuple/serializer.py | 32 ++++++------------- 6 files changed, 49 insertions(+), 110 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/algo/serializer.py b/substrabac/substrapp/serializers/ledger/algo/serializer.py index 85d6a7945..d283c27f1 100644 --- a/substrabac/substrapp/serializers/ledger/algo/serializer.py +++ b/substrabac/substrapp/serializers/ledger/algo/serializer.py @@ -26,24 +26,14 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = request.get_host() - # Json - # args = { - # 'name': name, - # 'algoHash': get_hash(instance.file), - # 'storageAddress': protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), - # 'descriptionHash': get_hash(instance.description), - # 'descriptionStorageAddress': protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), - # 'permissions': permissions - # } - - args = [ - name, - get_hash(instance.file), - protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), - get_hash(instance.description), - protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), - permissions, - ] + args = { + 'name': name, + 'hash': get_hash(instance.file), + 'storageAddress': protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), + 'descriptionHash': get_hash(instance.description), + 'descriptionStorageAddress': protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), + 'permissions': permissions + } if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerAlgo(args, instance.pkhash, sync=True) diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py index 684724e3d..f49fac4d5 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py @@ -30,28 +30,16 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = request.get_host() - # Json - # args = { - # 'name': name, - # 'openerHash': get_hash(instance.data_opener), - # 'openerStorageAddress': protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), - # 'type': data_type, - # 'descriptionHash': get_hash(instance.description), - # 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), # noqa - # 'objectiveKey': objective_key, - # 'permissions': permissions - # } - - args = [ - name, - get_hash(instance.data_opener), - protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), - data_type, - get_hash(instance.description), - protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), - objective_key, - permissions - ] + args = { + 'name': name, + 'openerHash': get_hash(instance.data_opener), + 'openerStorageAddress': protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), + 'type': data_type, + 'descriptionHash': get_hash(instance.description), + 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), + 'objectiveKey': objective_key, + 'permissions': permissions + } if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerDataManager(args, instance.pkhash, sync=True) diff --git a/substrabac/substrapp/serializers/ledger/datasample/serializer.py b/substrabac/substrapp/serializers/ledger/datasample/serializer.py index 7cddd2c95..654a2f09a 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datasample/serializer.py @@ -18,18 +18,11 @@ def create(self, validated_data): data_manager_keys = validated_data.get('data_manager_keys') test_only = validated_data.get('test_only') - # Json - # args = { - # 'hashes': ','.join([x.pk for x in instances]), - # 'dataManagerKeys': ','.join([x for x in data_manager_keys]), - # 'testOnly': json.dumps(test_only), - # } - - args = [ - ','.join([x.pk for x in instances]), - ','.join([x for x in data_manager_keys]), - json.dumps(test_only), - ] + args = { + 'hashes': ','.join([x.pk for x in instances]), + 'dataManagerKeys': ','.join([x for x in data_manager_keys]), + 'testOnly': json.dumps(test_only), + } if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerDataSample(args, [x.pk for x in instances], sync=True) diff --git a/substrabac/substrapp/serializers/ledger/objective/serializer.py b/substrabac/substrapp/serializers/ledger/objective/serializer.py index cd9d5ffaf..bf08746cc 100644 --- a/substrabac/substrapp/serializers/ledger/objective/serializer.py +++ b/substrabac/substrapp/serializers/ledger/objective/serializer.py @@ -34,28 +34,16 @@ def create(self, validated_data): protocol = 'https://' if request.is_secure() else 'http://' host = request.get_host() - # Json - # args = { - # 'name': name, - # 'descriptionHash': get_hash(instance.description), - # 'descriptionStorageAddress': protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), # noqa - # 'metricsName': metrics_name, - # 'metricsHash': get_hash(instance.metrics), - # 'metricsStorageAddress': protocol + host + reverse('substrapp:objective-metrics', args=[instance.pk]), - # 'testDataSample': f'{test_data_manager_key}:{",".join([x for x in test_data_sample_keys])}', - # 'permissions': permissions - # } - - args = [ - name, - get_hash(instance.description), - protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), - metrics_name, - get_hash(instance.metrics), - protocol + host + reverse('substrapp:objective-metrics', args=[instance.pk]), - f'{test_data_manager_key}:{",".join([x for x in test_data_sample_keys])}', - permissions - ] + args = { + 'name': name, + 'descriptionHash': get_hash(instance.description), + 'descriptionStorageAddress': protocol + host + reverse('substrapp:objective-description', args=[instance.pk]), # noqa + 'metricsName': metrics_name, + 'metricsHash': get_hash(instance.metrics), + 'metricsStorageAddress': protocol + host + reverse('substrapp:objective-metrics', args=[instance.pk]), + 'testDataset': f'{test_data_manager_key}:{",".join([x for x in test_data_sample_keys])}', + 'permissions': permissions + } if getattr(settings, 'LEDGER_SYNC_ENABLED'): return createLedgerObjective(args, instance.pkhash, sync=True) diff --git a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py index 2ada1638a..72adcb7f3 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py @@ -20,20 +20,12 @@ def get_args(self, validated_data): test_data_sample_keys = validated_data.get('test_data_sample_keys', []) tag = validated_data.get('tag', '') - # Json - # args = { - # 'traintupleKey': traintuple_key, - # 'dataManagerKey': data_manager_key, - # 'dataSampleKeys': ','.join(test_data_sample_keys), - # 'tag': tag - # } - - args = [ - traintuple_key, - data_manager_key, - ','.join([x for x in test_data_sample_keys]), - tag - ] + args = { + 'traintupleKey': traintuple_key, + 'dataManagerKey': data_manager_key, + 'dataSampleKeys': ','.join(test_data_sample_keys), + 'tag': tag + } return args diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index cbb4de2df..beb2607a3 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -31,28 +31,16 @@ def get_args(self, validated_data): in_models_keys = validated_data.get('in_models_keys', []) tag = validated_data.get('tag', '') - # Json - # args = { - # 'algoKey': algo_key, - # 'associatedObjective': objective_key, - # 'inModels': ','.join(in_models_keys), - # 'dataManagerKey': data_manager_key, - # 'dataSampleKeys': ','.join(train_data_sample_keys), - # 'FLtask': FLtask_key, - # 'rank': str(rank), - # 'tag': tag - # } - - args = [ - algo_key, - objective_key, - ','.join([x for x in in_models_keys]), - data_manager_key, - ','.join([x for x in train_data_sample_keys]), - FLtask_key, - str(rank), - tag, - ] + args = { + 'algoKey': algo_key, + 'objectiveKey': objective_key, + 'inModels': ','.join([x for x in in_models_keys]), + 'dataManagerKey': data_manager_key, + 'dataSampleKeys': ','.join([x for x in train_data_sample_keys]), + 'flTask': FLtask_key, + 'rank': str(rank), + 'tag': tag + } return args From 5c5182de85c67f5d8ac1862072fa02b0b1d60a2b Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Wed, 5 Jun 2019 15:28:17 +0200 Subject: [PATCH 077/457] Switch last smart contract to JSON --- substrabac/substrapp/ledger_utils.py | 44 +++++++++++++------ .../ledger/datamanager/serializer.py | 3 +- .../serializers/ledger/datamanager/util.py | 4 ++ .../serializers/ledger/datasample/util.py | 4 ++ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 5780549ca..cd185d2af 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -17,6 +17,8 @@ def query_ledger(fcn, args=None): if args is None: args = [] + else: + args = [json.dumps(args)] peer = LEDGER['peer'] loop = LEDGER['hfc']['loop'] @@ -90,7 +92,7 @@ def query_ledger(fcn, args=None): def get_object_from_ledger(pk, query): # get instance from remote node - data, st = query_ledger(fcn=query, args=[f'{pk}']) + data, st = query_ledger(fcn=query, args={'key': pk}) if st == status.HTTP_404_NOT_FOUND: raise Http404('Not found') @@ -105,6 +107,8 @@ def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): if args is None: args = [] + else: + args = [json.dumps(args)] peer = LEDGER['peer'] loop = LEDGER['hfc']['loop'] @@ -181,7 +185,10 @@ def log_fail_tuple(tuple_type, tuple_key, err_msg): data, st = invoke_ledger( fcn=fail_type, - args=[f'{tuple_key}', f'{err_msg}'], + args={ + 'key': tuple_key, + 'log': err_msg, + }, sync=True) return data, st @@ -190,18 +197,24 @@ def log_fail_tuple(tuple_type, tuple_key, err_msg): def log_success_tuple(tuple_type, tuple_key, res): if tuple_type == 'traintuple': invoke_fcn = 'logSuccessTrain' - # TODO: will be replace by a dict - invoke_args = [f'{tuple_key}', - f'{res["end_model_file_hash"]}, {res["end_model_file"]}', - f'{res["global_perf"]}', - f'Train - {res["job_task_log"]};'] + invoke_args = { + 'key': tuple_key, + 'outModel': { + 'hash': f'{res["end_model_file_hash"]}', + 'storageAddress': f'{res["end_model_file"]}', + }, + 'perf': f'{res["global_perf"]}', + 'log': f'Train - {res["job_task_log"]};', + } elif tuple_type == 'testtuple': invoke_fcn = 'logSuccessTest' - # TODO: will be replace by a dict - invoke_args = [f'{tuple_key}', - f'{res["global_perf"]}', - f'Test - {res["job_task_log"]};'] + invoke_args = { + 'key': tuple_key, + 'perf': f'{res["global_perf"]}', + 'log': f'Test - {res["job_task_log"]};', + } + else: raise NotImplementedError() @@ -222,7 +235,7 @@ def log_start_tuple(tuple_type, tuple_key): data, st = invoke_ledger( fcn=start_type, - args=[f'{tuple_key}'], + args={'key': tuple_key}, sync=True) return data, st @@ -231,6 +244,9 @@ def log_start_tuple(tuple_type, tuple_key): def query_tuples(tuple_type, data_owner): tuples, st = query_ledger( fcn="queryFilter", - args=[f'{tuple_type}~worker~status', f'{data_owner},todo']) - + args={ + 'indexName': f'{tuple_type}~worker~status', + 'attributes': f'{data_owner},todo' + } + ) return tuples, st diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py index f49fac4d5..22f8302e6 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py @@ -36,7 +36,8 @@ def create(self, validated_data): 'openerStorageAddress': protocol + host + reverse('substrapp:data_manager-opener', args=[instance.pk]), 'type': data_type, 'descriptionHash': get_hash(instance.description), - 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), + 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', + args=[instance.pk]), 'objectiveKey': objective_key, 'permissions': permissions } diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substrabac/substrapp/serializers/ledger/datamanager/util.py index 88fac77b9..dd38478b1 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/util.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/util.py @@ -29,4 +29,8 @@ def createLedgerDataManager(args, pkhash, sync=False): def updateLedgerDataManager(args, sync=False): + args = { + 'dataManagerKey': args[0], + 'objectiveKey': args[1], + } return invoke_ledger(fcn='updateDataManager', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substrabac/substrapp/serializers/ledger/datasample/util.py index 573744892..f4f8c60f2 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/util.py +++ b/substrabac/substrapp/serializers/ledger/datasample/util.py @@ -28,4 +28,8 @@ def createLedgerDataSample(args, pkhashes, sync=False): def updateLedgerDataSample(args, sync=False): + args = { + 'hashes': args[0], + 'dataManagerKeys': args[1], + } return invoke_ledger(fcn='updateDataSample', args=args, sync=sync) From 513056331c6f1b2513fa783dd2804caa4a81d0b1 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 5 Jun 2019 15:53:41 +0200 Subject: [PATCH 078/457] Performance in float. --- substrabac/substrapp/ledger_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index cd185d2af..57f70dbdd 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -203,7 +203,7 @@ def log_success_tuple(tuple_type, tuple_key, res): 'hash': f'{res["end_model_file_hash"]}', 'storageAddress': f'{res["end_model_file"]}', }, - 'perf': f'{res["global_perf"]}', + 'perf': float(res["global_perf"]), 'log': f'Train - {res["job_task_log"]};', } @@ -211,7 +211,7 @@ def log_success_tuple(tuple_type, tuple_key, res): invoke_fcn = 'logSuccessTest' invoke_args = { 'key': tuple_key, - 'perf': f'{res["global_perf"]}', + 'perf': float(res["global_perf"]), 'log': f'Test - {res["job_task_log"]};', } From 18c5da4c1f47db09f4672e7be06c8699e565ca12 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 5 Jun 2019 16:58:45 +0200 Subject: [PATCH 079/457] Complete view tests. --- .../substrapp/tests/views/tests_views_algo.py | 12 +++ .../tests/views/tests_views_datasample.py | 89 ++++++++++++++----- substrabac/substrapp/views/filters_utils.py | 1 + 3 files changed, 78 insertions(+), 24 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index 68755c13c..0e6e812d6 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -84,6 +84,18 @@ def test_algo_list_filter_name(self): self.assertEqual(len(r[0]), 1) + def test_algo_list_filter_dual(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + + search_params = '?search=algo%253Aname%253ALogistic%2520regression' + search_params += f'%2Calgo%253Aowner%253A{algo[0]["owner"]}' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + def test_algo_list_filter_datamanager_fail(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 65fc6f220..2dc8bc53d 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -10,17 +10,16 @@ from rest_framework import status from rest_framework.test import APITestCase -from substrapp.views import DataSampleViewSet from substrapp.serializers import LedgerDataSampleSerializer from substrapp.views.datasample import path_leaf, compute_dryrun as data_sample_compute_dryrun -from substrapp.utils import get_hash +from substrapp.utils import get_hash, uncompress_content from substrapp.models import DataManager from ..common import get_sample_datamanager -from ..common import FakeFilterDataManager, FakeTask, FakeDataManager +from ..common import FakeFilterDataManager, FakeDataManager MEDIA_ROOT = "/tmp/unittests_views/" @@ -88,6 +87,12 @@ def test_data_create_bulk(self): for x in data['files']: data[x].close() + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) def test_data_create_bulk_dryrun(self): url = reverse('substrapp:data_sample-list') @@ -96,8 +101,9 @@ def test_data_create_bulk_dryrun(self): data_path1 = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') data_path2 = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') - data_manager_keys = [ - get_hash(os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + opener_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') + + data_manager_keys = [get_hash(opener_path)] data = { 'files': [path_leaf(data_path1), path_leaf(data_path2)], @@ -109,17 +115,14 @@ def test_data_create_bulk_dryrun(self): } with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ - mock.patch.object(DataSampleViewSet, 'dryrun_task') as mdryrun_task: - + mock.patch.object(DataManager.objects, 'get') as mgetdatamanager: mdatamanager.return_value = FakeFilterDataManager(1) - mdryrun_task.return_value = ( - FakeTask('42'), - 'Your dry-run has been taken in account. You can follow the task execution on localhost') + mgetdatamanager.return_value = FakeDataManager(opener_path) + response = self.client.post(url, data=data, format='multipart', **self.extra) - self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], - 'Your dry-run has been taken in account. You can follow the task execution on localhost') + self.assertIn('Your dry-run has been taken in account. You can follow the task execution on ', + response.data['message']) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) for x in data['files']: @@ -157,17 +160,59 @@ def test_data_create(self): data['file'].close() - def test_data_create_dryrun(self): - + def test_data_create_path(self): url = reverse('substrapp:data_sample-list') dir_path = os.path.dirname(os.path.realpath(__file__)) - data_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_zip_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_path = os.path.join(MEDIA_ROOT, '0024700') + + with open(data_zip_path, 'rb') as data_zip: + uncompress_content(data_zip.read(), data_path) + + # dir hash + pkhash = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' data_manager_keys = [ get_hash(os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + data = { + 'path': data_path, + 'data_manager_keys': data_manager_keys, + 'test_only': False + } + + with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + + mdatamanager.return_value = FakeFilterDataManager(1) + mcreate.return_value = ({'keys': [pkhash]}, + status.HTTP_201_CREATED) + response = self.client.post(url, data=data, format='multipart', **self.extra) + + self.assertEqual(response.data[0]['pkhash'], pkhash) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + + @override_settings( + task_eager_propagates=True, + task_always_eager=True, + broker_url='memory://', + backend='memory' + ) + def test_data_create_dryrun(self): + + url = reverse('substrapp:data_sample-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + data_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.tar.gz') + + opener_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') + + data_manager_keys = [get_hash(opener_path)] + data = { 'file': open(data_path, 'rb'), 'data_manager_keys': data_manager_keys, @@ -176,17 +221,13 @@ def test_data_create_dryrun(self): } with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ - mock.patch.object(DataSampleViewSet, 'dryrun_task') as mdryrun_task: - + mock.patch.object(DataManager.objects, 'get') as mgetdatamanager: mdatamanager.return_value = FakeFilterDataManager(1) - mdryrun_task.return_value = ( - FakeTask('42'), - 'Your dry-run has been taken in account. You can follow the task execution on localhost') + mgetdatamanager.return_value = FakeDataManager(opener_path) response = self.client.post(url, data=data, format='multipart', **self.extra) - self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], - 'Your dry-run has been taken in account. You can follow the task execution on localhost') + self.assertIn('Your dry-run has been taken in account. You can follow the task execution on ', + response.data['message']) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) data['file'].close() diff --git a/substrabac/substrapp/views/filters_utils.py b/substrabac/substrapp/views/filters_utils.py index ca68bf3e6..a3b255008 100644 --- a/substrabac/substrapp/views/filters_utils.py +++ b/substrabac/substrapp/views/filters_utils.py @@ -24,6 +24,7 @@ def get_filters(query_params): filters = [] groups = query_params.split('-OR-') + for idx, group in enumerate(groups): # init From ed03d9b9783c6aca5fb867fcfe32ac429efe5bfc Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 6 Jun 2019 08:07:19 +0200 Subject: [PATCH 080/457] Refacto ledger_utils and update tests. --- substrabac/substrapp/ledger_utils.py | 152 +++++++----------- substrabac/substrapp/tests/tests_misc.py | 68 ++++++++ .../tests/views/tests_views_datasample.py | 1 - 3 files changed, 124 insertions(+), 97 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 57f70dbdd..c6c79fbd3 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -12,10 +12,8 @@ asyncio.set_event_loop(LEDGER['hfc']['loop']) -# careful, passing invoke parameters to query_ledger will NOT fail -def query_ledger(fcn, args=None): - - if args is None: +def call_ledger(call_type, fcn, args=None, kwargs=None): + if not args: args = [] else: args = [json.dumps(args)] @@ -23,6 +21,10 @@ def query_ledger(fcn, args=None): peer = LEDGER['peer'] loop = LEDGER['hfc']['loop'] client = LEDGER['hfc']['client'] + chaincode_calls = { + 'invoke': client.chaincode_invoke, + 'query': client.chaincode_query, + } requestor = LEDGER['hfc']['requestor'] channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] @@ -40,31 +42,49 @@ def query_ledger(fcn, args=None): if cc.name == chaincode_name: chaincode_version = cc.version + params = { + 'requestor': requestor, + 'channel_name': channel_name, + 'peers': [peer['name']], + 'args': args, + 'cc_name': chaincode_name, + 'cc_version': chaincode_version, + 'fcn': fcn + } + + if kwargs is not None and isinstance(kwargs, dict): + params.update(kwargs) + try: - # Async - need loop - response = loop.run_until_complete( - client.chaincode_query( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - args=args, - cc_name=chaincode_name, - cc_version=chaincode_version, - fcn=fcn)) + response = loop.run_until_complete(chaincode_calls[call_type](**params)) + except TimeoutError as e: + # Only for invoke + st = status.HTTP_408_REQUEST_TIMEOUT + data = {'message': str(e)} except Exception as e: st = status.HTTP_400_BAD_REQUEST data = {'message': str(e)} else: - msg = f'Query of channel \'{channel_name}\' on the peer \'{peer["host"]}\' was successful\n' - print(msg, flush=True) - st = status.HTTP_200_OK + if call_type == 'invoke': + st = status.HTTP_201_CREATED + elif call_type == 'query': + st = status.HTTP_200_OK + else: + raise NotImplementedError() # TO DO : review parsing error in case of failure # May have changed by using fabric-sdk-py + try: - # json transformation if needed - data = json.loads(response) + response = json.loads(response) + if call_type == 'invoke': + pkhash = response.get('key', response.get('keys')) + data = {'pkhash': pkhash} + elif call_type == 'query': + data = response + else: + raise NotImplementedError() except json.decoder.JSONDecodeError: st = status.HTTP_400_BAD_REQUEST @@ -79,7 +99,6 @@ def query_ledger(fcn, args=None): # TODO: get 409 from the chaincode if 'message' in data and 'tkey' in data['message']: pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if len(pkhash) == 64: st = status.HTTP_409_CONFLICT data['pkhash'] = pkhash @@ -87,7 +106,23 @@ def query_ledger(fcn, args=None): if 'permissions' in data and data['permissions'] != 'all': raise Exception('Not Allowed') - return data, st + return data, st + + +def query_ledger(fcn, args=None): + # careful, passing invoke parameters to query_ledger will NOT fail + return call_ledger('query', fcn=fcn, args=args) + + +def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): + params = { + 'wait_for_event': sync, + 'wait_for_event_timeout': 45, + } + if cc_pattern: + params['cc_pattern'] = cc_pattern + + return call_ledger('invoke', fcn=fcn, args=args, kwargs=params) def get_object_from_ledger(pk, query): @@ -103,81 +138,6 @@ def get_object_from_ledger(pk, query): return data -def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): - - if args is None: - args = [] - else: - args = [json.dumps(args)] - - peer = LEDGER['peer'] - loop = LEDGER['hfc']['loop'] - client = LEDGER['hfc']['client'] - requestor = LEDGER['hfc']['requestor'] - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - - # Get chaincode version - response = loop.run_until_complete( - client.query_instantiated_chaincodes( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - decode=True - )) - for ccs in response: - for cc in ccs.chaincodes: - if cc.name == chaincode_name: - chaincode_version = cc.version - - try: - # Async - need loop - kwargs = { - 'requestor': requestor, - 'channel_name': channel_name, - 'peers': [peer['name']], - 'args': args, - 'cc_name': chaincode_name, - 'cc_version': chaincode_version, - 'fcn': fcn, - 'wait_for_event': sync, - 'wait_for_event_timeout': 45 - } - if cc_pattern: - kwargs['cc_pattern'] = cc_pattern - - response = loop.run_until_complete(client.chaincode_invoke(**kwargs)) - except TimeoutError as e: - st = status.HTTP_408_REQUEST_TIMEOUT - data = {'message': str(e)} - except Exception as e: - st = status.HTTP_400_BAD_REQUEST - data = {'message': str(e)} - else: - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - # elif 'access denied' in msg or 'authentication handshake failed' in msg: - # st = status.HTTP_403_FORBIDDEN - - st = status.HTTP_201_CREATED - try: - response = json.loads(response) - pkhash = response.get('key', response.get('keys')) - data = {'pkhash': pkhash} - except json.decoder.JSONDecodeError: - st = status.HTTP_400_BAD_REQUEST - data = {'message': response} - - # TODO: get 409 from the chaincode - if 'message' in data and 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if len(pkhash) == 64: - st = status.HTTP_409_CONFLICT - data['pkhash'] = pkhash - - return data, st - - def log_fail_tuple(tuple_type, tuple_key, err_msg): err_msg = str(err_msg).replace('"', "'").replace('\\', "").replace('\\n', "")[:200] diff --git a/substrabac/substrapp/tests/tests_misc.py b/substrabac/substrapp/tests/tests_misc.py index 37b974da7..4c61b5d99 100644 --- a/substrabac/substrapp/tests/tests_misc.py +++ b/substrabac/substrapp/tests/tests_misc.py @@ -6,6 +6,13 @@ from substrapp.tests.common import JobStats, Stats, gpu +from rest_framework import status +from django.http import Http404 +from substrapp.utils import JsonException + +from substrapp.ledger_utils import get_object_from_ledger, log_fail_tuple, log_start_tuple, \ + log_success_tuple, query_tuples + class MockDevice(): """A mock device to temporarily suppress output to stdout @@ -69,3 +76,64 @@ def test_update_statistics(self): self.assertNotEqual(job_statistics['memory']['max'], 0) self.assertNotEqual(job_statistics['cpu']['max'], 0) self.assertNotEqual(job_statistics['netio']['rx'], 0) + + def test_get_object_from_ledger(self): + with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.return_value = {'key': 'pk'}, status.HTTP_404_NOT_FOUND + + self.assertRaises(Http404, get_object_from_ledger, 'pk', 'fake_query') + + with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.return_value = {'key': 'pk'}, status.HTTP_400_BAD_REQUEST + self.assertRaises(JsonException, get_object_from_ledger, 'pk', 'fake_query') + + with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.return_value = {'key': 'pk'}, status.HTTP_200_OK + data = get_object_from_ledger('pk', 'good_query') + self.assertEqual(data['key'], 'pk') + + def test_log_fail_tuple(self): + with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = None, status.HTTP_200_OK + data, st = log_fail_tuple('traintuple', 'pk', 'error_msg') + + with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = None, status.HTTP_200_OK + data, st = log_fail_tuple('testtuple', 'pk', 'error_msg') + + def test_log_start_tuple(self): + with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = None, status.HTTP_200_OK + data, st = log_start_tuple('traintuple', 'pk') + + with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = None, status.HTTP_200_OK + data, st = log_start_tuple('testtuple', 'pk') + + def test_log_success_tuple(self): + with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = None, status.HTTP_200_OK + res = { + 'end_model_file_hash': 'hash', + 'end_model_file': 'storageAddress', + 'global_perf': '0.99', + 'job_task_log': 'log', + } + data, st = log_success_tuple('traintuple', 'pk', res) + + with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = None, status.HTTP_200_OK + res = { + 'global_perf': '0.99', + 'job_task_log': 'log', + } + data, st = log_success_tuple('testtuple', 'pk', res) + + def test_query_tuples(self): + with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.return_value = None, status.HTTP_200_OK + data, st = query_tuples('traintuple', 'data_owner') + + with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: + mquery_ledger.return_value = None, status.HTTP_200_OK + data, st = query_tuples('testtuple', 'data_owner') diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 2dc8bc53d..61641ccc3 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -194,7 +194,6 @@ def test_data_create_path(self): self.assertEqual(response.data[0]['pkhash'], pkhash) self.assertEqual(response.status_code, status.HTTP_201_CREATED) - @override_settings( task_eager_propagates=True, task_always_eager=True, From ad7dde51ce3f16506ad9010cbf8ecfff03b2cbf7 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 6 Jun 2019 11:26:55 +0200 Subject: [PATCH 081/457] Complete test tasks --- substrabac/substrapp/tests/tests_tasks.py | 174 ++++++++++++++++++++-- 1 file changed, 160 insertions(+), 14 deletions(-) diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 4e77163fb..7cc63b84f 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -3,18 +3,20 @@ import mock import time import uuid +from unittest.mock import MagicMock from django.test import override_settings from django.http import HttpResponse from rest_framework import status from rest_framework.test import APITestCase +from django_celery_results.models import TaskResult from substrapp.models import DataSample from substrapp.utils import compute_hash, get_computed_hash, get_remote_file, get_hash, create_directory from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, put_model, put_models, put_algo, put_metric, put_data_sample, prepare_task, do_task, - compute_task) + compute_task, remove_subtuple_materials, prepare_materials) from .common import (get_sample_algo, get_sample_script, get_sample_zip_data_sample, get_sample_tar_data_sample, get_sample_model) @@ -53,7 +55,14 @@ def test_create_directory(self): directory = './test/' create_directory(directory) self.assertTrue(os.path.exists(directory)) - shutil.rmtree(directory) + remove_subtuple_materials(directory) + self.assertFalse(os.path.exists(directory)) + + # Remove a second time, it should not raise exception + try: + remove_subtuple_materials(directory) + except Exception: + self.fail('`remove_subtuple_materials` raised Exception unexpectedly!') def test_get_computed_hash(self): with mock.patch('substrapp.utils.requests.get') as mget: @@ -166,6 +175,8 @@ def test_put_opener(self): f.write(self.script.read()) self.assertTrue(os.path.exists(filepath)) + opener_hash = get_hash(filepath) + opener_directory = os.path.join(self.subtuple_path, 'opener') create_directory(opener_directory) @@ -177,9 +188,22 @@ def test_put_opener(self): put_opener({'dataset': {'openerHash': 'HASH'}}, self.subtuple_path) # test work - put_opener({'dataset': {'openerHash': get_hash(filepath)}}, self.subtuple_path) + put_opener({'dataset': {'openerHash': opener_hash}}, self.subtuple_path) + + opener_path = os.path.join(opener_directory, 'opener.py') + self.assertTrue(os.path.exists(opener_path)) + + # test corrupted + + os.remove(opener_path) + shutil.copyfile(filepath, opener_path) + + # Corrupted + with open(opener_path, 'a+') as f: + f.write('corrupted') - self.assertTrue(os.path.exists(os.path.join(opener_directory, 'opener.py'))) + with self.assertRaises(Exception): + put_opener({'dataset': {'openerHash': opener_hash}}, self.subtuple_path) def test_put_data_sample_zip(self): @@ -194,9 +218,9 @@ def test_put_data_sample_zip(self): with mock.patch('substrapp.models.DataSample.objects.get') as mget: mget.return_value = data_sample - subtuple_direcory = build_subtuple_folders(subtuple) + subtuple_directory = build_subtuple_folders(subtuple) - put_data_sample(subtuple, subtuple_direcory) + put_data_sample(subtuple, subtuple_directory) # check folder has been correctly renamed with pk of directory containing uncompressed data sample self.assertFalse( @@ -215,6 +239,32 @@ def test_put_data_sample_zip(self): self.assertTrue(os.path.exists(os.path.join( MEDIA_ROOT, 'subtuple/bar/data', data_sample.pk, 'IMG_0024900.jpg'))) + def test_put_data_sample_zip_fail(self): + + data_sample = DataSample(pkhash='foo', path=self.data_sample) + data_sample.save() + + subtuple = { + 'key': 'bar', + 'dataset': {'keys': ['fake_pk']} + } + + subtuple2 = { + 'key': 'bar', + 'dataset': {'keys': [data_sample.pk]} + } + + with mock.patch('substrapp.models.DataSample.objects.get') as mget: + mget.return_value = data_sample + + subtuple_directory = build_subtuple_folders(subtuple) + + with self.assertRaises(Exception): + put_data_sample(subtuple, subtuple_directory) + + with self.assertRaises(Exception): + put_data_sample(subtuple2, '/fake/directory/failure') + def test_put_data_tar(self): data_sample = DataSample(pkhash='foo', path=self.data_sample_tar) @@ -228,9 +278,9 @@ def test_put_data_tar(self): with mock.patch('substrapp.models.DataSample.objects.get') as mget: mget.return_value = data_sample - subtuple_direcory = build_subtuple_folders(subtuple) + subtuple_directory = build_subtuple_folders(subtuple) - put_data_sample(subtuple, subtuple_direcory) + put_data_sample(subtuple, subtuple_directory) # check folder has been correctly renamed with pk of directory containing uncompressed data_sample self.assertFalse(os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', 'foo'))) @@ -263,7 +313,20 @@ def test_put_model(self): model_path = os.path.join(model_directory, traintupleKey) self.assertTrue(os.path.exists(model_path)) - os.rename(model_path, model_path + '-local') + shutil.copyfile(model_path, model_path + '-local') + + # Corrupted + with open(model_path, 'a+') as f: + f.write('corrupted') + + with mock.patch('substrapp.models.Model.objects.get') as mget: + mget.return_value = FakeModel(model_path + '-local') + with self.assertRaises(Exception): + put_model({'model': {'hash': model_hash, 'traintupleKey': traintupleKey}}, + self.subtuple_path, model_content) + + os.remove(model_path) + with mock.patch('substrapp.models.Model.objects.get') as mget: mget.return_value = FakeModel(model_path + '-local') put_model(subtuple, self.subtuple_path, model_content) @@ -272,7 +335,11 @@ def test_put_model(self): with mock.patch('substrapp.models.Model.objects.get') as mget: mget.return_value = FakeModel(model_path) with self.assertRaises(Exception): - put_model({'model': {'hash': 'fail-hash'}}, self.subtuple_path, model_content) + put_model({'model': {'hash': 'fail-hash', 'traintupleKey': traintupleKey}}, + self.subtuple_path, model_content) + + with self.assertRaises(Exception): + put_model(subtuple, self.subtuple_path, None) def test_put_models(self): @@ -315,6 +382,9 @@ def test_put_models(self): with self.assertRaises(Exception): put_models({'inModels': [{'hash': 'hash'}]}, self.subtuple_path, model_content) + with self.assertRaises(Exception): + put_models({'model': {'hash': 'fail-hash'}}, self.subtuple_path, None) + def test_get_model(self): model_content = self.model.read().encode() traintupleKey = compute_hash(model_content) @@ -328,6 +398,8 @@ def test_get_model(self): self.assertIsNotNone(model_content) + self.assertIsNone(get_model({})) + def test_get_models(self): model_content = self.model.read().encode() models_content = [model_content, model_content + b', -2.0'] @@ -350,6 +422,8 @@ def test_get_models(self): self.assertEqual(models_content_res, models_content) + self.assertEqual(len(get_models({})), 0) + def test_get_algo(self): algo_content = self.algo.read() algo_hash = get_hash(self.algo) @@ -359,11 +433,18 @@ def test_get_algo(self): self.assertEqual(algo_content, get_algo({'algo': ''})) def test_get_objective(self): - metrics_content = self.script.read() + metrics_content = self.script.read().encode('utf-8') objective_hash = get_hash(self.script) - with mock.patch('substrapp.models.Objective.objects.get') as mget, \ - mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ + with mock.patch('substrapp.models.Objective.objects.get') as mget: + + mget.return_value = FakeObjective() + + objective = get_objective({'objective': {'hash': objective_hash, + 'metrics': ''}}) + self.assertTrue(isinstance(objective, FakeObjective)) + + with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: mget.return_value = FakeObjective() @@ -427,9 +508,10 @@ def __init__(self): self.MEDIA_ROOT = MEDIA_ROOT - subtuple = [{'key': 'subtuple_test'}] + subtuple = [{'key': 'subtuple_test', 'fltask': 'flkey'}] with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ + mock.patch.object(TaskResult.objects, 'filter') as mtaskresult, \ mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash, \ mock.patch('substrapp.tasks.tasks.query_tuples') as mquery_tuples, \ mock.patch('substrapp.tasks.tasks.get_objective') as mget_objective, \ @@ -440,6 +522,7 @@ def __init__(self): mock.patch('substrapp.tasks.tasks.put_data_sample') as mput_data_sample, \ mock.patch('substrapp.tasks.tasks.put_metric') as mput_metric, \ mock.patch('substrapp.tasks.tasks.put_algo') as mput_algo, \ + mock.patch('substrapp.tasks.tasks.json.loads') as mjson_loads, \ mock.patch('substrapp.tasks.tasks.put_model') as mput_model: msettings.return_value = FakeSettings() @@ -455,6 +538,18 @@ def __init__(self): mput_algo.return_value = 'algo' mput_model.return_value = 'model' + mock_filter = MagicMock() + mock_filter.count.return_value = 1 + mtaskresult.return_value = mock_filter + + mjson_loads.return_value = {'worker': 'worker'} + + with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple, \ + mock.patch('substrapp.tasks.tasks.log_fail_tuple') as mlog_fail_tuple: + mlog_start_tuple.side_effect = Exception("Test") + mlog_fail_tuple.return_value = 'data', 404 + prepare_task('traintuple') + with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple: mlog_start_tuple.return_value = 'data', 404 prepare_task('traintuple') @@ -532,11 +627,62 @@ def __init__(self): f.write("MODEL") with mock.patch('substrapp.tasks.tasks.compute_docker') as mcompute_docker, \ + mock.patch('substrapp.tasks.tasks.do_task') as mdo_task,\ mock.patch('substrapp.tasks.tasks.prepare_materials') as mprepare_materials, \ mock.patch('substrapp.tasks.tasks.log_success_tuple') as mlog_success_tuple: mcompute_docker.return_value = 'DONE' mprepare_materials.return_value = 'DONE' + mdo_task.return_value = 'DONE' + mlog_success_tuple.return_value = 'data', 201 + compute_task('traintuple', subtuple, None) + mlog_success_tuple.return_value = 'data', 404 compute_task('traintuple', subtuple, None) + + with mock.patch('substrapp.tasks.tasks.log_fail_tuple') as mlog_fail_tuple: + mdo_task.side_effect = Exception("Test") + mlog_fail_tuple.return_value = 'data', 404 + compute_task('traintuple', subtuple, None) + + def test_prepare_materials(self): + + class FakeSettings(object): + def __init__(self): + self.LEDGER = {'signcert': 'signcert', + 'org': 'owkin', + 'peer': 'peer'} + + self.MEDIA_ROOT = MEDIA_ROOT + + subtuple = [{'key': 'subtuple_test', 'fltask': 'flkey'}] + + with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ + mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash, \ + mock.patch('substrapp.tasks.tasks.query_tuples') as mquery_tuples, \ + mock.patch('substrapp.tasks.tasks.get_objective') as mget_objective, \ + mock.patch('substrapp.tasks.tasks.get_algo') as mget_algo, \ + mock.patch('substrapp.tasks.tasks.get_model') as mget_model, \ + mock.patch('substrapp.tasks.tasks.build_subtuple_folders') as mbuild_subtuple_folders, \ + mock.patch('substrapp.tasks.tasks.put_opener') as mput_opener, \ + mock.patch('substrapp.tasks.tasks.put_data_sample') as mput_data_sample, \ + mock.patch('substrapp.tasks.tasks.put_metric') as mput_metric, \ + mock.patch('substrapp.tasks.tasks.put_algo') as mput_algo, \ + mock.patch('substrapp.tasks.tasks.put_model') as mput_model: + + msettings.return_value = FakeSettings() + mget_hash.return_value = 'owkinhash' + mquery_tuples.return_value = subtuple, 200 + mget_objective.return_value = 'objective' + mget_algo.return_value = 'algo', 'algo_hash' + mget_model.return_value = 'model', 'model_hash' + mbuild_subtuple_folders.return_value = MEDIA_ROOT + mput_opener.return_value = 'opener' + mput_data_sample.return_value = 'data' + mput_metric.return_value = 'metric' + mput_algo.return_value = 'algo' + mput_model.return_value = 'model' + + prepare_materials(subtuple[0], 'traintuple') + prepare_materials(subtuple[0], 'testtuple') From 85ee8d8ad1b83ba6839d07f9d1a63c9f1391e468 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 6 Jun 2019 16:54:13 +0200 Subject: [PATCH 082/457] Improve ledger call. --- substrabac/substrapp/ledger_utils.py | 140 +++++++++--------- .../serializers/ledger/algo/serializer.py | 7 +- .../substrapp/serializers/ledger/algo/util.py | 29 +--- .../ledger/datamanager/serializer.py | 7 +- .../serializers/ledger/datamanager/util.py | 29 +--- .../ledger/datasample/serializer.py | 5 +- .../serializers/ledger/datasample/util.py | 27 +--- .../ledger/objective/serializer.py | 7 +- .../serializers/ledger/objective/util.py | 29 +--- .../ledger/testtuple/serializer.py | 7 +- .../ledger/traintuple/serializer.py | 7 +- .../substrapp/serializers/ledger/utils.py | 53 +++++++ substrabac/substrapp/tasks/tasks.py | 57 ++++--- substrabac/substrapp/views/algo.py | 60 ++++---- substrabac/substrapp/views/datamanager.py | 73 ++++----- substrabac/substrapp/views/datasample.py | 31 ++-- substrabac/substrapp/views/filters_utils.py | 8 +- substrabac/substrapp/views/model.py | 55 ++++--- substrabac/substrapp/views/objective.py | 64 ++++---- substrabac/substrapp/views/testtuple.py | 41 ++--- substrabac/substrapp/views/traintuple.py | 43 +++--- substrabac/substrapp/views/utils.py | 25 ++-- 22 files changed, 425 insertions(+), 379 deletions(-) create mode 100644 substrabac/substrapp/serializers/ledger/utils.py diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index c6c79fbd3..393f5cd24 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -1,17 +1,48 @@ import asyncio import json +import logging -from rest_framework import status from django.conf import settings -from django.http import Http404 - -from substrapp.utils import JsonException +from rest_framework import status LEDGER = getattr(settings, 'LEDGER', None) if LEDGER: asyncio.set_event_loop(LEDGER['hfc']['loop']) +class LedgerError(Exception): + status = status.HTTP_400_BAD_REQUEST + + def __init__(self, msg): + super(LedgerError, self).__init__() + self.msg = msg + + +class LedgerConflict(LedgerError): + + status = status.HTTP_409_CONFLICT + + def __init__(self, msg, pkhash): + super(LedgerConflict, self).__init__(msg) + self.pkhash = pkhash + + +class LedgerTimeout(LedgerError): + status = status.HTTP_408_REQUEST_TIMEOUT + + +class LedgerForbidden(LedgerError): + status = status.HTTP_403_FORBIDDEN + + +class LedgerNotFound(LedgerError): + status = status.HTTP_404_NOT_FOUND + + +class LedgerBadResponse(LedgerError): + pass + + def call_ledger(call_type, fcn, args=None, kwargs=None): if not args: args = [] @@ -58,55 +89,34 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): try: response = loop.run_until_complete(chaincode_calls[call_type](**params)) except TimeoutError as e: - # Only for invoke - st = status.HTTP_408_REQUEST_TIMEOUT - data = {'message': str(e)} + raise LedgerTimeout(str(e)) except Exception as e: - st = status.HTTP_400_BAD_REQUEST - data = {'message': str(e)} - else: - - if call_type == 'invoke': - st = status.HTTP_201_CREATED - elif call_type == 'query': - st = status.HTTP_200_OK + logging.exception(e) + raise LedgerError(str(e)) + + # Sanity check of the response: + if 'access denied' in response: + raise LedgerForbidden(f'Access denied for {(fcn, args)}') + elif 'no element with key' in response: + raise LedgerNotFound(f'No element founded for {(fcn, args)}') + elif 'tkey' in response: + pkhash = response.replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if len(pkhash) == 64: + raise LedgerConflict(msg='Asset conflict', pkhash=pkhash) else: - raise NotImplementedError() - - # TO DO : review parsing error in case of failure - # May have changed by using fabric-sdk-py - - try: - response = json.loads(response) - if call_type == 'invoke': - pkhash = response.get('key', response.get('keys')) - data = {'pkhash': pkhash} - elif call_type == 'query': - data = response - else: - raise NotImplementedError() - except json.decoder.JSONDecodeError: - st = status.HTTP_400_BAD_REQUEST - - if 'access denied' in response: - st = status.HTTP_403_FORBIDDEN - elif 'no element with key' in response: - st = status.HTTP_404_NOT_FOUND + raise LedgerBadResponse(response) - data = {'message': response} - - if data is not None: - # TODO: get 409 from the chaincode - if 'message' in data and 'tkey' in data['message']: - pkhash = data['message'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if len(pkhash) == 64: - st = status.HTTP_409_CONFLICT - data['pkhash'] = pkhash + # Deserialize the stringified json + try: + response = json.loads(response) + except json.decoder.JSONDecodeError: + raise LedgerBadResponse(response) - if 'permissions' in data and data['permissions'] != 'all': - raise Exception('Not Allowed') + # Check permissions + if 'permissions' in response and response['permissions'] != 'all': + raise LedgerForbidden('Not allowed') - return data, st + return response def query_ledger(fcn, args=None): @@ -122,20 +132,13 @@ def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): if cc_pattern: params['cc_pattern'] = cc_pattern - return call_ledger('invoke', fcn=fcn, args=args, kwargs=params) - - -def get_object_from_ledger(pk, query): - # get instance from remote node - data, st = query_ledger(fcn=query, args={'key': pk}) + response = call_ledger('invoke', fcn=fcn, args=args, kwargs=params) - if st == status.HTTP_404_NOT_FOUND: - raise Http404('Not found') + return {'pkhash': response.get('key', response.get('keys'))} - if st != status.HTTP_200_OK: - raise JsonException(data) - return data +def get_object_from_ledger(pk, query): + return query_ledger(fcn=query, args={'key': pk}) def log_fail_tuple(tuple_type, tuple_key, err_msg): @@ -143,7 +146,7 @@ def log_fail_tuple(tuple_type, tuple_key, err_msg): fail_type = 'logFailTrain' if tuple_type == 'traintuple' else 'logFailTest' - data, st = invoke_ledger( + return invoke_ledger( fcn=fail_type, args={ 'key': tuple_key, @@ -151,8 +154,6 @@ def log_fail_tuple(tuple_type, tuple_key, err_msg): }, sync=True) - return data, st - def log_success_tuple(tuple_type, tuple_key, res): if tuple_type == 'traintuple': @@ -178,9 +179,7 @@ def log_success_tuple(tuple_type, tuple_key, res): else: raise NotImplementedError() - data, st = invoke_ledger(fcn=invoke_fcn, args=invoke_args, sync=True) - - return data, st + return invoke_ledger(fcn=invoke_fcn, args=invoke_args, sync=True) def log_start_tuple(tuple_type, tuple_key): @@ -193,20 +192,21 @@ def log_start_tuple(tuple_type, tuple_key): else: raise NotImplementedError() - data, st = invoke_ledger( + return invoke_ledger( fcn=start_type, args={'key': tuple_key}, sync=True) - return data, st - def query_tuples(tuple_type, data_owner): - tuples, st = query_ledger( + data = query_ledger( fcn="queryFilter", args={ 'indexName': f'{tuple_type}~worker~status', 'attributes': f'{data_owner},todo' } ) - return tuples, st + + data = [] if data is None else data + + return data diff --git a/substrabac/substrapp/serializers/ledger/algo/serializer.py b/substrabac/substrapp/serializers/ledger/algo/serializer.py index d283c27f1..dcec28214 100644 --- a/substrabac/substrapp/serializers/ledger/algo/serializer.py +++ b/substrabac/substrapp/serializers/ledger/algo/serializer.py @@ -1,4 +1,4 @@ -from rest_framework import serializers, status +from rest_framework import serializers from django.conf import settings from rest_framework.reverse import reverse @@ -36,7 +36,7 @@ def create(self, validated_data): } if getattr(settings, 'LEDGER_SYNC_ENABLED'): - return createLedgerAlgo(args, instance.pkhash, sync=True) + data = createLedgerAlgo(args, instance.pkhash, sync=True) else: # use a celery task, as we are in an http request transaction createLedgerAlgoAsync.delay(args, instance.pkhash) @@ -44,4 +44,5 @@ def create(self, validated_data): 'message': 'Algo added in local db waiting for validation. ' 'The substra network has been notified for adding this Algo' } - return data, status.HTTP_202_ACCEPTED + + return data diff --git a/substrabac/substrapp/serializers/ledger/algo/util.py b/substrabac/substrapp/serializers/ledger/algo/util.py index ab50a74f2..5efce85cd 100644 --- a/substrabac/substrapp/serializers/ledger/algo/util.py +++ b/substrabac/substrapp/serializers/ledger/algo/util.py @@ -1,28 +1,13 @@ from __future__ import absolute_import, unicode_literals -from rest_framework import status -from django.core.exceptions import ObjectDoesNotExist from substrapp.models import Algo -from substrapp.ledger_utils import invoke_ledger +from substrapp.serializers.ledger.utils import create_ledger_asset def createLedgerAlgo(args, pkhash, sync=False): - - data, st = invoke_ledger(fcn='registerAlgo', args=args, sync=sync) - - try: - instance = Algo.objects.get(pk=pkhash) - except ObjectDoesNotExist: - pass - else: - # if not created on ledger, delete from local db - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - instance.delete() - else: - # if created on ledger - if st != status.HTTP_408_REQUEST_TIMEOUT: - instance.validated = True - instance.save() - data['validated'] = True - - return data, st + return create_ledger_asset( + model=Algo, + fcn='registerAlgo', + args=args, + pkhash=pkhash, + sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py index 22f8302e6..6969e662b 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py @@ -1,4 +1,4 @@ -from rest_framework import serializers, status +from rest_framework import serializers from django.conf import settings from rest_framework.reverse import reverse @@ -43,7 +43,7 @@ def create(self, validated_data): } if getattr(settings, 'LEDGER_SYNC_ENABLED'): - return createLedgerDataManager(args, instance.pkhash, sync=True) + data = createLedgerDataManager(args, instance.pkhash, sync=True) else: # use a celery task, as we are in an http request transaction createLedgerDataManagerAsync.delay(args, instance.pkhash) @@ -52,4 +52,5 @@ def create(self, validated_data): 'message': 'DataManager added in local db waiting for validation. ' 'The substra network has been notified for adding this DataManager' } - return data, status.HTTP_202_ACCEPTED + + return data diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substrabac/substrapp/serializers/ledger/datamanager/util.py index dd38478b1..d77d68155 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/util.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/util.py @@ -1,31 +1,18 @@ from __future__ import absolute_import, unicode_literals -from rest_framework import status -from django.core.exceptions import ObjectDoesNotExist from substrapp.models import DataManager from substrapp.ledger_utils import invoke_ledger +from substrapp.serializers.ledger.utils import create_ledger_asset -def createLedgerDataManager(args, pkhash, sync=False): - - data, st = invoke_ledger(fcn='registerDataManager', args=args, sync=sync) - try: - instance = DataManager.objects.get(pk=pkhash) - except ObjectDoesNotExist: - pass - else: - # if not created on ledger, delete from local db - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - instance.delete() - else: - # if created on ledger - if st != status.HTTP_408_REQUEST_TIMEOUT: - instance.validated = True - instance.save() - data['validated'] = True - - return data, st +def createLedgerDataManager(args, pkhash, sync=False): + return create_ledger_asset( + model=DataManager, + fcn='registerDataManager', + args=args, + pkhash=pkhash, + sync=sync) def updateLedgerDataManager(args, sync=False): diff --git a/substrabac/substrapp/serializers/ledger/datasample/serializer.py b/substrabac/substrapp/serializers/ledger/datasample/serializer.py index 654a2f09a..6adfa6e9d 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datasample/serializer.py @@ -25,7 +25,7 @@ def create(self, validated_data): } if getattr(settings, 'LEDGER_SYNC_ENABLED'): - return createLedgerDataSample(args, [x.pk for x in instances], sync=True) + data = createLedgerDataSample(args, [x.pk for x in instances], sync=True) else: # use a celery task, as we are in an http request transaction createLedgerDataSampleAsync.delay(args, [x.pk for x in instances]) @@ -33,4 +33,5 @@ def create(self, validated_data): 'message': 'Data samples added in local db waiting for validation. ' 'The substra network has been notified for adding this Data' } - return data, status.HTTP_202_ACCEPTED + + return data diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substrabac/substrapp/serializers/ledger/datasample/util.py index f4f8c60f2..598ff2383 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/util.py +++ b/substrabac/substrapp/serializers/ledger/datasample/util.py @@ -1,30 +1,17 @@ from __future__ import absolute_import, unicode_literals -from rest_framework import status -from django.core.exceptions import ObjectDoesNotExist from substrapp.models import DataSample from substrapp.ledger_utils import invoke_ledger +from substrapp.serializers.ledger.utils import create_ledger_assets def createLedgerDataSample(args, pkhashes, sync=False): - - data, st = invoke_ledger(fcn='registerDataSample', args=args, sync=sync) - - try: - instances = DataSample.objects.filter(pk__in=pkhashes) - except ObjectDoesNotExist: - pass - else: - # if not created on ledger, delete from local db - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - instances.delete() - else: - # if created on ledger - if st != status.HTTP_408_REQUEST_TIMEOUT: - instances.update(validated=True) - data['validated'] = True - - return data, st + return create_ledger_assets( + model=DataSample, + fcn='registerDataSample', + args=args, + pkhashes=pkhashes, + sync=sync) def updateLedgerDataSample(args, sync=False): diff --git a/substrabac/substrapp/serializers/ledger/objective/serializer.py b/substrabac/substrapp/serializers/ledger/objective/serializer.py index bf08746cc..bb3fd8f6d 100644 --- a/substrabac/substrapp/serializers/ledger/objective/serializer.py +++ b/substrabac/substrapp/serializers/ledger/objective/serializer.py @@ -1,4 +1,4 @@ -from rest_framework import serializers, status +from rest_framework import serializers # from django.contrib.sites.models import Site from django.conf import settings from rest_framework.reverse import reverse @@ -46,7 +46,7 @@ def create(self, validated_data): } if getattr(settings, 'LEDGER_SYNC_ENABLED'): - return createLedgerObjective(args, instance.pkhash, sync=True) + data = createLedgerObjective(args, instance.pkhash, sync=True) else: # use a celery task, as we are in an http request transaction createLedgerObjectiveAsync.delay(args, instance.pkhash) @@ -54,4 +54,5 @@ def create(self, validated_data): 'message': 'Objective added in local db waiting for validation. ' 'The substra network has been notified for adding this Objective' } - return data, status.HTTP_202_ACCEPTED + + return data diff --git a/substrabac/substrapp/serializers/ledger/objective/util.py b/substrabac/substrapp/serializers/ledger/objective/util.py index a3befdc43..517cba558 100644 --- a/substrabac/substrapp/serializers/ledger/objective/util.py +++ b/substrabac/substrapp/serializers/ledger/objective/util.py @@ -1,28 +1,13 @@ from __future__ import absolute_import, unicode_literals -from rest_framework import status -from django.core.exceptions import ObjectDoesNotExist from substrapp.models import Objective -from substrapp.ledger_utils import invoke_ledger +from substrapp.serializers.ledger.utils import create_ledger_asset def createLedgerObjective(args, pkhash, sync=False): - - data, st = invoke_ledger(fcn='registerObjective', args=args, sync=sync) - - try: - instance = Objective.objects.get(pk=pkhash) - except ObjectDoesNotExist: - pass - else: - # if not created on ledger, delete from local db - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - instance.delete() - else: - # if created on ledger - if st != status.HTTP_408_REQUEST_TIMEOUT: - instance.validated = True - instance.save() - data['validated'] = True - - return data, st + return create_ledger_asset( + model=Objective, + fcn='registerObjective', + args=args, + pkhash=pkhash, + sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py index 72adcb7f3..c0722d55f 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py @@ -1,4 +1,4 @@ -from rest_framework import serializers, status +from rest_framework import serializers from django.conf import settings @@ -33,7 +33,7 @@ def create(self, validated_data): args = self.get_args(validated_data) if getattr(settings, 'LEDGER_SYNC_ENABLED'): - return createLedgerTesttuple(args, sync=True) + data = createLedgerTesttuple(args, sync=True) else: # use a celery task, as we are in an http request transaction createLedgerTesttupleAsync.delay(args) @@ -42,4 +42,5 @@ def create(self, validated_data): 'Please be aware you won\'t get return values from the ledger. ' 'You will need to check manually' } - return data, status.HTTP_202_ACCEPTED + + return data diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index beb2607a3..4343c23c9 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -1,4 +1,4 @@ -from rest_framework import serializers, status +from rest_framework import serializers from django.conf import settings @@ -48,7 +48,7 @@ def create(self, validated_data): args = self.get_args(validated_data) if getattr(settings, 'LEDGER_SYNC_ENABLED'): - return createLedgerTraintuple(args, sync=True) + data = createLedgerTraintuple(args, sync=True) else: # use a celery task, as we are in an http request transaction createLedgerTraintupleAsync.delay(args) @@ -57,4 +57,5 @@ def create(self, validated_data): 'Please be aware you won\'t get return values from the ledger. ' 'You will need to check manually' } - return data, status.HTTP_202_ACCEPTED + + return data diff --git a/substrabac/substrapp/serializers/ledger/utils.py b/substrabac/substrapp/serializers/ledger/utils.py new file mode 100644 index 000000000..32b93920e --- /dev/null +++ b/substrabac/substrapp/serializers/ledger/utils.py @@ -0,0 +1,53 @@ +from django.core.exceptions import ObjectDoesNotExist +from substrapp.ledger_utils import invoke_ledger, LedgerError, LedgerTimeout + + +def create_ledger_asset(model, fcn, args, pkhash, sync=False): + try: + instance = model.objects.get(pk=pkhash) + except ObjectDoesNotExist: + instance = None + + try: + data = invoke_ledger(fcn=fcn, args=args, sync=sync) + except LedgerTimeout: + # LedgerTimeout herits from LedgerError do not delete + # In case of timeout we keep the instance if it exists + raise + except LedgerError: + # if not created on ledger, delete from local db + if instance: + instance.delete() + raise + + if instance: + instance.validated = True + instance.save() + data['validated'] = True + + return data + + +def create_ledger_assets(model, fcn, args, pkhashes, sync=False): + try: + instances = model.objects.filter(pk__in=pkhashes) + except ObjectDoesNotExist: + instances = None + + try: + data = invoke_ledger(fcn=fcn, args=args, sync=sync) + except LedgerTimeout: + # LedgerTimeout herits from LedgerError do not delete + # In case of timeout we keep the instances if it exists + raise + except LedgerError: + # if not created on ledger, delete from local db + if instances: + instances.delete() + raise + + if instances: + instances.update(validated=True) + data['validated'] = True + + return data diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index dde1a09ae..4eecad91a 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -8,13 +8,12 @@ from checksumdir import dirhash from django.core.exceptions import ObjectDoesNotExist from django.conf import settings -from rest_framework import status from rest_framework.reverse import reverse from substrabac.celery import app from substrapp.utils import get_hash, create_directory, get_remote_file, uncompress_content from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, - query_tuples) + query_tuples, LedgerTimeout, LedgerError) from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code @@ -200,14 +199,13 @@ def prepare_testing_task(): def prepare_task(tuple_type): data_owner = get_hash(settings.LEDGER['signcert']) worker_queue = f"{settings.LEDGER['name']}.worker" - tuples, st = query_tuples(tuple_type, data_owner) + tuples = query_tuples(tuple_type, data_owner) - if st == status.HTTP_200_OK and tuples is not None: - for subtuple in tuples: - prepare_tuple.apply_async( - (subtuple, tuple_type), - task_id=subtuple['key'], - queue=worker_queue) + for subtuple in tuples: + prepare_tuple.apply_async( + (subtuple, tuple_type), + task_id=subtuple['key'], + queue=worker_queue) @app.task(ignore_result=False) @@ -227,16 +225,20 @@ def prepare_tuple(subtuple, tuple_type): worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] try: - data, st = log_start_tuple(tuple_type, subtuple['key']) - - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): + compute = True + try: + log_start_tuple(tuple_type, subtuple['key']) + except LedgerTimeout: + pass + except LedgerError as e: # Do not log_fail_tuple in this case, because prepare_tuple task are not unique # in case of multiple instances of substrabac running for the same organisation # So prepare_tuple tasks are ignored if it cannot log_start_tuple # TODO: find a way to handle this special case to avoid silent failure in other cases. - e = Exception(f'Failed to invoke ledger on prepare_task {tuple_type}. Error: {data}') logging.exception(e) - else: + compute = False + + if compute: compute_task.apply_async( (tuple_type, subtuple, fltask), queue=worker_queue) @@ -244,12 +246,10 @@ def prepare_tuple(subtuple, tuple_type): except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - data, st = log_fail_tuple(tuple_type, subtuple['key'], error_code) - - if st != status.HTTP_201_CREATED: - logging.error(data, exc_info=True) - - return data, st + try: + log_fail_tuple(tuple_type, subtuple['key'], error_code) + except LedgerError as e: + logging.exception(e) @app.task(bind=True, ignore_result=False) @@ -271,18 +271,17 @@ def compute_task(self, tuple_type, subtuple, fltask): error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - data, st = log_fail_tuple(tuple_type, subtuple['key'], error_code) - - if st != status.HTTP_201_CREATED: - logging.error(data, exc_info=True) + try: + log_fail_tuple(tuple_type, subtuple['key'], error_code) + except LedgerError as e: + logging.exception(e) return result - data, st = log_success_tuple(tuple_type, subtuple['key'], res) - - if st not in (status.HTTP_201_CREATED, status.HTTP_408_REQUEST_TIMEOUT): - logging.error('Failed to invoke ledger on logSuccess') - logging.error(data) + try: + log_success_tuple(tuple_type, subtuple['key'], res) + except LedgerError as e: + logging.exception(e) return result diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index f28907556..35eefb212 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -10,10 +10,10 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer -from substrapp.utils import get_hash, JsonException, get_from_node -from substrapp.ledger_utils import query_ledger, get_object_from_ledger +from substrapp.utils import get_hash, get_from_node +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError from substrapp.views.utils import (ComputeHashMixin, ManageFileMixin, find_primary_key_error, - validate_pk) + validate_pk, get_success_create_code) from substrapp.views.filters_utils import filter_list @@ -67,14 +67,16 @@ def create(self, request, *args, **kwargs): raise ValidationError(ledger_serializer.errors) # create on ledger - data, st = ledger_serializer.create(ledger_serializer.validated_data) - - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED, status.HTTP_408_REQUEST_TIMEOUT): - return Response(data, status=st) + try: + data = ledger_serializer.create(ledger_serializer.validated_data) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + st = get_success_create_code() headers = self.get_success_headers(serializer.data) d = dict(serializer.data) d.update(data) + return Response(d, status=st, headers=headers) def create_or_update_algo(self, algo, pk): @@ -114,10 +116,8 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: data = get_object_from_ledger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) # try to get it from local db to check if description exists try: @@ -142,29 +142,33 @@ def retrieve(self, request, *args, **kwargs): return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): - data, st = query_ledger(fcn='queryAlgos', args=[]) + try: + data = query_ledger(fcn='queryAlgos', args=[]) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + data = data if data else [] algos_list = [data] - if st == status.HTTP_200_OK: - - # parse filters - query_params = request.query_params.get('search', None) + # parse filters + query_params = request.query_params.get('search', None) - if query_params is not None: - try: - algos_list = filter_list( - object_type='algo', - data=data, - query_params=query_params) - except Exception as e: - logging.exception(e) - return Response( - {'message': f'Malformed search filters {query_params}'}, - status=status.HTTP_400_BAD_REQUEST) + if query_params is not None: + try: + algos_list = filter_list( + object_type='algo', + data=data, + query_params=query_params) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + except Exception as e: + logging.exception(e) + return Response( + {'message': f'Malformed search filters {query_params}'}, + status=status.HTTP_400_BAD_REQUEST) - return Response(algos_list, status=st) + return Response(algos_list, status=status.HTTP_200_OK) @action(detail=True) def file(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 164427f05..5eb94c484 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -15,10 +15,10 @@ from substrapp.serializers import DataManagerSerializer, LedgerDataManagerSerializer from substrapp.serializers.ledger.datamanager.util import updateLedgerDataManager from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync -from substrapp.utils import get_hash, JsonException, get_from_node -from substrapp.ledger_utils import query_ledger, get_object_from_ledger +from substrapp.utils import get_hash, get_from_node +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError from substrapp.views.utils import (ManageFileMixin, ComputeHashMixin, find_primary_key_error, - validate_pk) + validate_pk, get_success_create_code) from substrapp.views.filters_utils import filter_list @@ -101,13 +101,17 @@ def create(self, request, *args, **kwargs): raise ValidationError(ledger_serializer.errors) # create on ledger - data, st = ledger_serializer.create(ledger_serializer.validated_data) - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED, status.HTTP_408_REQUEST_TIMEOUT): - return Response(data, status=st) + try: + data = ledger_serializer.create(ledger_serializer.validated_data) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + + st = get_success_create_code() headers = self.get_success_headers(serializer.data) d = dict(serializer.data) d.update(data) + return Response(d, status=st, headers=headers) def create_or_update_datamanager(self, instance, datamanager, pk): @@ -174,10 +178,8 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: data = get_object_from_ledger(pk, 'queryDataset') - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) # try to get it from local db to check if description exists try: @@ -202,29 +204,33 @@ def retrieve(self, request, *args, **kwargs): def list(self, request, *args, **kwargs): - data, st = query_ledger(fcn='queryDataManagers', args=[]) + try: + data = query_ledger(fcn='queryDataManagers', args=[]) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + data = data if data else [] data_managers_list = [data] - if st == status.HTTP_200_OK: + # parse filters + query_params = request.query_params.get('search', None) - # parse filters - query_params = request.query_params.get('search', None) - - if query_params is not None: - try: - data_managers_list = filter_list( - object_type='dataset', - data=data, - query_params=query_params) - except Exception as e: - logging.exception(e) - return Response( - {'message': f'Malformed search filters {query_params}'}, - status=status.HTTP_400_BAD_REQUEST) + if query_params is not None: + try: + data_managers_list = filter_list( + object_type='dataset', + data=data, + query_params=query_params) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + except Exception as e: + logging.exception(e) + return Response( + {'message': f'Malformed search filters {query_params}'}, + status=status.HTTP_400_BAD_REQUEST) - return Response(data_managers_list, status=st) + return Response(data_managers_list, status=status.HTTP_200_OK) @action(methods=['post'], detail=True) def update_ledger(self, request, *args, **kwargs): @@ -235,17 +241,18 @@ def update_ledger(self, request, *args, **kwargs): try: validate_pk(pk) except Exception as e: - return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) objective_key = request.data.get('objective_key') args = [pk, objective_key] if getattr(settings, 'LEDGER_SYNC_ENABLED'): - data, st = updateLedgerDataManager(args, sync=True) - # patch status for update - if st == status.HTTP_201_CREATED: - st = status.HTTP_200_OK - return Response(data, status=st) + try: + data = updateLedgerDataManager(args, sync=True) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + + return Response(data, status=status.HTTP_200_OK) else: # use a celery task, as we are in an http request transaction diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 83ee2ecc9..0974d0ab0 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -24,7 +24,9 @@ from substrapp.serializers.ledger.datasample.tasks import updateLedgerDataSampleAsync from substrapp.utils import uncompress_path, get_dir_hash from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.views.utils import find_primary_key_error, LedgerException, ValidationException +from substrapp.views.utils import find_primary_key_error, LedgerException, ValidationException, \ + get_success_create_code +from substrapp.ledger_utils import LedgerError, LedgerTimeout logger = logging.getLogger('django.request') @@ -64,14 +66,16 @@ def commit(serializer, ledger_data): raise ValidationError(ledger_serializer.errors) # create on ledger - data, st = ledger_serializer.create(ledger_serializer.validated_data) - - if st == status.HTTP_408_REQUEST_TIMEOUT: + try: + data = ledger_serializer.create(ledger_serializer.validated_data) + except LedgerTimeout as e: + data = {'message': str(e)} data.update({'pkhash': [x['pkhash'] for x in serializer.data]}) - raise LedgerException(data, st) + raise LedgerException(data, e.status) + except LedgerError as e: + raise LedgerException({'message': str(e)}, e.status) - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED): - raise LedgerException(data, st) + st = get_success_create_code() # update validated to True in response if 'pkhash' in data and data['validated']: @@ -201,7 +205,7 @@ def create(self, request, *args, **kwargs): except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: - return Response({'message': e.data}, status=e.st) + return Response({'message': str(e)}, status=e.st) except Exception as e: return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: @@ -248,12 +252,13 @@ def bulk_update(self, request): ','.join(data_manager_keys) ] if getattr(settings, 'LEDGER_SYNC_ENABLED'): - data, st = updateLedgerDataSample(args, sync=True) + try: + data = updateLedgerDataSample(args, sync=True) + except LedgerError as e: + return Response({'message': str(e)}, status=e.st) + + return Response(data, status=status.HTTP_200_OK) - # patch status for update - if st == status.HTTP_201_CREATED: - st = status.HTTP_200_OK - return Response(data, status=st) else: # use a celery task, as we are in an http request transaction updateLedgerDataSampleAsync.delay(args) diff --git a/substrabac/substrapp/views/filters_utils.py b/substrabac/substrapp/views/filters_utils.py index a3b255008..682e9b39c 100644 --- a/substrabac/substrapp/views/filters_utils.py +++ b/substrabac/substrapp/views/filters_utils.py @@ -1,8 +1,5 @@ from urllib.parse import unquote -from rest_framework import status -from rest_framework.response import Response - from substrapp.ledger_utils import query_ledger @@ -97,9 +94,8 @@ def filter_list(object_type, data, query_params): # Filter by other asset # Get other asset list - filtering_data, st = query_ledger(fcn=FILTER_QUERIES[filter_key], args=[]) - if st != status.HTTP_200_OK: - return Response(filtering_data, status=st) + filtering_data = query_ledger(fcn=FILTER_QUERIES[filter_key], args=[]) + filtering_data = filtering_data if filtering_data else [] if filter_key == 'algo': diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 1c023f4dd..921dab61c 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -10,8 +10,8 @@ from substrapp.models import Model from substrapp.serializers import ModelSerializer -from substrapp.utils import JsonException, get_from_node -from substrapp.ledger_utils import query_ledger, get_object_from_ledger +from substrapp.utils import get_from_node +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError from substrapp.views.utils import ComputeHashMixin, CustomFileResponse, validate_pk from substrapp.views.filters_utils import filter_list @@ -65,10 +65,8 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: data = get_object_from_ledger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) # Try to get it from local db, else create it in local db try: @@ -92,27 +90,31 @@ def retrieve(self, request, *args, **kwargs): return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): + try: + data = query_ledger(fcn='queryModels', args=[]) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) - data, st = query_ledger(fcn='queryModels', args=[]) data = data if data else [] models_list = [data] - if st == status.HTTP_200_OK: - query_params = request.query_params.get('search', None) - if query_params is not None: - try: - models_list = filter_list( - object_type='model', - data=data, - query_params=query_params) - except Exception as e: - logging.exception(e) - return Response( - {'message': f'Malformed search filters {query_params}'}, - status=status.HTTP_400_BAD_REQUEST) - - return Response(models_list, status=st) + query_params = request.query_params.get('search', None) + if query_params is not None: + try: + models_list = filter_list( + object_type='model', + data=data, + query_params=query_params) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + except Exception as e: + logging.exception(e) + return Response( + {'message': f'Malformed search filters {query_params}'}, + status=status.HTTP_400_BAD_REQUEST) + + return Response(models_list, status=status.HTTP_200_OK) @action(detail=True) def file(self, request, *args, **kwargs): @@ -124,5 +126,10 @@ def file(self, request, *args, **kwargs): def details(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - data, st = query_ledger(fcn='queryModelDetails', args=[f'{pk}']) - return Response(data, st) + + try: + data = query_ledger(fcn='queryModelDetails', args=[f'{pk}']) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + + return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index ba947b8aa..763fad7f0 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -22,10 +22,11 @@ from substrapp.models import Objective from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer -from substrapp.ledger_utils import query_ledger, get_object_from_ledger +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError from substrapp.utils import get_hash, get_computed_hash, JsonException, get_from_node from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk +from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ + get_success_create_code from substrapp.views.filters_utils import filter_list @@ -112,16 +113,18 @@ def create(self, request, *args, **kwargs): instance.delete() raise ValidationError(ledger_serializer.errors) - ledger_data, st = ledger_serializer.create(ledger_serializer.validated_data) - - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED, status.HTTP_408_REQUEST_TIMEOUT): - return Response(ledger_data, status=st) + # create on ledger + try: + data = ledger_serializer.create(ledger_serializer.validated_data) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + st = get_success_create_code() # return response with local db and ledger data information headers = self.get_success_headers(serializer.data) - data = dict(serializer.data) # local db data - data.update(ledger_data) # ledger data - return Response(data, status=st, headers=headers) + d = dict(serializer.data) # local db data + d.update(data) # ledger data + return Response(d, status=st, headers=headers) def create_or_update_objective(self, objective, pk): @@ -161,10 +164,8 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: data = get_object_from_ledger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) # try to get it from local db to check if description exists try: @@ -187,27 +188,31 @@ def retrieve(self, request, *args, **kwargs): return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): + try: + data = query_ledger(fcn='queryObjectives', args=[]) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) - data, st = query_ledger(fcn='queryObjectives', args=[]) data = data if data else [] objectives_list = [data] - if st == status.HTTP_200_OK: - query_params = request.query_params.get('search', None) - if query_params is not None: - try: - objectives_list = filter_list( - object_type='objective', - data=data, - query_params=query_params) - except Exception as e: - logging.exception(e) - return Response( - {'message': f'Malformed search filters {query_params}'}, - status=status.HTTP_400_BAD_REQUEST) - - return Response(objectives_list, status=st) + query_params = request.query_params.get('search', None) + if query_params is not None: + try: + objectives_list = filter_list( + object_type='objective', + data=data, + query_params=query_params) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + except Exception as e: + logging.exception(e) + return Response( + {'message': f'Malformed search filters {query_params}'}, + status=status.HTTP_400_BAD_REQUEST) + + return Response(objectives_list, status=status.HTTP_200_OK) @action(detail=True) def description(self, request, *args, **kwargs): @@ -244,6 +249,7 @@ def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): raise Exception('Cannot do a objective dryrun without a data manager key.') datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') + opener_content, opener_computed_hash = get_computed_hash(datamanager['opener']['storageAddress']) with open(os.path.join(subtuple_directory, 'opener/opener.py'), 'wb') as file: file.write(opener_content) diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index d908e4425..2e350ef4e 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -1,12 +1,10 @@ -from django.http import Http404 from rest_framework import mixins, status from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from substrapp.serializers import LedgerTestTupleSerializer -from substrapp.ledger_utils import query_ledger, get_object_from_ledger -from substrapp.utils import JsonException -from substrapp.views.utils import validate_pk +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerConflict +from substrapp.views.utils import validate_pk, get_success_create_code class TestTupleViewSet(mixins.CreateModelMixin, @@ -36,26 +34,35 @@ def create(self, request, *args, **kwargs): # Get testtuple pkhash to handle 408 timeout in invoke_ledger args = serializer.get_args(serializer.validated_data) - data, st = query_ledger(fcn='createTesttuple', args=args) - if st == status.HTTP_409_CONFLICT: - return Response({'message': data['message'], - 'pkhash': data['pkhash']}, status=st) + + try: + data = query_ledger(fcn='createTesttuple', args=args) + except LedgerConflict as e: + return Response({'message': str(e), 'pkhash': e.pkhash}, status=e.status) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + pkhash = data.get('key') # create on ledger - data, st = serializer.create(serializer.validated_data) + try: + data = serializer.create(serializer.validated_data) + except LedgerError as e: + return Response({'message': str(e), 'pkhash': pkhash}, status=e.status) - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED): - return Response({'message': data['message'], - 'pkhash': pkhash}, status=st) + st = get_success_create_code() headers = self.get_success_headers(serializer.data) return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): - data, st = query_ledger(fcn='queryTesttuples', args=[]) + try: + data = query_ledger(fcn='queryTesttuples', args=[]) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + data = data if data else [] - return Response(data, status=st) + return Response(data, status=status.HTTP_200_OK) def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field @@ -69,9 +76,7 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: data = get_object_from_ledger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) else: return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index db47ab628..79e2d6875 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -1,12 +1,10 @@ -from django.http import Http404 from rest_framework import mixins, status from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from substrapp.serializers import LedgerTrainTupleSerializer -from substrapp.ledger_utils import query_ledger, get_object_from_ledger -from substrapp.utils import JsonException -from substrapp.views.utils import validate_pk +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerConflict +from substrapp.views.utils import validate_pk, get_success_create_code class TrainTupleViewSet(mixins.CreateModelMixin, @@ -40,26 +38,37 @@ def create(self, request, *args, **kwargs): # Get traintuple pkhash to handle 408 timeout in invoke_ledger args = serializer.get_args(serializer.validated_data) - data, st = query_ledger(fcn='createTraintuple', args=args) - if st == status.HTTP_409_CONFLICT: - return Response({'message': data['message'], - 'pkhash': data['pkhash']}, status=st) + + try: + data = query_ledger(fcn='createTraintuple', args=args) + except LedgerConflict as e: + return Response({'message': str(e), 'pkhash': e.pkhash}, status=e.status) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + pkhash = data.get('key') # create on ledger - data, st = serializer.create(serializer.validated_data) + try: + data = serializer.create(serializer.validated_data) + except LedgerError as e: + return Response({'message': str(e), 'pkhash': pkhash}, status=e.status) - if st not in (status.HTTP_201_CREATED, status.HTTP_202_ACCEPTED): - return Response({'message': data['message'], - 'pkhash': pkhash}, status=st) + st = get_success_create_code() headers = self.get_success_headers(serializer.data) return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): - data, st = query_ledger(fcn='queryTraintuples', args=[]) + + try: + data = query_ledger(fcn='queryTraintuples', args=[]) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) + data = data if data else [] - return Response(data, status=st) + + return Response(data, status=status.HTTP_200_OK) def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field @@ -73,9 +82,7 @@ def retrieve(self, request, *args, **kwargs): # get instance from remote node try: data = get_object_from_ledger(pk, self.ledger_query_call) - except JsonException as e: - return Response(e.msg, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) else: return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 796c5ba38..4b506df26 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -1,11 +1,13 @@ import hashlib import os -from django.http import FileResponse, Http404 -from rest_framework import status +from django.http import FileResponse from rest_framework.response import Response -from substrapp.ledger_utils import get_object_from_ledger +from substrapp.ledger_utils import get_object_from_ledger, LedgerError + +from django.conf import settings +from rest_framework import status class ComputeHashMixin(object): @@ -40,14 +42,12 @@ def manage_file(self, field): try: get_object_from_ledger(pk, self.ledger_query_call) - except Exception as e: - return Response(e, status=status.HTTP_400_BAD_REQUEST) - except Http404: - return Response(f'No element with key {pk}', status=status.HTTP_404_NOT_FOUND) + except LedgerError as e: + return Response({'message': str(e)}, status=e.status) else: - object = self.get_object() + obj = self.get_object() - data = getattr(object, field) + data = getattr(obj, field) return CustomFileResponse(open(data.path, 'rb'), as_attachment=True, filename=os.path.basename(data.path)) @@ -103,3 +103,10 @@ def __init__(self, data, pkhash, st): self.pkhash = pkhash self.st = st super(ValidationException).__init__() + + +def get_success_create_code(): + if getattr(settings, 'LEDGER_SYNC_ENABLED'): + return status.HTTP_201_CREATED + else: + return status.HTTP_202_ACCEPTED From fa3ff6752b17d4171b2c05ced7cb7b409b33271b Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 6 Jun 2019 18:01:36 +0200 Subject: [PATCH 083/457] Fix flake8 --- .../substrapp/serializers/ledger/datasample/serializer.py | 2 +- substrabac/substrapp/views/objective.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/datasample/serializer.py b/substrabac/substrapp/serializers/ledger/datasample/serializer.py index 6adfa6e9d..e1a4a7b36 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datasample/serializer.py @@ -1,6 +1,6 @@ import json -from rest_framework import serializers, status +from rest_framework import serializers from django.conf import settings diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 763fad7f0..6090ad5b2 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -23,7 +23,7 @@ from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError -from substrapp.utils import get_hash, get_computed_hash, JsonException, get_from_node +from substrapp.utils import get_hash, get_computed_hash, get_from_node from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ get_success_create_code From 2ab23ea108b015878002f27d6ed5a957fc08d547 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 7 Jun 2019 10:41:06 +0200 Subject: [PATCH 084/457] Fix tests and views. --- .../substrapp/tests/query/tests_query_algo.py | 15 +++--- .../tests/query/tests_query_datamanager.py | 11 +++-- .../tests/query/tests_query_datasample.py | 35 +++++++------- .../tests/query/tests_query_objective.py | 15 +++--- .../tests/query/tests_query_tuples.py | 13 ++--- substrabac/substrapp/tests/tests_misc.py | 47 +++++++++---------- substrabac/substrapp/tests/tests_tasks.py | 9 ++-- .../substrapp/tests/views/tests_views.py | 9 +--- .../substrapp/tests/views/tests_views_algo.py | 30 ++++++------ .../tests/views/tests_views_datamanager.py | 19 ++++---- .../tests/views/tests_views_datasample.py | 10 ++-- .../tests/views/tests_views_model.py | 24 +++++----- .../tests/views/tests_views_objective.py | 26 +++++----- .../tests/views/tests_views_tuples.py | 10 ++-- substrabac/substrapp/views/algo.py | 8 ++-- substrabac/substrapp/views/datamanager.py | 10 ++-- substrabac/substrapp/views/datasample.py | 9 ++-- substrabac/substrapp/views/model.py | 8 ++-- substrabac/substrapp/views/objective.py | 8 ++-- substrabac/substrapp/views/testtuple.py | 10 ++-- substrabac/substrapp/views/traintuple.py | 10 ++-- substrabac/substrapp/views/utils.py | 2 +- 22 files changed, 165 insertions(+), 173 deletions(-) diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substrabac/substrapp/tests/query/tests_query_algo.py index 5198e18dd..a38cb7355 100644 --- a/substrabac/substrapp/tests/query/tests_query_algo.py +++ b/substrabac/substrapp/tests/query/tests_query_algo.py @@ -13,6 +13,7 @@ from substrapp.models import Objective, Algo from substrapp.serializers import LedgerAlgoSerializer from substrapp.utils import get_hash, compute_hash +from substrapp.ledger_utils import LedgerError from ..common import get_sample_objective, get_sample_datamanager, \ get_sample_algo, get_sample_algo_zip @@ -21,6 +22,7 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class AlgoQueryTests(APITestCase): @@ -79,8 +81,8 @@ def test_add_algo_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.algo.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = {'pkhash': pkhash}, status.HTTP_201_CREATED + with mock.patch('substrapp.serializers.ledger.utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'pkhash': pkhash} response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -108,11 +110,11 @@ def test_add_algo_no_sync_ok(self): extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.algo.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = ({ + with mock.patch('substrapp.serializers.ledger.utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = { 'message': 'Algo added in local db waiting for validation.' 'The substra network has been notified for adding this Algo' - }, status.HTTP_202_ACCEPTED) + } response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -140,8 +142,7 @@ def test_add_algo_ko(self): } with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: - mcreate.return_value = { - 'message': 'Fail to add algo. Objective does not exist'}, status.HTTP_400_BAD_REQUEST + mcreate.side_effect = LedgerError('Fail to add algo. Objective does not exist') response = self.client.post(url, data, format='multipart', **extra) r = response.json() diff --git a/substrabac/substrapp/tests/query/tests_query_datamanager.py b/substrabac/substrapp/tests/query/tests_query_datamanager.py index b245d6d02..487a0cd3c 100644 --- a/substrabac/substrapp/tests/query/tests_query_datamanager.py +++ b/substrabac/substrapp/tests/query/tests_query_datamanager.py @@ -19,6 +19,7 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class DataManagerQueryTests(APITestCase): @@ -53,8 +54,8 @@ def test_add_datamanager_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.datamanager.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = ({'pkhash': pkhash}, status.HTTP_201_CREATED) + with mock.patch('substrapp.serializers.ledger.utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'pkhash': pkhash} response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -82,11 +83,11 @@ def test_add_datamanager_no_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.datamanager.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = ({ + with mock.patch('substrapp.serializers.ledger.utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = { 'message': 'DataManager added in local db waiting for validation.' 'The substra network has been notified for adding this DataManager' - }, status.HTTP_202_ACCEPTED) + } response = self.client.post(url, data, format='multipart', **extra) r = response.json() diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substrabac/substrapp/tests/query/tests_query_datasample.py index cde04d252..2fe4908a3 100644 --- a/substrabac/substrapp/tests/query/tests_query_datasample.py +++ b/substrabac/substrapp/tests/query/tests_query_datasample.py @@ -18,6 +18,7 @@ from substrapp.serializers import LedgerDataSampleSerializer, DataSampleSerializer from substrapp.utils import get_hash, get_dir_hash +from substrapp.ledger_utils import LedgerError, LedgerTimeout from substrapp.views import DataSampleViewSet from ..common import get_sample_datamanager, get_sample_zip_data_sample, get_sample_script, \ @@ -27,6 +28,7 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class DataSampleQueryTests(APITestCase): @@ -78,11 +80,11 @@ def test_add_data_sample_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = ({ + with mock.patch('substrapp.serializers.ledger.datasample.util.create_ledger_assets') as mcreate_ledger_assets: + mcreate_ledger_assets.return_value = { 'pkhash': pkhash, 'validated': True - }, status.HTTP_201_CREATED) + } response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -114,14 +116,15 @@ def test_bulk_add_data_sample_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: + with mock.patch('substrapp.serializers.ledger.datasample.util.create_ledger_assets') as mcreate_ledger_assets: self.data_file.seek(0) self.data_file_2.seek(0) ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': True} - minvoke_ledger.return_value = ledger_data, status.HTTP_201_CREATED + mcreate_ledger_assets.return_value = ledger_data response = self.client.post(url, data, format='multipart', **extra) r = response.json() + self.assertEqual(len(r), 2) self.assertEqual(r[0]['pkhash'], get_dir_hash(file_mock)) self.assertTrue(r[0]['path'].endswith(f'/datasamples/{get_dir_hash(file_mock)}')) @@ -143,14 +146,10 @@ def test_add_data_sample_no_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = ({ - 'message': 'Data added in local db waiting for validation.' - 'The substra network has been notified for adding this Data' - }, status.HTTP_202_ACCEPTED) + with mock.patch('substrapp.serializers.ledger.datasample.util.create_ledger_assets') as mcreate_ledger_assets: + mcreate_ledger_assets.return_value = '' response = self.client.post(url, data, format='multipart', **extra) r = response.json() - self.assertEqual(r[0]['pkhash'], pkhash) self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) @@ -260,11 +259,13 @@ def test_add_data_sample_ko_408(self): with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mcreate.return_value = {'pkhash': get_hash(file_mock), 'validated': False}, status.HTTP_408_REQUEST_TIMEOUT + mcreate.side_effect = LedgerTimeout('Timeout') mis_zipfile.return_value = True response = self.client.post(url, data, format='multipart', **extra) r = response.json() - self.assertEqual(r['message'], {'pkhash': [get_dir_hash(file_mock)], 'validated': False}) + self.assertEqual( + r['message'], + {'pkhash': [get_dir_hash(file_mock)], 'validated': False}) self.assertEqual(response.status_code, status.HTTP_408_REQUEST_TIMEOUT) def test_bulk_add_data_sample_ko_408(self): @@ -295,8 +296,8 @@ def test_bulk_add_data_sample_ko_408(self): mget_validators.return_value = [] self.data_file.seek(0) self.data_tar_file.seek(0) - ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} - mcreate.return_value = ledger_data, status.HTTP_408_REQUEST_TIMEOUT + # ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} + mcreate.side_effect = LedgerTimeout('Timeout') response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -365,7 +366,7 @@ def test_add_data_sample_ko_400(self): with mock.patch.object(zipfile, 'is_zipfile') as mis_zipfile, \ mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: - mcreate.return_value = 'Failed', status.HTTP_400_BAD_REQUEST + mcreate.side_effect = LedgerError('Failed') mis_zipfile.return_value = True response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -499,7 +500,7 @@ def test_bulk_update_data(self): with mock.patch( 'substrapp.serializers.ledger.datasample.util.invoke_ledger') as minvoke_ledger: minvoke_ledger.return_value = {'keys': [ - d.pkhash]}, status.HTTP_200_OK + d.pkhash]} response = self.client.post(url, data, format='multipart', **extra) r = response.json() diff --git a/substrabac/substrapp/tests/query/tests_query_objective.py b/substrabac/substrapp/tests/query/tests_query_objective.py index 2cbf8e1e6..4bde52de3 100644 --- a/substrabac/substrapp/tests/query/tests_query_objective.py +++ b/substrabac/substrapp/tests/query/tests_query_objective.py @@ -21,6 +21,7 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class ObjectiveQueryTests(APITestCase): @@ -68,8 +69,8 @@ def test_add_objective_sync_ok(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.objective.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = {'pkhash': pkhash}, status.HTTP_201_CREATED + with mock.patch('substrapp.serializers.ledger.utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'pkhash': pkhash} response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -97,11 +98,11 @@ def test_add_objective_no_sync_ok(self): extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.objective.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = ({ + with mock.patch('substrapp.serializers.ledger.utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = { 'message': 'Objective added in local db waiting for validation.' 'The substra network has been notified for adding this Objective' - }, status.HTTP_202_ACCEPTED) + } response = self.client.post(url, data, format='multipart', **extra) r = response.json() @@ -125,8 +126,8 @@ def test_add_objective_conflict(self): 'HTTP_ACCEPT': 'application/json;version=0.0', } - with mock.patch('substrapp.serializers.ledger.objective.util.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = {'pkhash': pkhash}, status.HTTP_201_CREATED + with mock.patch('substrapp.serializers.ledger.utils.invoke_ledger') as minvoke_ledger: + minvoke_ledger.return_value = {'pkhash': pkhash} response = self.client.post(url, data, format='multipart', **extra) r = response.json() diff --git a/substrabac/substrapp/tests/query/tests_query_tuples.py b/substrabac/substrapp/tests/query/tests_query_tuples.py index 2486d7268..77148e582 100644 --- a/substrabac/substrapp/tests/query/tests_query_tuples.py +++ b/substrabac/substrapp/tests/query/tests_query_tuples.py @@ -19,6 +19,7 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class TraintupleQueryTests(APITestCase): @@ -59,8 +60,8 @@ def test_add_traintuple_sync_ok(self): mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: raw_pkhash = 'traintuple_pkhash'.encode('utf-8').hex() - mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) - minvoke_ledger.return_value = ({'pkhash': raw_pkhash}, status.HTTP_201_CREATED) + mquery_ledger.return_value = {'key': raw_pkhash} + minvoke_ledger.return_value = {'pkhash': raw_pkhash} response = self.client.post(url, data, format='multipart', **extra) @@ -97,7 +98,7 @@ def test_add_traintuple_no_sync_ok(self): mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: raw_pkhash = 'traintuple_pkhash'.encode('utf-8').hex() - mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) + mquery_ledger.return_value = {'key': raw_pkhash} minvoke_ledger.return_value = None response = self.client.post(url, data, format='multipart', **extra) @@ -206,8 +207,8 @@ def test_add_testtuple_sync_ok(self): mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: raw_pkhash = 'testtuple_pkhash'.encode('utf-8').hex() - mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) - minvoke_ledger.return_value = ({'pkhash': raw_pkhash}, status.HTTP_201_CREATED) + mquery_ledger.return_value = {'key': raw_pkhash} + minvoke_ledger.return_value = {'pkhash': raw_pkhash} response = self.client.post(url, data, format='multipart', **extra) @@ -240,7 +241,7 @@ def test_add_testtuple_no_sync_ok(self): mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: raw_pkhash = 'testtuple_pkhash'.encode('utf-8').hex() - mquery_ledger.return_value = ({'key': raw_pkhash}, status.HTTP_200_OK) + mquery_ledger.return_value = {'key': raw_pkhash} minvoke_ledger.return_value = None response = self.client.post(url, data, format='multipart', **extra) diff --git a/substrabac/substrapp/tests/tests_misc.py b/substrabac/substrapp/tests/tests_misc.py index 4c61b5d99..77767fa2f 100644 --- a/substrabac/substrapp/tests/tests_misc.py +++ b/substrabac/substrapp/tests/tests_misc.py @@ -6,9 +6,7 @@ from substrapp.tests.common import JobStats, Stats, gpu -from rest_framework import status -from django.http import Http404 -from substrapp.utils import JsonException +from substrapp.ledger_utils import LedgerNotFound, LedgerBadResponse from substrapp.ledger_utils import get_object_from_ledger, log_fail_tuple, log_start_tuple, \ log_success_tuple, query_tuples @@ -79,61 +77,60 @@ def test_update_statistics(self): def test_get_object_from_ledger(self): with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'key': 'pk'}, status.HTTP_404_NOT_FOUND - - self.assertRaises(Http404, get_object_from_ledger, 'pk', 'fake_query') + mquery_ledger.side_effect = LedgerNotFound('Not Found') + self.assertRaises(LedgerNotFound, get_object_from_ledger, 'pk', 'fake_query') with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'key': 'pk'}, status.HTTP_400_BAD_REQUEST - self.assertRaises(JsonException, get_object_from_ledger, 'pk', 'fake_query') + mquery_ledger.side_effect = LedgerBadResponse('Bad Response') + self.assertRaises(LedgerBadResponse, get_object_from_ledger, 'pk', 'fake_query') with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'key': 'pk'}, status.HTTP_200_OK + mquery_ledger.return_value = {'key': 'pk'} data = get_object_from_ledger('pk', 'good_query') self.assertEqual(data['key'], 'pk') def test_log_fail_tuple(self): with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = None, status.HTTP_200_OK - data, st = log_fail_tuple('traintuple', 'pk', 'error_msg') + minvoke_ledger.return_value = None + log_fail_tuple('traintuple', 'pk', 'error_msg') with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = None, status.HTTP_200_OK - data, st = log_fail_tuple('testtuple', 'pk', 'error_msg') + minvoke_ledger.return_value = None + log_fail_tuple('testtuple', 'pk', 'error_msg') def test_log_start_tuple(self): with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = None, status.HTTP_200_OK - data, st = log_start_tuple('traintuple', 'pk') + minvoke_ledger.return_value = None + log_start_tuple('traintuple', 'pk') with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = None, status.HTTP_200_OK - data, st = log_start_tuple('testtuple', 'pk') + minvoke_ledger.return_value = None + log_start_tuple('testtuple', 'pk') def test_log_success_tuple(self): with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = None, status.HTTP_200_OK + minvoke_ledger.return_value = None res = { 'end_model_file_hash': 'hash', 'end_model_file': 'storageAddress', 'global_perf': '0.99', 'job_task_log': 'log', } - data, st = log_success_tuple('traintuple', 'pk', res) + log_success_tuple('traintuple', 'pk', res) with patch('substrapp.ledger_utils.invoke_ledger') as minvoke_ledger: - minvoke_ledger.return_value = None, status.HTTP_200_OK + minvoke_ledger.return_value = None res = { 'global_perf': '0.99', 'job_task_log': 'log', } - data, st = log_success_tuple('testtuple', 'pk', res) + log_success_tuple('testtuple', 'pk', res) def test_query_tuples(self): with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.return_value = None, status.HTTP_200_OK - data, st = query_tuples('traintuple', 'data_owner') + mquery_ledger.return_value = None + query_tuples('traintuple', 'data_owner') with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.return_value = None, status.HTTP_200_OK - data, st = query_tuples('testtuple', 'data_owner') + mquery_ledger.return_value = None + query_tuples('testtuple', 'data_owner') diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 7cc63b84f..000f25b19 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -12,6 +12,7 @@ from django_celery_results.models import TaskResult from substrapp.models import DataSample +from substrapp.ledger_utils import LedgerError, LedgerBadResponse from substrapp.utils import compute_hash, get_computed_hash, get_remote_file, get_hash, create_directory from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, @@ -527,7 +528,7 @@ def __init__(self): msettings.return_value = FakeSettings() mget_hash.return_value = 'owkinhash' - mquery_tuples.return_value = subtuple, 200 + mquery_tuples.return_value = subtuple mget_objective.return_value = 'objective' mget_algo.return_value = 'algo', 'algo_hash' mget_model.return_value = 'model', 'model_hash' @@ -546,12 +547,12 @@ def __init__(self): with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple, \ mock.patch('substrapp.tasks.tasks.log_fail_tuple') as mlog_fail_tuple: - mlog_start_tuple.side_effect = Exception("Test") - mlog_fail_tuple.return_value = 'data', 404 + mlog_start_tuple.side_effect = LedgerError("Test") + mlog_fail_tuple.return_value = 'data' prepare_task('traintuple') with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple: - mlog_start_tuple.return_value = 'data', 404 + mlog_start_tuple.side_effect = LedgerBadResponse('Bad Response') prepare_task('traintuple') with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple, \ diff --git a/substrabac/substrapp/tests/views/tests_views.py b/substrabac/substrapp/tests/views/tests_views.py index 38392fe25..5560252b6 100644 --- a/substrabac/substrapp/tests/views/tests_views.py +++ b/substrabac/substrapp/tests/views/tests_views.py @@ -1,10 +1,8 @@ import mock -from rest_framework import status from rest_framework.test import APITestCase -from substrapp.utils import JsonException from substrapp.views.utils import ComputeHashMixin from substrapp.views.datasample import path_leaf from substrapp.utils import compute_hash @@ -36,12 +34,7 @@ def test_utils_ComputeHashMixin(self): def test_utils_get_object_from_ledger(self): with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger.return_value = objective data = get_object_from_ledger('', 'queryObjective') self.assertEqual(data, objective) - - with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [('', status.HTTP_400_BAD_REQUEST)] - with self.assertRaises(JsonException): - get_object_from_ledger('', 'queryAllObjective') diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index 0e6e812d6..bef8eb799 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -13,7 +13,8 @@ from substrapp.serializers import LedgerAlgoSerializer -from substrapp.utils import JsonException +from substrapp.ledger_utils import LedgerError + from substrapp.utils import get_hash from ..common import get_sample_algo @@ -28,6 +29,7 @@ @override_settings(DRYRUN_ROOT=MEDIA_ROOT) @override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +@override_settings(LEDGER_SYNC_ENABLED=True) class AlgoViewTests(APITestCase): def setUp(self): @@ -51,8 +53,7 @@ def tearDown(self): def test_algo_list_empty(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] + mquery_ledger.side_effect = [None, ['ISIC']] response = self.client.get(url, **self.extra) r = response.json() @@ -65,7 +66,7 @@ def test_algo_list_empty(self): def test_algo_list_filter_fail(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger.return_value = algo search_params = '?search=algERRORo' response = self.client.get(url + search_params, **self.extra) @@ -76,7 +77,7 @@ def test_algo_list_filter_fail(self): def test_algo_list_filter_name(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger.return_value = algo search_params = '?search=algo%253Aname%253ALogistic%2520regression' response = self.client.get(url + search_params, **self.extra) @@ -87,7 +88,7 @@ def test_algo_list_filter_name(self): def test_algo_list_filter_dual(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger.return_value = algo search_params = '?search=algo%253Aname%253ALogistic%2520regression' search_params += f'%2Calgo%253Aowner%253A{algo[0]["owner"]}' @@ -100,8 +101,8 @@ def test_algo_list_filter_datamanager_fail(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger.return_value = algo + mquery_ledger2.return_value = datamanager search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -113,8 +114,8 @@ def test_algo_list_filter_objective_fail(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger.return_value = algo + mquery_ledger2.return_value = objective search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -126,8 +127,8 @@ def test_algo_list_filter_model(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(algo, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] + mquery_ledger.return_value = algo + mquery_ledger2.return_value = traintuple pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' @@ -174,7 +175,7 @@ def test_algo_retrieve_fail(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') + mget_object_from_ledger.side_effect = LedgerError('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../../fixtures/owkin/objectives/objective0/description.md")) @@ -201,8 +202,7 @@ def test_algo_create(self): with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: - mcreate.return_value = ({}, - status.HTTP_201_CREATED) + mcreate.return_value = {} response = self.client.post(url, data=data, format='multipart', **self.extra) diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index c3c7a8e07..f23009acb 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -10,7 +10,7 @@ from rest_framework import status from rest_framework.test import APITestCase -from substrapp.utils import JsonException +from substrapp.ledger_utils import LedgerError from substrapp.utils import get_hash @@ -49,8 +49,7 @@ def tearDown(self): def test_datamanager_list_empty(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] + mquery_ledger.side_effect = [None, ['ISIC']] response = self.client.get(url, **self.extra) r = response.json() @@ -63,7 +62,7 @@ def test_datamanager_list_empty(self): def test_datamanager_list_filter_fail(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger.return_value = datamanager search_params = '?search=dataseERRORt' response = self.client.get(url + search_params, **self.extra) @@ -74,7 +73,7 @@ def test_datamanager_list_filter_fail(self): def test_datamanager_list_filter_name(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger.return_value = datamanager search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -86,8 +85,8 @@ def test_datamanager_list_filter_objective(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger.return_value = datamanager + mquery_ledger2.return_value = objective search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -99,8 +98,8 @@ def test_datamanager_list_filter_model(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(datamanager, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] + mquery_ledger.return_value = datamanager + mquery_ledger2.return_value = traintuple pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' response = self.client.get(url + search_params, **self.extra) @@ -152,7 +151,7 @@ def test_datamanager_retrieve_fail(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') + mget_object_from_ledger.side_effect = LedgerError('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../../fixtures/owkin/objectives/objective0/description.md")) diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 61641ccc3..6eb038f29 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -29,6 +29,7 @@ @override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(DEFAULT_DOMAIN='https://localhost') +@override_settings(LEDGER_SYNC_ENABLED=True) class DataSampleViewTests(APITestCase): def setUp(self): @@ -78,8 +79,7 @@ def test_data_create_bulk(self): mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: mdatamanager.return_value = FakeFilterDataManager(1) - mcreate.return_value = ({'keys': [pkhash1, pkhash2]}, - status.HTTP_201_CREATED) + mcreate.return_value = {'keys': [pkhash1, pkhash2]} response = self.client.post(url, data=data, format='multipart', **self.extra) self.assertEqual([r['pkhash'] for r in response.data], [pkhash1, pkhash2]) self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -151,8 +151,7 @@ def test_data_create(self): mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: mdatamanager.return_value = FakeFilterDataManager(1) - mcreate.return_value = ({'keys': [pkhash]}, - status.HTTP_201_CREATED) + mcreate.return_value = {'keys': [pkhash]} response = self.client.post(url, data=data, format='multipart', **self.extra) self.assertEqual(response.data[0]['pkhash'], pkhash) @@ -187,8 +186,7 @@ def test_data_create_path(self): mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: mdatamanager.return_value = FakeFilterDataManager(1) - mcreate.return_value = ({'keys': [pkhash]}, - status.HTTP_201_CREATED) + mcreate.return_value = {'keys': [pkhash]} response = self.client.post(url, data=data, format='multipart', **self.extra) self.assertEqual(response.data[0]['pkhash'], pkhash) diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substrabac/substrapp/tests/views/tests_views_model.py index b08f41e15..57196c09e 100644 --- a/substrabac/substrapp/tests/views/tests_views_model.py +++ b/substrabac/substrapp/tests/views/tests_views_model.py @@ -10,7 +10,8 @@ from rest_framework import status from rest_framework.test import APITestCase -from substrapp.utils import JsonException +from substrapp.ledger_utils import LedgerError + from substrapp.utils import get_hash from ..common import get_sample_model @@ -47,8 +48,7 @@ def tearDown(self): def test_model_list_empty(self): url = reverse('substrapp:model-list') with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] + mquery_ledger.side_effect = [None, ['ISIC']] response = self.client.get(url, **self.extra) r = response.json() @@ -61,7 +61,7 @@ def test_model_list_empty(self): def test_model_list_filter_fail(self): with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + mquery_ledger.return_value = model url = reverse('substrapp:model-list') search_params = '?search=modeERRORl' @@ -72,7 +72,7 @@ def test_model_list_filter_fail(self): def test_model_list_filter_hash(self): with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] + mquery_ledger.return_value = model pkhash = model[0]['traintuple']['outModel']['hash'] url = reverse('substrapp:model-list') @@ -85,8 +85,8 @@ def test_model_list_filter_datamanager(self): url = reverse('substrapp:model-list') with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger.return_value = model + mquery_ledger2.return_value = datamanager search_params = '?search=dataset%253Aname%253AISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -98,8 +98,8 @@ def test_model_list_filter_objective(self): url = reverse('substrapp:model-list') with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger.return_value = model + mquery_ledger2.return_value = objective search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -111,8 +111,8 @@ def test_model_list_filter_algo(self): url = reverse('substrapp:model-list') with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(model, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(algo, status.HTTP_200_OK)] + mquery_ledger.return_value = model + mquery_ledger2.return_value = algo search_params = '?search=algo%253Aname%253ALogistic%2520regression' response = self.client.get(url + search_params, **self.extra) @@ -155,7 +155,7 @@ def test_model_retrieve_fail(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') + mget_object_from_ledger.side_effect = LedgerError('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../../fixtures/owkin/objectives/objective0/description.md")) diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 232ec610d..e595fdf2f 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -13,7 +13,8 @@ from substrapp.serializers import LedgerObjectiveSerializer -from substrapp.utils import JsonException +from substrapp.ledger_utils import LedgerError + from substrapp.views.objective import compute_dryrun as objective_compute_dryrun from substrapp.utils import compute_hash, get_hash @@ -31,6 +32,7 @@ @override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(DEFAULT_DOMAIN='https://localhost') +@override_settings(LEDGER_SYNC_ENABLED=True) class ObjectiveViewTests(APITestCase): def setUp(self): @@ -61,8 +63,7 @@ def tearDown(self): def test_objective_list_empty(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(None, status.HTTP_200_OK), - (['ISIC'], status.HTTP_200_OK)] + mquery_ledger.side_effect = [None, ['ISIC']] response = self.client.get(url, **self.extra) r = response.json() @@ -75,7 +76,7 @@ def test_objective_list_empty(self): def test_objective_list_filter_fail(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger.return_value = objective search_params = '?search=challenERRORge' response = self.client.get(url + search_params, **self.extra) @@ -86,7 +87,7 @@ def test_objective_list_filter_fail(self): def test_objective_list_filter_name(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger.return_value = objective search_params = '?search=objective%253Aname%253ASkin%2520Lesion%2520Classification%2520Objective' response = self.client.get(url + search_params, **self.extra) @@ -97,7 +98,7 @@ def test_objective_list_filter_name(self): def test_objective_list_filter_metrics(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] + mquery_ledger.return_value = objective search_params = '?search=objective%253Ametrics%253Amacro-average%2520recall' response = self.client.get(url + search_params, **self.extra) @@ -109,8 +110,8 @@ def test_objective_list_filter_datamanager(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(datamanager, status.HTTP_200_OK)] + mquery_ledger.return_value = objective + mquery_ledger2.return_value = datamanager search_params = '?search=dataset%253Aname%253ASimplified%2520ISIC%25202018' response = self.client.get(url + search_params, **self.extra) @@ -122,8 +123,8 @@ def test_objective_list_filter_model(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: - mquery_ledger.side_effect = [(objective, status.HTTP_200_OK)] - mquery_ledger2.side_effect = [(traintuple, status.HTTP_200_OK)] + mquery_ledger.return_value = objective + mquery_ledger2.return_value = traintuple pkhash = model[0]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' @@ -168,7 +169,7 @@ def test_objective_retrieve_fail(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') + mget_object_from_ledger.side_effect = LedgerError('TEST') file_hash = get_hash(os.path.join(dir_path, "../../../../fixtures/owkin/objectives/objective0/description.md")) @@ -202,8 +203,7 @@ def test_objective_create(self): with mock.patch.object(LedgerObjectiveSerializer, 'create') as mcreate: - mcreate.return_value = ({}, - status.HTTP_201_CREATED) + mcreate.return_value = {} response = self.client.post(url, data=data, format='multipart', **self.extra) diff --git a/substrabac/substrapp/tests/views/tests_views_tuples.py b/substrabac/substrapp/tests/views/tests_views_tuples.py index bc4280939..7f2854967 100644 --- a/substrabac/substrapp/tests/views/tests_views_tuples.py +++ b/substrabac/substrapp/tests/views/tests_views_tuples.py @@ -12,9 +12,9 @@ from substrapp.views import TrainTupleViewSet, TestTupleViewSet -from substrapp.utils import JsonException from substrapp.utils import get_hash +from substrapp.ledger_utils import LedgerError from ..assets import traintuple, testtuple @@ -50,7 +50,7 @@ def test_traintuple_queryset(self): def test_traintuple_list_empty(self): url = reverse('substrapp:traintuple-list') with mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: - mquery_ledger.return_value = ([[]], status.HTTP_200_OK) + mquery_ledger.return_value = [[]] response = self.client.get(url, **self.extra) r = response.json() @@ -82,7 +82,7 @@ def test_traintuple_retrieve_fail(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) with mock.patch('substrapp.views.traintuple.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') + mget_object_from_ledger.side_effect = LedgerError('Test') file_hash = get_hash(os.path.join(dir_path, "../../../../fixtures/owkin/objectives/objective0/description.md")) @@ -121,7 +121,7 @@ def test_testtuple_queryset(self): def test_testtuple_list_empty(self): url = reverse('substrapp:testtuple-list') with mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: - mquery_ledger.return_value = ([[]], status.HTTP_200_OK) + mquery_ledger.return_value = [[]] response = self.client.get(url, **self.extra) r = response.json() @@ -153,7 +153,7 @@ def test_testtuple_retrieve_fail(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) with mock.patch('substrapp.views.testtuple.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.side_effect = JsonException('TEST') + mget_object_from_ledger.side_effect = LedgerError('Test') file_hash = get_hash(os.path.join(dir_path, "../../../../fixtures/owkin/objectives/objective0/description.md")) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 35eefb212..14fe2284d 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -70,7 +70,7 @@ def create(self, request, *args, **kwargs): try: data = ledger_serializer.create(ledger_serializer.validated_data) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) st = get_success_create_code() headers = self.get_success_headers(serializer.data) @@ -117,7 +117,7 @@ def retrieve(self, request, *args, **kwargs): try: data = get_object_from_ledger(pk, self.ledger_query_call) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) # try to get it from local db to check if description exists try: @@ -145,7 +145,7 @@ def list(self, request, *args, **kwargs): try: data = query_ledger(fcn='queryAlgos', args=[]) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) data = data if data else [] @@ -161,7 +161,7 @@ def list(self, request, *args, **kwargs): data=data, query_params=query_params) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) except Exception as e: logging.exception(e) return Response( diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 5eb94c484..062cb1d26 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -104,7 +104,7 @@ def create(self, request, *args, **kwargs): try: data = ledger_serializer.create(ledger_serializer.validated_data) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) st = get_success_create_code() @@ -179,7 +179,7 @@ def retrieve(self, request, *args, **kwargs): try: data = get_object_from_ledger(pk, 'queryDataset') except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) # try to get it from local db to check if description exists try: @@ -207,7 +207,7 @@ def list(self, request, *args, **kwargs): try: data = query_ledger(fcn='queryDataManagers', args=[]) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) data = data if data else [] @@ -223,7 +223,7 @@ def list(self, request, *args, **kwargs): data=data, query_params=query_params) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) except Exception as e: logging.exception(e) return Response( @@ -250,7 +250,7 @@ def update_ledger(self, request, *args, **kwargs): try: data = updateLedgerDataManager(args, sync=True) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 0974d0ab0..ac5e6f048 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -69,11 +69,10 @@ def commit(serializer, ledger_data): try: data = ledger_serializer.create(ledger_serializer.validated_data) except LedgerTimeout as e: - data = {'message': str(e)} - data.update({'pkhash': [x['pkhash'] for x in serializer.data]}) + data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) except LedgerError as e: - raise LedgerException({'message': str(e)}, e.status) + raise LedgerException(str(e.msg), e.status) st = get_success_create_code() @@ -205,7 +204,7 @@ def create(self, request, *args, **kwargs): except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: - return Response({'message': str(e)}, status=e.st) + return Response({'message': e.data}, status=e.st) except Exception as e: return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: @@ -255,7 +254,7 @@ def bulk_update(self, request): try: data = updateLedgerDataSample(args, sync=True) except LedgerError as e: - return Response({'message': str(e)}, status=e.st) + return Response({'message': str(e.msg)}, status=e.st) return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 921dab61c..e401b52f0 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -66,7 +66,7 @@ def retrieve(self, request, *args, **kwargs): try: data = get_object_from_ledger(pk, self.ledger_query_call) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) # Try to get it from local db, else create it in local db try: @@ -93,7 +93,7 @@ def list(self, request, *args, **kwargs): try: data = query_ledger(fcn='queryModels', args=[]) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) data = data if data else [] @@ -107,7 +107,7 @@ def list(self, request, *args, **kwargs): data=data, query_params=query_params) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) except Exception as e: logging.exception(e) return Response( @@ -130,6 +130,6 @@ def details(self, request, *args, **kwargs): try: data = query_ledger(fcn='queryModelDetails', args=[f'{pk}']) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 6090ad5b2..1bc9bd475 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -117,7 +117,7 @@ def create(self, request, *args, **kwargs): try: data = ledger_serializer.create(ledger_serializer.validated_data) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) st = get_success_create_code() # return response with local db and ledger data information @@ -165,7 +165,7 @@ def retrieve(self, request, *args, **kwargs): try: data = get_object_from_ledger(pk, self.ledger_query_call) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) # try to get it from local db to check if description exists try: @@ -191,7 +191,7 @@ def list(self, request, *args, **kwargs): try: data = query_ledger(fcn='queryObjectives', args=[]) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) data = data if data else [] @@ -205,7 +205,7 @@ def list(self, request, *args, **kwargs): data=data, query_params=query_params) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) except Exception as e: logging.exception(e) return Response( diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 2e350ef4e..228ecb56e 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -38,9 +38,9 @@ def create(self, request, *args, **kwargs): try: data = query_ledger(fcn='createTesttuple', args=args) except LedgerConflict as e: - return Response({'message': str(e), 'pkhash': e.pkhash}, status=e.status) + return Response({'message': str(e.msg), 'pkhash': e.pkhash}, status=e.status) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) pkhash = data.get('key') @@ -48,7 +48,7 @@ def create(self, request, *args, **kwargs): try: data = serializer.create(serializer.validated_data) except LedgerError as e: - return Response({'message': str(e), 'pkhash': pkhash}, status=e.status) + return Response({'message': str(e.msg), 'pkhash': pkhash}, status=e.status) st = get_success_create_code() @@ -59,7 +59,7 @@ def list(self, request, *args, **kwargs): try: data = query_ledger(fcn='queryTesttuples', args=[]) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) data = data if data else [] return Response(data, status=status.HTTP_200_OK) @@ -77,6 +77,6 @@ def retrieve(self, request, *args, **kwargs): try: data = get_object_from_ledger(pk, self.ledger_query_call) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) else: return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 79e2d6875..ab559d466 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -42,9 +42,9 @@ def create(self, request, *args, **kwargs): try: data = query_ledger(fcn='createTraintuple', args=args) except LedgerConflict as e: - return Response({'message': str(e), 'pkhash': e.pkhash}, status=e.status) + return Response({'message': str(e.msg), 'pkhash': e.pkhash}, status=e.status) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) pkhash = data.get('key') @@ -52,7 +52,7 @@ def create(self, request, *args, **kwargs): try: data = serializer.create(serializer.validated_data) except LedgerError as e: - return Response({'message': str(e), 'pkhash': pkhash}, status=e.status) + return Response({'message': str(e.msg), 'pkhash': pkhash}, status=e.status) st = get_success_create_code() @@ -64,7 +64,7 @@ def list(self, request, *args, **kwargs): try: data = query_ledger(fcn='queryTraintuples', args=[]) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) data = data if data else [] @@ -83,6 +83,6 @@ def retrieve(self, request, *args, **kwargs): try: data = get_object_from_ledger(pk, self.ledger_query_call) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) else: return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 4b506df26..d8521024e 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -43,7 +43,7 @@ def manage_file(self, field): try: get_object_from_ledger(pk, self.ledger_query_call) except LedgerError as e: - return Response({'message': str(e)}, status=e.status) + return Response({'message': str(e.msg)}, status=e.status) else: obj = self.get_object() From 18d02604280e264fa59354705f149f6583fd52cb Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 7 Jun 2019 15:18:22 +0200 Subject: [PATCH 085/457] fix after review --- substrabac/.coveragerc | 1 - substrabac/substrapp/ledger_utils.py | 20 ++++++++++++------- .../serializers/ledger/datamanager/util.py | 4 ---- .../serializers/ledger/datasample/util.py | 4 ---- substrabac/substrapp/tasks/tasks.py | 9 ++------- substrabac/substrapp/views/datamanager.py | 11 ++++++---- substrabac/substrapp/views/datasample.py | 18 +++++++---------- 7 files changed, 29 insertions(+), 38 deletions(-) diff --git a/substrabac/.coveragerc b/substrabac/.coveragerc index ae10b6470..809edc1ed 100644 --- a/substrabac/.coveragerc +++ b/substrabac/.coveragerc @@ -4,7 +4,6 @@ source = ./substrapp/ omit = - #./substrapp/serializers/ledger/* ./substrapp/tests/generate_assets.py ./substrapp/management/* diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 393f5cd24..ad1842bec 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -127,8 +127,11 @@ def query_ledger(fcn, args=None): def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): params = { 'wait_for_event': sync, - 'wait_for_event_timeout': 45, } + + if sync: + params['wait_for_event_timeout'] = 45 + if cc_pattern: params['cc_pattern'] = cc_pattern @@ -161,8 +164,8 @@ def log_success_tuple(tuple_type, tuple_key, res): invoke_args = { 'key': tuple_key, 'outModel': { - 'hash': f'{res["end_model_file_hash"]}', - 'storageAddress': f'{res["end_model_file"]}', + 'hash': res["end_model_file_hash"], + 'storageAddress': res["end_model_file"], }, 'perf': float(res["global_perf"]), 'log': f'Train - {res["job_task_log"]};', @@ -192,10 +195,13 @@ def log_start_tuple(tuple_type, tuple_key): else: raise NotImplementedError() - return invoke_ledger( - fcn=start_type, - args={'key': tuple_key}, - sync=True) + try: + invoke_ledger( + fcn=start_type, + args={'key': tuple_key}, + sync=True) + except LedgerTimeout: + pass def query_tuples(tuple_type, data_owner): diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substrabac/substrapp/serializers/ledger/datamanager/util.py index d77d68155..e762dc98e 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/util.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/util.py @@ -16,8 +16,4 @@ def createLedgerDataManager(args, pkhash, sync=False): def updateLedgerDataManager(args, sync=False): - args = { - 'dataManagerKey': args[0], - 'objectiveKey': args[1], - } return invoke_ledger(fcn='updateDataManager', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substrabac/substrapp/serializers/ledger/datasample/util.py index 598ff2383..ac05b7b62 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/util.py +++ b/substrabac/substrapp/serializers/ledger/datasample/util.py @@ -15,8 +15,4 @@ def createLedgerDataSample(args, pkhashes, sync=False): def updateLedgerDataSample(args, sync=False): - args = { - 'hashes': args[0], - 'dataManagerKeys': args[1], - } return invoke_ledger(fcn='updateDataSample', args=args, sync=sync) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 4eecad91a..cd46852f6 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -13,7 +13,7 @@ from substrabac.celery import app from substrapp.utils import get_hash, create_directory, get_remote_file, uncompress_content from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, - query_tuples, LedgerTimeout, LedgerError) + query_tuples, LedgerError) from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code @@ -225,20 +225,15 @@ def prepare_tuple(subtuple, tuple_type): worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] try: - compute = True try: log_start_tuple(tuple_type, subtuple['key']) - except LedgerTimeout: - pass except LedgerError as e: # Do not log_fail_tuple in this case, because prepare_tuple task are not unique # in case of multiple instances of substrabac running for the same organisation # So prepare_tuple tasks are ignored if it cannot log_start_tuple # TODO: find a way to handle this special case to avoid silent failure in other cases. logging.exception(e) - compute = False - - if compute: + else: compute_task.apply_async( (tuple_type, subtuple, fltask), queue=worker_queue) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 062cb1d26..ef1d7d498 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -244,15 +244,17 @@ def update_ledger(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) objective_key = request.data.get('objective_key') - args = [pk, objective_key] + args = { + 'dataManagerKey': pk, + 'objectiveKey': objective_key, + } if getattr(settings, 'LEDGER_SYNC_ENABLED'): try: data = updateLedgerDataManager(args, sync=True) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - - return Response(data, status=status.HTTP_200_OK) + st = status.HTTP_200_OK else: # use a celery task, as we are in an http request transaction @@ -261,7 +263,8 @@ def update_ledger(self, request, *args, **kwargs): 'message': 'The substra network has been notified for updating this DataManager' } st = status.HTTP_202_ACCEPTED - return Response(data, status=st) + + return Response(data, status=st) @action(detail=True) def description(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index ac5e6f048..b5898bb07 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -241,22 +241,17 @@ def bulk_update(self, request): except Exception as e: return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: - # args = '"%(hashes)s", "%(dataManagerKeys)s"' % { - # 'hashes': ','.join(data_sample_keys), - # 'dataManagerKeys': ','.join(data_manager_keys), - # } - - args = [ - ','.join(data_sample_keys), - ','.join(data_manager_keys) - ] + args = { + 'hashes': ','.join(data_sample_keys), + 'dataManagerKeys': ','.join(data_manager_keys), + } if getattr(settings, 'LEDGER_SYNC_ENABLED'): try: data = updateLedgerDataSample(args, sync=True) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.st) - return Response(data, status=status.HTTP_200_OK) + st = status.HTTP_200_OK else: # use a celery task, as we are in an http request transaction @@ -265,7 +260,8 @@ def bulk_update(self, request): 'message': 'The substra network has been notified for updating these Data' } st = status.HTTP_202_ACCEPTED - return Response(data, status=st) + + return Response(data, status=st) def path_leaf(path): From 5de2dc2af37bacf396a749d8f48975b675039c36 Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 7 Jun 2019 15:40:47 +0200 Subject: [PATCH 086/457] more fixes after review --- .../substrapp/serializers/ledger/traintuple/serializer.py | 4 ++-- substrabac/substrapp/tasks/tasks.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index 4343c23c9..f48e6a932 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -25,7 +25,7 @@ def get_args(self, validated_data): data_manager_key = validated_data.get('data_manager_key') objective_key = validated_data.get('objective_key') rank = validated_data.get('rank', '') - rank = '' if rank is None else rank # rank should be an integer or empty string, not None + rank = '' if rank is None else str(rank) FLtask_key = validated_data.get('FLtask_key', '') train_data_sample_keys = validated_data.get('train_data_sample_keys', []) in_models_keys = validated_data.get('in_models_keys', []) @@ -38,7 +38,7 @@ def get_args(self, validated_data): 'dataManagerKey': data_manager_key, 'dataSampleKeys': ','.join([x for x in train_data_sample_keys]), 'flTask': FLtask_key, - 'rank': str(rank), + 'rank': rank, 'tag': tag } diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index cd46852f6..c2ba9f924 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -186,8 +186,8 @@ def remove_subtuple_materials(subtuple_directory): resources_manager = manager.ResourcesManager() -@app.task(bind=True, ignore_result=True) -def prepare_training_task(self): +@app.task(ignore_result=True) +def prepare_training_task(): prepare_task('traintuple') From 31fde35222c8a38b0742fad926d38fb021c4bead Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 11 Jun 2019 10:47:53 +0200 Subject: [PATCH 087/457] basic auth required by default when querying node --- substrabac/substrapp/utils.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 69b3e52ad..1992b1280 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -70,19 +70,7 @@ def compute_hash(bytes, key=None): def get_computed_hash(url, key=None): - username = getattr(settings, 'BASICAUTH_USERNAME', None) - password = getattr(settings, 'BASICAUTH_PASSWORD', None) - - kwargs = {} - - if username is not None and password is not None: - kwargs.update({'auth': (username, password)}) - - if settings.DEBUG: - kwargs.update({'verify': False}) - - response = get_from_node(url, **kwargs) - + response = get_from_node(url) computedHash = compute_hash(response.content, key) return response.content, computedHash @@ -135,10 +123,22 @@ class NodeError(Exception): pass -def get_from_node(url, **kwargs): +def get_from_node(url): + + kwargs = { + 'headers': {'Accept': 'application/json;version=0.0'}, + } + + username = getattr(settings, 'BASICAUTH_USERNAME', None) + password = getattr(settings, 'BASICAUTH_PASSWORD', None) + if username is not None and password is not None: + kwargs['auth'] = (username, password) + + if settings.DEBUG: + kwargs['verify'] = False try: - response = requests.get(url, headers={'Accept': 'application/json;version=0.0'}, **kwargs) + response = requests.get(url, **kwargs) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: raise NodeError(f'Failed to fetch {url}') from e else: From 9d1d508129f0a40189078b0235a3410cbf25414d Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 11 Jun 2019 14:59:10 +0200 Subject: [PATCH 088/457] fix buggy refactoring in datasample bulk_update - `','.join(` call was done twice - getlist raise a single exception: django.utils.datastructures.MultiValueDictKeyError, subsclass of KeyError --- substrabac/substrapp/views/datasample.py | 27 ++++++++++-------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index b5898bb07..a9193f824 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -212,30 +212,24 @@ def create(self, request, *args, **kwargs): return Response(data, status=st, headers=headers) def validate_bulk_update(self, data): - # validation try: - data_manager_keys = data.getlist('data_manager_keys', []) - except Exception: - raise Exception('Please pass a valid data_manager_keys key param') - else: - data_manager_keys = ','.join(data_manager_keys) - if not data_manager_keys: - raise Exception('Please pass a non empty data_manager_keys key param') + data_manager_keys = data.getlist('data_manager_keys') + except KeyError: + data_manager_keys = [] + if not data_manager_keys: + raise Exception('Please pass a non empty data_manager_keys key param') try: - data_sample_keys = data.getlist('data_sample_keys', []) - except Exception: - raise Exception('Please pass a valid data_sample_keys key param') - else: - data_sample_keys = ','.join(data_sample_keys) - if not data_sample_keys: - raise Exception('Please pass a non empty data_sample_keys key param') + data_sample_keys = data.getlist('data_sample_keys') + except KeyError: + data_sample_keys = [] + if not data_sample_keys: + raise Exception('Please pass a non empty data_sample_keys key param') return data_manager_keys, data_sample_keys @action(methods=['post'], detail=False) def bulk_update(self, request): - try: data_manager_keys, data_sample_keys = self.validate_bulk_update(request.data) except Exception as e: @@ -245,6 +239,7 @@ def bulk_update(self, request): 'hashes': ','.join(data_sample_keys), 'dataManagerKeys': ','.join(data_manager_keys), } + if getattr(settings, 'LEDGER_SYNC_ENABLED'): try: data = updateLedgerDataSample(args, sync=True) From cc5df27a7d19be5d88d53a40406534d0e1ce734b Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 11 Jun 2019 21:09:32 +0200 Subject: [PATCH 089/457] Refacto create and retrieve views --- substrabac/substrapp/views/algo.py | 136 ++++++++++-------- substrabac/substrapp/views/datamanager.py | 161 +++++++++++---------- substrabac/substrapp/views/datasample.py | 2 +- substrabac/substrapp/views/model.py | 48 +++---- substrabac/substrapp/views/objective.py | 168 ++++++++++++---------- substrabac/substrapp/views/testtuple.py | 57 +++++--- substrabac/substrapp/views/traintuple.py | 54 ++++--- 7 files changed, 348 insertions(+), 278 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 14fe2284d..504ed100a 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -11,9 +11,9 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer from substrapp.utils import get_hash, get_from_node -from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout from substrapp.views.utils import (ComputeHashMixin, ManageFileMixin, find_primary_key_error, - validate_pk, get_success_create_code) + validate_pk, get_success_create_code, LedgerException, ValidationException) from substrapp.views.filters_utils import filter_list @@ -30,37 +30,13 @@ class AlgoViewSet(mixins.CreateModelMixin, def perform_create(self, serializer): return serializer.save() - def create(self, request, *args, **kwargs): - - file = request.data.get('file') - pkhash = get_hash(file) - serializer = self.get_serializer(data={ - 'pkhash': pkhash, - 'file': file, - 'description': request.data.get('description') - }) - - try: - serializer.is_valid(raise_exception=True) - except Exception as e: - st = status.HTTP_400_BAD_REQUEST - if find_primary_key_error(e): - st = status.HTTP_409_CONFLICT - return Response({'message': e.args, 'pkhash': pkhash}, status=st) - + def commit(self, serializer, ledger_data): # create on db - try: - instance = self.perform_create(serializer) - except Exception as e: - return Response({'message': e.args}, - status=status.HTTP_400_BAD_REQUEST) + instance = self.perform_create(serializer) # init ledger serializer - ledger_serializer = LedgerAlgoSerializer(data={ - 'name': request.data.get('name'), - 'permissions': request.data.get('permissions', 'all'), - 'instance': instance - }, context={'request': request}) + ledger_data.update({'instance': instance}) + ledger_serializer = LedgerAlgoSerializer(data=ledger_data) if not ledger_serializer.is_valid(): # delete instance instance.delete() @@ -69,15 +45,57 @@ def create(self, request, *args, **kwargs): # create on ledger try: data = ledger_serializer.create(ledger_serializer.validated_data) + except LedgerTimeout as e: + data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} + raise LedgerException(data, e.status) except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) + raise LedgerException(str(e.msg), e.status) st = get_success_create_code() - headers = self.get_success_headers(serializer.data) + d = dict(serializer.data) d.update(data) - return Response(d, status=st, headers=headers) + return d, st + + def _create(self, request, file): + pkhash = get_hash(file) + serializer = self.get_serializer(data={ + 'pkhash': pkhash, + 'file': file, + 'description': request.data.get('description') + }) + + try: + serializer.is_valid(raise_exception=True) + except Exception as e: + st = status.HTTP_400_BAD_REQUEST + if find_primary_key_error(e): + st = status.HTTP_409_CONFLICT + raise ValidationException(e.args, pkhash, st) + else: + # create on ledger + db + ledger_data = { + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions', 'all'), + } + data, st = self.commit(serializer, ledger_data) + return data, st + + def create(self, request, *args, **kwargs): + file = request.data.get('file') + + try: + data, st = self._create(request, file) + except ValidationException as e: + return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) + except LedgerException as e: + return Response({'message': e.data}, status=e.st) + except Exception as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + else: + headers = self.get_success_headers(data) + return Response(data, status=st, headers=headers) def create_or_update_algo(self, algo, pk): # get algo description from remote node @@ -104,42 +122,40 @@ def create_or_update_algo(self, algo, pk): return instance - def retrieve(self, request, *args, **kwargs): - lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field - pk = self.kwargs[lookup_url_kwarg] - - try: - validate_pk(pk) - except Exception as e: - return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) - - # get instance from remote node - try: - data = get_object_from_ledger(pk, self.ledger_query_call) - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) + def _retrieve(self, pk): + validate_pk(pk) + data = get_object_from_ledger(pk, self.ledger_query_call) # try to get it from local db to check if description exists try: instance = self.get_object() except Http404: instance = None - - # check if instance has description - if not instance or not instance.description: - try: + finally: + # check if instance has description + if not instance or not instance.description: instance = self.create_or_update_algo(data, pk) - except Exception as e: - logging.exception(e) - return Response(str(e), status=status.HTTP_400_BAD_REQUEST) - # For security reason, do not give access to local file address - # Restrain data to some fields - # TODO: do we need to send creation date and/or last modified date ? - serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) - data.update(serializer.data) + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date ? + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) + data.update(serializer.data) + + return data + + def retrieve(self, request, *args, **kwargs): + lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field + pk = self.kwargs[lookup_url_kwarg] - return Response(data, status=status.HTTP_200_OK) + try: + data = self._retrieve(pk) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + else: + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): try: diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index ef1d7d498..032fded2e 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -16,9 +16,9 @@ from substrapp.serializers.ledger.datamanager.util import updateLedgerDataManager from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync from substrapp.utils import get_hash, get_from_node -from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout from substrapp.views.utils import (ManageFileMixin, ComputeHashMixin, find_primary_key_error, - validate_pk, get_success_create_code) + validate_pk, get_success_create_code, ValidationException, LedgerException) from substrapp.views.filters_utils import filter_list @@ -35,31 +35,52 @@ class DataManagerViewSet(mixins.CreateModelMixin, def perform_create(self, serializer): return serializer.save() - def dryrun(self, data_opener): + def handle_dryrun(self, data_opener): file = data_opener.open().read() try: node = ast.parse(file) except BaseException: - return Response({ - 'message': f'Opener must be a valid python file, please review your opener file and the documentation.' - }, status=status.HTTP_400_BAD_REQUEST) + raise Exception('Opener must be a valid python file, please review your opener file and the documentation.') imported_module_names = [m.name for e in node.body if isinstance(e, ast.Import) for m in e.names] if 'substratools' not in imported_module_names: - return Response({ - 'message': 'Opener must import substratools, please review your opener and the documentation.' - }, status=status.HTTP_400_BAD_REQUEST) + return { + 'message': 'Opener must import substratools, please review your opener and the documentation.' + }, status.HTTP_400_BAD_REQUEST - return Response({ - 'message': f'Your data opener is valid. You can remove the dryrun option.' - }, status=status.HTTP_200_OK) + return {'message': f'Your data opener is valid. You can remove the dryrun option.'}, status.HTTP_200_OK - def create(self, request, *args, **kwargs): - dryrun = request.data.get('dryrun', False) - data_opener = request.data.get('data_opener') + def commit(self, serializer, ledger_data): + # create on db + instance = self.perform_create(serializer) + # init ledger serializer + ledger_data.update({'instance': instance}) + ledger_serializer = LedgerDataManagerSerializer(data=ledger_data) + + if not ledger_serializer.is_valid(): + # delete instance + instance.delete() + raise ValidationError(ledger_serializer.errors) + + # create on ledger + try: + data = ledger_serializer.create(ledger_serializer.validated_data) + except LedgerTimeout as e: + data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} + raise LedgerException(data, e.status) + except LedgerError as e: + raise LedgerException(str(e.msg), e.status) + + st = get_success_create_code() + + d = dict(serializer.data) + d.update(data) + + return d, st + def _create(self, request, data_opener, dryrun): pkhash = get_hash(data_opener) serializer = self.get_serializer(data={ 'pkhash': pkhash, @@ -74,45 +95,36 @@ def create(self, request, *args, **kwargs): st = status.HTTP_400_BAD_REQUEST if find_primary_key_error(e): st = status.HTTP_409_CONFLICT - return Response({'message': e.args, 'pkhash': pkhash}, status=st) + raise ValidationException(e.args, pkhash, st) + else: + if dryrun: + return self.handle_dryrun(data_opener) + + # create on ledger + db + ledger_data = { + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions'), + 'type': request.data.get('type'), + 'objective_keys': request.data.getlist('objective_keys'), + } + data, st = self.commit(serializer, ledger_data) + return data, st - if dryrun: - return self.dryrun(data_opener) + def create(self, request, *args, **kwargs): + dryrun = request.data.get('dryrun', False) + data_opener = request.data.get('data_opener') - # create on db try: - instance = self.perform_create(serializer) + data, st = self._create(request, data_opener, dryrun) + except ValidationException as e: + return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) + except LedgerException as e: + return Response({'message': e.data}, status=e.st) except Exception as e: - return Response({'message': e.args}, - status=status.HTTP_400_BAD_REQUEST) - - # init ledger serializer - ledger_serializer = LedgerDataManagerSerializer(data={ - 'name': request.data.get('name'), - 'permissions': request.data.get('permissions'), - 'type': request.data.get('type'), - 'objective_keys': request.data.getlist('objective_keys'), - 'instance': instance - }, context={'request': request}) - - if not ledger_serializer.is_valid(): - # delete instance - instance.delete() - raise ValidationError(ledger_serializer.errors) - - # create on ledger - try: - data = ledger_serializer.create(ledger_serializer.validated_data) - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) - - st = get_success_create_code() - - headers = self.get_success_headers(serializer.data) - d = dict(serializer.data) - d.update(data) - - return Response(d, status=st, headers=headers) + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + else: + headers = self.get_success_headers(data) + return Response(data, status=st, headers=headers) def create_or_update_datamanager(self, instance, datamanager, pk): @@ -166,41 +178,38 @@ def create_or_update_datamanager(self, instance, datamanager, pk): return instance - def retrieve(self, request, *args, **kwargs): - lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field - pk = self.kwargs[lookup_url_kwarg] - - try: - validate_pk(pk) - except Exception as e: - return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) - + def _retrieve(self, pk): + validate_pk(pk) # get instance from remote node - try: - data = get_object_from_ledger(pk, 'queryDataset') - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) - + data = get_object_from_ledger(pk, 'queryDataset') # try to get it from local db to check if description exists try: instance = self.get_object() except Http404: instance = None - - # check if instance has description or data_opener - if not instance or not instance.description or not instance.data_opener: - try: + finally: + # check if instance has description or data_opener + if not instance or not instance.description or not instance.data_opener: instance = self.create_or_update_datamanager(instance, data, pk) - except Exception as e: - return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) - # do not give access to local files address - serializer = self.get_serializer( - instance, - fields=('owner', 'pkhash', 'creation_date', 'last_modified')) - data.update(serializer.data) + # do not give access to local files address + serializer = self.get_serializer(instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + data.update(serializer.data) + + return data + + def retrieve(self, request, *args, **kwargs): + lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field + pk = self.kwargs[lookup_url_kwarg] - return Response(data, status=status.HTTP_200_OK) + try: + data = self._retrieve(pk) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + except Exception as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + else: + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index a9193f824..e2aba1c43 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -161,7 +161,7 @@ def handle_dryrun(self, data, data_manager_keys): try: task, msg = self.dryrun_task(data_dry_run, data_manager_keys) except Exception as e: - return Exception(f'Could not launch data creation with dry-run on this instance: {str(e)}') + raise Exception(f'Could not launch data creation with dry-run on this instance: {str(e)}') else: return {'id': task.id, 'message': msg}, status.HTTP_202_ACCEPTED diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index e401b52f0..62de758c2 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -53,41 +53,41 @@ def create_or_update_model(self, traintuple, pk): return instance - def retrieve(self, request, *args, **kwargs): - lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field - pk = self.kwargs[lookup_url_kwarg] - - try: - validate_pk(pk) - except Exception as e: - return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) - + def _retrieve(self, pk): + validate_pk(pk) # get instance from remote node - try: - data = get_object_from_ledger(pk, self.ledger_query_call) - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) + data = get_object_from_ledger(pk, self.ledger_query_call) # Try to get it from local db, else create it in local db try: instance = self.get_object() except Http404: instance = None - - if not instance or not instance.file: - try: + finally: + if not instance or not instance.file: instance = self.create_or_update_model(data['traintuple'], data['traintuple']['outModel']['hash']) - except Exception as e: - Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) - # For security reason, do not give access to local file address - # Restrain data to some fields - # TODO: do we need to send creation date and/or last modified date ? - serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) - data.update(serializer.data) + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date ? + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) + data.update(serializer.data) - return Response(data, status=status.HTTP_200_OK) + return data + + def retrieve(self, request, *args, **kwargs): + lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field + pk = self.kwargs[lookup_url_kwarg] + + try: + data = self._retrieve(pk) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + else: + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): try: diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 1bc9bd475..70af9c2cf 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -22,11 +22,11 @@ from substrapp.models import Objective from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer -from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout from substrapp.utils import get_hash, get_computed_hash, get_from_node from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ - get_success_create_code + get_success_create_code, ValidationException, LedgerException from substrapp.views.filters_utils import filter_list @@ -44,46 +44,25 @@ class ObjectiveViewSet(mixins.CreateModelMixin, def perform_create(self, serializer): return serializer.save() - def create(self, request, *args, **kwargs): - metrics = request.data.get('metrics') - description = request.data.get('description') - pkhash = get_hash(description) - test_data_manager_key = request.data.get('test_data_manager_key', '') - - # try to serialize in local db to check that it is valid - serializer = self.get_serializer(data={'pkhash': pkhash, - 'metrics': metrics, - 'description': description}) + def handle_dryrun(self, pkhash, metrics, test_data_manager_key): try: - serializer.is_valid(raise_exception=True) - except ValidationError as e: - if find_primary_key_error(e): - st = status.HTTP_409_CONFLICT - else: - st = status.HTTP_400_BAD_REQUEST - return Response({'message': e.args, 'pkhash': pkhash}, status=st) - - # perform dry run if requested - if request.data.get('dryrun', False): - try: - metrics_path = os.path.join(getattr(settings, 'DRYRUN_ROOT'), f'metrics_{pkhash}.py') - with open(metrics_path, 'wb') as metrics_file: - metrics_file.write(metrics.open().read()) - task = compute_dryrun.apply_async( - (metrics_path, test_data_manager_key, pkhash), - queue=f"{settings.LEDGER['name']}.dryrunner" - ) - except Exception as e: - return Response({ - 'message': f'Could not launch objective creation with dry-run on this instance: {str(e)}' - }, status=status.HTTP_400_BAD_REQUEST) - else: - current_site = getattr(settings, "DEFAULT_DOMAIN") - task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' - msg = f'Your dry-run has been taken in account. You can follow the task execution on {task_route}' + metrics_path = os.path.join(getattr(settings, 'DRYRUN_ROOT'), f'metrics_{pkhash}.py') + with open(metrics_path, 'wb') as metrics_file: + metrics_file.write(metrics.open().read()) + task = compute_dryrun.apply_async( + (metrics_path, test_data_manager_key, pkhash), + queue=f"{settings.LEDGER['name']}.dryrunner" + ) + except Exception as e: + raise Exception('Could not launch objective creation with dry-run on this instance: {str(e)}') + else: + current_site = getattr(settings, "DEFAULT_DOMAIN") + task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' + msg = f'Your dry-run has been taken in account. You can follow the task execution on {task_route}' - return Response({'id': task.id, 'message': msg}, status=status.HTTP_202_ACCEPTED) + return {'id': task.id, 'message': msg}, status.HTTP_202_ACCEPTED + def commit(self, serializer, ledger_data): # create on local db try: instance = self.perform_create(serializer) @@ -92,39 +71,79 @@ def create(self, request, *args, **kwargs): pkhash = re.search(r'\(pkhash\)=\((\w+)\)', e.args[0]).group(1) except IndexError: pkhash = '' - return Response({'message': 'A objective with this description file already exists.', 'pkhash': pkhash}, - status=status.HTTP_409_CONFLICT) + return {'message': 'A objective with this description file already exists.', 'pkhash': pkhash}, status.HTTP_409_CONFLICT except Exception as e: - return Response({'message': e.args}, - status=status.HTTP_400_BAD_REQUEST) + raise Exception(e.args) - # create on ledger db - ledger_serializer = LedgerObjectiveSerializer( - data={'test_data_sample_keys': request.data.getlist('test_data_sample_keys', []), - 'test_data_manager_key': test_data_manager_key, - 'name': request.data.get('name'), - 'permissions': request.data.get('permissions'), - 'metrics_name': request.data.get('metrics_name'), - 'instance': instance}, - context={'request': request} - ) + # init ledger serializer + ledger_data.update({'instance': instance}) + ledger_serializer = LedgerObjectiveSerializer(data=ledger_data) if not ledger_serializer.is_valid(): + # delete instance instance.delete() raise ValidationError(ledger_serializer.errors) # create on ledger try: data = ledger_serializer.create(ledger_serializer.validated_data) + except LedgerTimeout as e: + data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} + raise LedgerException(data, e.status) except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) + raise LedgerException(str(e.msg), e.status) st = get_success_create_code() - # return response with local db and ledger data information - headers = self.get_success_headers(serializer.data) - d = dict(serializer.data) # local db data - d.update(data) # ledger data - return Response(d, status=st, headers=headers) + + d = dict(serializer.data) + d.update(data) + + return d, st + + def _create(self, request, metrics, description, test_data_manager_key, dryrun): + pkhash = get_hash(description) + serializer = self.get_serializer(data={'pkhash': pkhash, + 'metrics': metrics, + 'description': description}) + + try: + serializer.is_valid(raise_exception=True) + except Exception as e: + st = status.HTTP_400_BAD_REQUEST + if find_primary_key_error(e): + st = status.HTTP_409_CONFLICT + raise ValidationException(e.args, pkhash, st) + else: + if dryrun: + return self.handle_dryrun(pkhash, metrics, test_data_manager_key) + + # create on ledger + db + ledger_data = {'test_data_sample_keys': request.data.getlist('test_data_sample_keys', []), + 'test_data_manager_key': test_data_manager_key, + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions'), + 'metrics_name': request.data.get('metrics_name'), + } + data, st = self.commit(serializer, ledger_data) + return data, st + + def create(self, request, *args, **kwargs): + metrics = request.data.get('metrics') + description = request.data.get('description') + test_data_manager_key = request.data.get('test_data_manager_key', '') + dryrun = request.data.get('dryrun', False) + + try: + data, st = self._create(request, metrics, description, test_data_manager_key, dryrun) + except ValidationException as e: + return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) + except LedgerException as e: + return Response({'message': e.data}, status=e.st) + except Exception as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + else: + headers = self.get_success_headers(data) + return Response(data, status=st, headers=headers) def create_or_update_objective(self, objective, pk): @@ -152,20 +171,10 @@ def create_or_update_objective(self, objective, pk): return instance - def retrieve(self, request, *args, **kwargs): - lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field - pk = self.kwargs[lookup_url_kwarg] - - try: - validate_pk(pk) - except Exception as e: - return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) - + def _retrieve(self, pk): + validate_pk(pk) # get instance from remote node - try: - data = get_object_from_ledger(pk, self.ledger_query_call) - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) + data = get_object_from_ledger(pk, self.ledger_query_call) # try to get it from local db to check if description exists try: @@ -185,7 +194,20 @@ def retrieve(self, request, *args, **kwargs): serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) data.update(serializer.data) - return Response(data, status=status.HTTP_200_OK) + return data + + def retrieve(self, request, *args, **kwargs): + lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field + pk = self.kwargs[lookup_url_kwarg] + + try: + data = self._retrieve(pk) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) + else: + return Response(data, status=status.HTTP_200_OK) def list(self, request, *args, **kwargs): try: diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 228ecb56e..da27d8286 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -4,7 +4,7 @@ from substrapp.serializers import LedgerTestTupleSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerConflict -from substrapp.views.utils import validate_pk, get_success_create_code +from substrapp.views.utils import validate_pk, get_success_create_code, LedgerException class TestTupleViewSet(mixins.CreateModelMixin, @@ -20,7 +20,16 @@ def get_queryset(self): def perform_create(self, serializer): return serializer.save() - def create(self, request, *args, **kwargs): + def commit(self, serializer, pkhash): + # create on ledger + try: + data = serializer.create(serializer.validated_data) + except LedgerError as e: + raise LedgerException({'message': str(e.msg), 'pkhash': pkhash}, e.status) + else: + return data + + def _create(self, request): data = { 'traintuple_key': request.data.get('traintuple_key'), 'data_manager_key': request.data.get('data_manager_key', ''), @@ -28,32 +37,34 @@ def create(self, request, *args, **kwargs): 'tag': request.data.get('tag', '') } - # init ledger serializer serializer = self.get_serializer(data=data) serializer.is_valid(raise_exception=True) - # Get testtuple pkhash to handle 408 timeout in invoke_ledger + # Get traintuple pkhash to handle 408 timeout in invoke_ledger args = serializer.get_args(serializer.validated_data) try: data = query_ledger(fcn='createTesttuple', args=args) except LedgerConflict as e: - return Response({'message': str(e.msg), 'pkhash': e.pkhash}, status=e.status) + raise LedgerException({'message': str(e.msg), 'pkhash': e.pkhash}, e.status) except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) - - pkhash = data.get('key') + raise LedgerException(str(e.msg), e.status) + else: + pkhash = data.get('key') + data = self.commit(serializer, pkhash) - # create on ledger - try: - data = serializer.create(serializer.validated_data) - except LedgerError as e: - return Response({'message': str(e.msg), 'pkhash': pkhash}, status=e.status) + st = get_success_create_code() - st = get_success_create_code() + return data, st - headers = self.get_success_headers(serializer.data) - return Response(data, status=st, headers=headers) + def create(self, request, *args, **kwargs): + try: + data, st = self._create(request) + except LedgerException as e: + return Response({'message': e.data}, status=e.st) + else: + headers = self.get_success_headers(data) + return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): try: @@ -64,19 +75,19 @@ def list(self, request, *args, **kwargs): data = data if data else [] return Response(data, status=status.HTTP_200_OK) + def _retrieve(self, pk): + validate_pk(pk) + return get_object_from_ledger(pk, self.ledger_query_call) + def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] try: - validate_pk(pk) - except Exception as e: - return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) - - # get instance from remote node - try: - data = get_object_from_ledger(pk, self.ledger_query_call) + data = self._retrieve(pk) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) else: return Response(data, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index ab559d466..b74d33754 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -4,7 +4,7 @@ from substrapp.serializers import LedgerTrainTupleSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerConflict -from substrapp.views.utils import validate_pk, get_success_create_code +from substrapp.views.utils import validate_pk, get_success_create_code, LedgerException, ValidationException class TrainTupleViewSet(mixins.CreateModelMixin, @@ -20,7 +20,16 @@ def get_queryset(self): def perform_create(self, serializer): return serializer.save() - def create(self, request, *args, **kwargs): + def commit(self, serializer, pkhash): + # create on ledger + try: + data = serializer.create(serializer.validated_data) + except LedgerError as e: + raise LedgerException({'message': str(e.msg), 'pkhash': pkhash}, e.status) + else: + return data + + def _create(self, request): data = { 'algo_key': request.data.get('algo_key'), 'data_manager_key': request.data.get('data_manager_key'), @@ -42,22 +51,25 @@ def create(self, request, *args, **kwargs): try: data = query_ledger(fcn='createTraintuple', args=args) except LedgerConflict as e: - return Response({'message': str(e.msg), 'pkhash': e.pkhash}, status=e.status) + raise LedgerException({'message': str(e.msg), 'pkhash': e.pkhash}, e.status) except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) - - pkhash = data.get('key') + raise LedgerException(str(e.msg), e.status) + else: + pkhash = data.get('key') + data = self.commit(serializer, pkhash) - # create on ledger - try: - data = serializer.create(serializer.validated_data) - except LedgerError as e: - return Response({'message': str(e.msg), 'pkhash': pkhash}, status=e.status) + st = get_success_create_code() - st = get_success_create_code() + return data, st - headers = self.get_success_headers(serializer.data) - return Response(data, status=st, headers=headers) + def create(self, request, *args, **kwargs): + try: + data, st = self._create(request) + except LedgerException as e: + return Response({'message': e.data}, status=e.st) + else: + headers = self.get_success_headers(data) + return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): @@ -70,19 +82,19 @@ def list(self, request, *args, **kwargs): return Response(data, status=status.HTTP_200_OK) + def _retrieve(self, pk): + validate_pk(pk) + return get_object_from_ledger(pk, self.ledger_query_call) + def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] try: - validate_pk(pk) - except Exception as e: - return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) - - # get instance from remote node - try: - data = get_object_from_ledger(pk, self.ledger_query_call) + data = self._retrieve(pk) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) + except Exception as e: + return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) else: return Response(data, status=status.HTTP_200_OK) From 570c6f0cff92803859c665f83b0d166af321852a Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 11 Jun 2019 21:10:59 +0200 Subject: [PATCH 090/457] clean import --- substrabac/substrapp/views/traintuple.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index b74d33754..305addb91 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -4,7 +4,7 @@ from substrapp.serializers import LedgerTrainTupleSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerConflict -from substrapp.views.utils import validate_pk, get_success_create_code, LedgerException, ValidationException +from substrapp.views.utils import validate_pk, get_success_create_code, LedgerException class TrainTupleViewSet(mixins.CreateModelMixin, From bebe68468ea332c022bd8fd76552a1a84ed06e2b Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 12 Jun 2019 09:27:23 +0200 Subject: [PATCH 091/457] fix flake8 --- .../tests/views/tests_views_datasample.py | 1 + substrabac/substrapp/views/datamanager.py | 5 ++--- substrabac/substrapp/views/objective.py | 15 ++++++++------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 6eb038f29..43ba2e1ea 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -23,6 +23,7 @@ MEDIA_ROOT = "/tmp/unittests_views/" + # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(DRYRUN_ROOT=MEDIA_ROOT) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 032fded2e..92ce59e03 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -46,9 +46,8 @@ def handle_dryrun(self, data_opener): imported_module_names = [m.name for e in node.body if isinstance(e, ast.Import) for m in e.names] if 'substratools' not in imported_module_names: - return { - 'message': 'Opener must import substratools, please review your opener and the documentation.' - }, status.HTTP_400_BAD_REQUEST + err_msg = 'Opener must import substratools, please review your opener and the documentation.' + return {'message': err_msg}, status.HTTP_400_BAD_REQUEST return {'message': f'Your data opener is valid. You can remove the dryrun option.'}, status.HTTP_200_OK diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 70af9c2cf..6a1c2f17e 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -39,6 +39,7 @@ class ObjectiveViewSet(mixins.CreateModelMixin, queryset = Objective.objects.all() serializer_class = ObjectiveSerializer ledger_query_call = 'queryObjective' + # permission_classes = (permissions.IsAuthenticated,) def perform_create(self, serializer): @@ -71,7 +72,8 @@ def commit(self, serializer, ledger_data): pkhash = re.search(r'\(pkhash\)=\((\w+)\)', e.args[0]).group(1) except IndexError: pkhash = '' - return {'message': 'A objective with this description file already exists.', 'pkhash': pkhash}, status.HTTP_409_CONFLICT + err_msg = 'A objective with this description file already exists.' + return {'message': err_msg, 'pkhash': pkhash}, status.HTTP_409_CONFLICT except Exception as e: raise Exception(e.args) @@ -119,11 +121,11 @@ def _create(self, request, metrics, description, test_data_manager_key, dryrun): # create on ledger + db ledger_data = {'test_data_sample_keys': request.data.getlist('test_data_sample_keys', []), - 'test_data_manager_key': test_data_manager_key, - 'name': request.data.get('name'), - 'permissions': request.data.get('permissions'), - 'metrics_name': request.data.get('metrics_name'), - } + 'test_data_manager_key': test_data_manager_key, + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions'), + 'metrics_name': request.data.get('metrics_name'), + } data, st = self.commit(serializer, ledger_data) return data, st @@ -257,7 +259,6 @@ def data(self, request, *args, **kwargs): @app.task(bind=True, ignore_result=False) def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): - dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) From 929abbbeefb7d7b1412f390209c5b6ebd20a3fa3 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 12 Jun 2019 09:55:09 +0200 Subject: [PATCH 092/457] Fix status return --- substrabac/substrapp/views/algo.py | 10 ++++------ substrabac/substrapp/views/datamanager.py | 10 ++++------ substrabac/substrapp/views/objective.py | 11 +++++------ substrabac/substrapp/views/testtuple.py | 9 +++------ substrabac/substrapp/views/traintuple.py | 9 +++------ 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 504ed100a..820d34c5c 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -51,12 +51,10 @@ def commit(self, serializer, ledger_data): except LedgerError as e: raise LedgerException(str(e.msg), e.status) - st = get_success_create_code() - d = dict(serializer.data) d.update(data) - return d, st + return d def _create(self, request, file): pkhash = get_hash(file) @@ -79,14 +77,13 @@ def _create(self, request, file): 'name': request.data.get('name'), 'permissions': request.data.get('permissions', 'all'), } - data, st = self.commit(serializer, ledger_data) - return data, st + return self.commit(serializer, ledger_data) def create(self, request, *args, **kwargs): file = request.data.get('file') try: - data, st = self._create(request, file) + data = self._create(request, file) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -95,6 +92,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) + st = get_success_create_code() return Response(data, status=st, headers=headers) def create_or_update_algo(self, algo, pk): diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 92ce59e03..f88f72149 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -72,12 +72,10 @@ def commit(self, serializer, ledger_data): except LedgerError as e: raise LedgerException(str(e.msg), e.status) - st = get_success_create_code() - d = dict(serializer.data) d.update(data) - return d, st + return d def _create(self, request, data_opener, dryrun): pkhash = get_hash(data_opener) @@ -106,15 +104,14 @@ def _create(self, request, data_opener, dryrun): 'type': request.data.get('type'), 'objective_keys': request.data.getlist('objective_keys'), } - data, st = self.commit(serializer, ledger_data) - return data, st + return self.commit(serializer, ledger_data) def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) data_opener = request.data.get('data_opener') try: - data, st = self._create(request, data_opener, dryrun) + data = self._create(request, data_opener, dryrun) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -123,6 +120,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) + st = get_success_create_code() return Response(data, status=st, headers=headers) def create_or_update_datamanager(self, instance, datamanager, pk): diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 6a1c2f17e..973b0d637 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -95,12 +95,10 @@ def commit(self, serializer, ledger_data): except LedgerError as e: raise LedgerException(str(e.msg), e.status) - st = get_success_create_code() - d = dict(serializer.data) d.update(data) - return d, st + return d def _create(self, request, metrics, description, test_data_manager_key, dryrun): pkhash = get_hash(description) @@ -126,8 +124,8 @@ def _create(self, request, metrics, description, test_data_manager_key, dryrun): 'permissions': request.data.get('permissions'), 'metrics_name': request.data.get('metrics_name'), } - data, st = self.commit(serializer, ledger_data) - return data, st + data = self.commit(serializer, ledger_data) + return data def create(self, request, *args, **kwargs): metrics = request.data.get('metrics') @@ -136,7 +134,7 @@ def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) try: - data, st = self._create(request, metrics, description, test_data_manager_key, dryrun) + data = self._create(request, metrics, description, test_data_manager_key, dryrun) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -145,6 +143,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) + st = get_success_create_code() return Response(data, status=st, headers=headers) def create_or_update_objective(self, objective, pk): diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index da27d8286..8c4c3b98b 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -51,19 +51,16 @@ def _create(self, request): raise LedgerException(str(e.msg), e.status) else: pkhash = data.get('key') - data = self.commit(serializer, pkhash) - - st = get_success_create_code() - - return data, st + return self.commit(serializer, pkhash) def create(self, request, *args, **kwargs): try: - data, st = self._create(request) + data = self._create(request) except LedgerException as e: return Response({'message': e.data}, status=e.st) else: headers = self.get_success_headers(data) + st = get_success_create_code() return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 305addb91..4bc5ff973 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -56,19 +56,16 @@ def _create(self, request): raise LedgerException(str(e.msg), e.status) else: pkhash = data.get('key') - data = self.commit(serializer, pkhash) - - st = get_success_create_code() - - return data, st + return self.commit(serializer, pkhash) def create(self, request, *args, **kwargs): try: - data, st = self._create(request) + data = self._create(request) except LedgerException as e: return Response({'message': e.data}, status=e.st) else: headers = self.get_success_headers(data) + st = get_success_create_code() return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): From 878e9052845683de527710c80ebfabf647748139 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 12 Jun 2019 10:19:19 +0200 Subject: [PATCH 093/457] Fix tests - readd status for correctly handling dryrun --- .../substrapp/tests/views/tests_views_datamanager.py | 1 + substrabac/substrapp/views/datamanager.py | 8 +++++--- substrabac/substrapp/views/objective.py | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index f23009acb..d0746415b 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -24,6 +24,7 @@ # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +@override_settings(LEDGER_SYNC_ENABLED=True) class DataManagerViewTests(APITestCase): def setUp(self): diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index f88f72149..17393aa98 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -104,14 +104,17 @@ def _create(self, request, data_opener, dryrun): 'type': request.data.get('type'), 'objective_keys': request.data.getlist('objective_keys'), } - return self.commit(serializer, ledger_data) + + data = self.commit(serializer, ledger_data) + st = get_success_create_code() + return data, st def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) data_opener = request.data.get('data_opener') try: - data = self._create(request, data_opener, dryrun) + data, st = self._create(request, data_opener, dryrun) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -120,7 +123,6 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) - st = get_success_create_code() return Response(data, status=st, headers=headers) def create_or_update_datamanager(self, instance, datamanager, pk): diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 973b0d637..72c3fabce 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -125,7 +125,8 @@ def _create(self, request, metrics, description, test_data_manager_key, dryrun): 'metrics_name': request.data.get('metrics_name'), } data = self.commit(serializer, ledger_data) - return data + st = get_success_create_code() + return data, st def create(self, request, *args, **kwargs): metrics = request.data.get('metrics') @@ -134,7 +135,7 @@ def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) try: - data = self._create(request, metrics, description, test_data_manager_key, dryrun) + data, st = self._create(request, metrics, description, test_data_manager_key, dryrun) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -143,7 +144,6 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) - st = get_success_create_code() return Response(data, status=st, headers=headers) def create_or_update_objective(self, objective, pk): From 93b84d1c45fd5e20bc4002cfeca8671894869a44 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 12 Jun 2019 10:43:30 +0200 Subject: [PATCH 094/457] clean --- substrabac/substrapp/views/objective.py | 2 +- substrabac/substrapp/views/testtuple.py | 4 ++-- substrabac/substrapp/views/traintuple.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 72c3fabce..f60af25a1 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -55,7 +55,7 @@ def handle_dryrun(self, pkhash, metrics, test_data_manager_key): queue=f"{settings.LEDGER['name']}.dryrunner" ) except Exception as e: - raise Exception('Could not launch objective creation with dry-run on this instance: {str(e)}') + raise Exception(f'Could not launch objective creation with dry-run on this instance: {str(e)}') else: current_site = getattr(settings, "DEFAULT_DOMAIN") task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 8c4c3b98b..f29039af4 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -48,7 +48,7 @@ def _create(self, request): except LedgerConflict as e: raise LedgerException({'message': str(e.msg), 'pkhash': e.pkhash}, e.status) except LedgerError as e: - raise LedgerException(str(e.msg), e.status) + raise LedgerException({'message': str(e.msg)}, e.status) else: pkhash = data.get('key') return self.commit(serializer, pkhash) @@ -57,7 +57,7 @@ def create(self, request, *args, **kwargs): try: data = self._create(request) except LedgerException as e: - return Response({'message': e.data}, status=e.st) + return Response(e.data, status=e.st) else: headers = self.get_success_headers(data) st = get_success_create_code() diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 4bc5ff973..6317d5f4a 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -53,7 +53,7 @@ def _create(self, request): except LedgerConflict as e: raise LedgerException({'message': str(e.msg), 'pkhash': e.pkhash}, e.status) except LedgerError as e: - raise LedgerException(str(e.msg), e.status) + raise LedgerException({'message': str(e.msg)}, e.status) else: pkhash = data.get('key') return self.commit(serializer, pkhash) @@ -62,7 +62,7 @@ def create(self, request, *args, **kwargs): try: data = self._create(request) except LedgerException as e: - return Response({'message': e.data}, status=e.st) + return Response(e.data, status=e.st) else: headers = self.get_success_headers(data) st = get_success_create_code() From 511e5368a444581ee89b0884f9d8c2f7fa1b72b8 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 12 Jun 2019 11:27:53 +0200 Subject: [PATCH 095/457] Fix hosts --- substrabac/substrapp/views/algo.py | 16 +++++++----- substrabac/substrapp/views/datamanager.py | 23 +++++++++-------- substrabac/substrapp/views/objective.py | 31 +++++++++++++---------- 3 files changed, 38 insertions(+), 32 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 820d34c5c..12deefc5b 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -30,13 +30,19 @@ class AlgoViewSet(mixins.CreateModelMixin, def perform_create(self, serializer): return serializer.save() - def commit(self, serializer, ledger_data): + def commit(self, serializer, request): # create on db instance = self.perform_create(serializer) + ledger_data = { + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions', 'all'), + } + # init ledger serializer ledger_data.update({'instance': instance}) - ledger_serializer = LedgerAlgoSerializer(data=ledger_data) + ledger_serializer = LedgerAlgoSerializer(data=ledger_data, + context={'request': request}) if not ledger_serializer.is_valid(): # delete instance instance.delete() @@ -73,11 +79,7 @@ def _create(self, request, file): raise ValidationException(e.args, pkhash, st) else: # create on ledger + db - ledger_data = { - 'name': request.data.get('name'), - 'permissions': request.data.get('permissions', 'all'), - } - return self.commit(serializer, ledger_data) + return self.commit(serializer, request) def create(self, request, *args, **kwargs): file = request.data.get('file') diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 17393aa98..5bdb5adc6 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -51,12 +51,21 @@ def handle_dryrun(self, data_opener): return {'message': f'Your data opener is valid. You can remove the dryrun option.'}, status.HTTP_200_OK - def commit(self, serializer, ledger_data): + def commit(self, serializer, request): + # create on ledger + db + ledger_data = { + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions'), + 'type': request.data.get('type'), + 'objective_keys': request.data.getlist('objective_keys'), + } + # create on db instance = self.perform_create(serializer) # init ledger serializer ledger_data.update({'instance': instance}) - ledger_serializer = LedgerDataManagerSerializer(data=ledger_data) + ledger_serializer = LedgerDataManagerSerializer(data=ledger_data, + context={'request': request}) if not ledger_serializer.is_valid(): # delete instance @@ -97,15 +106,7 @@ def _create(self, request, data_opener, dryrun): if dryrun: return self.handle_dryrun(data_opener) - # create on ledger + db - ledger_data = { - 'name': request.data.get('name'), - 'permissions': request.data.get('permissions'), - 'type': request.data.get('type'), - 'objective_keys': request.data.getlist('objective_keys'), - } - - data = self.commit(serializer, ledger_data) + data = self.commit(serializer, request) st = get_success_create_code() return data, st diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index f60af25a1..45a770438 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -63,7 +63,7 @@ def handle_dryrun(self, pkhash, metrics, test_data_manager_key): return {'id': task.id, 'message': msg}, status.HTTP_202_ACCEPTED - def commit(self, serializer, ledger_data): + def commit(self, serializer, request): # create on local db try: instance = self.perform_create(serializer) @@ -78,8 +78,16 @@ def commit(self, serializer, ledger_data): raise Exception(e.args) # init ledger serializer + ledger_data = { + 'test_data_sample_keys': request.data.getlist('test_data_sample_keys', []), + 'test_data_manager_key': request.data.get('test_data_manager_key', ''), + 'name': request.data.get('name'), + 'permissions': request.data.get('permissions'), + 'metrics_name': request.data.get('metrics_name'), + } ledger_data.update({'instance': instance}) - ledger_serializer = LedgerObjectiveSerializer(data=ledger_data) + ledger_serializer = LedgerObjectiveSerializer(data=ledger_data, + context={'request': request}) if not ledger_serializer.is_valid(): # delete instance @@ -100,7 +108,11 @@ def commit(self, serializer, ledger_data): return d - def _create(self, request, metrics, description, test_data_manager_key, dryrun): + def _create(self, request, dryrun): + metrics = request.data.get('metrics') + description = request.data.get('description') + test_data_manager_key = request.data.get('test_data_manager_key', '') + pkhash = get_hash(description) serializer = self.get_serializer(data={'pkhash': pkhash, 'metrics': metrics, @@ -118,24 +130,15 @@ def _create(self, request, metrics, description, test_data_manager_key, dryrun): return self.handle_dryrun(pkhash, metrics, test_data_manager_key) # create on ledger + db - ledger_data = {'test_data_sample_keys': request.data.getlist('test_data_sample_keys', []), - 'test_data_manager_key': test_data_manager_key, - 'name': request.data.get('name'), - 'permissions': request.data.get('permissions'), - 'metrics_name': request.data.get('metrics_name'), - } - data = self.commit(serializer, ledger_data) + data = self.commit(serializer, request) st = get_success_create_code() return data, st def create(self, request, *args, **kwargs): - metrics = request.data.get('metrics') - description = request.data.get('description') - test_data_manager_key = request.data.get('test_data_manager_key', '') dryrun = request.data.get('dryrun', False) try: - data, st = self._create(request, metrics, description, test_data_manager_key, dryrun) + data, st = self._create(request, dryrun) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: From 70475afb8272d5a347ecf715e0bc16954417e4cf Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 12 Jun 2019 11:45:33 +0200 Subject: [PATCH 096/457] Fix permissionss check with empty reponse --- substrabac/substrapp/ledger_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index ad1842bec..ca38eea97 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -113,7 +113,7 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): raise LedgerBadResponse(response) # Check permissions - if 'permissions' in response and response['permissions'] != 'all': + if response and 'permissions' in response and response['permissions'] != 'all': raise LedgerForbidden('Not allowed') return response From a47657ab074bf003cd57c6d28237acd0caf39cff Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 12 Jun 2019 17:03:11 +0200 Subject: [PATCH 097/457] Improve ledger loop and client. --- substrabac/substrabac/settings/deps/ledger.py | 63 ++++---- substrabac/substrapp/ledger_utils.py | 150 ++++++++++-------- 2 files changed, 115 insertions(+), 98 deletions(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 963764f86..3eb16cda9 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -20,14 +20,7 @@ PEER_PORT = LEDGER['peer']['port'][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] -LEDGER['hfc'] = {} -LEDGER['hfc']['loop'] = asyncio.new_event_loop() -asyncio.set_event_loop(LEDGER['hfc']['loop']) - -LEDGER['hfc']['client'] = Client() -LEDGER['hfc']['client'].new_channel(LEDGER['channel_name']) - -LEDGER['hfc']['requestor'] = create_user( +LEDGER['hfc_requestor'] = create_user( name=LEDGER['client']['name'], org=LEDGER['client']['org'], state_store=FileKeyValueStore(LEDGER['client']['state_store']), @@ -36,28 +29,42 @@ cert_path=LEDGER['client']['cert_path'] ) -target_peer = Peer(name=LEDGER['peer']['name']) -# Need loop -target_peer.init_with_bundle({ - 'url': f'{LEDGER["peer"]["host"]}:{PEER_PORT}', - 'grpcOptions': LEDGER['peer']['grpcOptions'], - 'tlsCACerts': {'path': LEDGER['peer']['tlsCACerts']}, - 'clientKey': {'path': LEDGER['peer']['clientKey']}, - 'clientCert': {'path': LEDGER['peer']['clientCert']}, -}) +def get_hfc_client(): + + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + client = Client() + client.new_channel(LEDGER['channel_name']) + + target_peer = Peer(name=LEDGER['peer']['name']) + + # Need loop + target_peer.init_with_bundle({ + 'url': f'{LEDGER["peer"]["host"]}:{PEER_PORT}', + 'grpcOptions': LEDGER['peer']['grpcOptions'], + 'tlsCACerts': {'path': LEDGER['peer']['tlsCACerts']}, + 'clientKey': {'path': LEDGER['peer']['clientKey']}, + 'clientCert': {'path': LEDGER['peer']['clientCert']}, + }) + + client._peers[LEDGER['peer']['name']] = target_peer + + target_orderer = Orderer(name=LEDGER['orderer']['name']) + + # Need loop + target_orderer.init_with_bundle({ + 'url': f'{LEDGER["orderer"]["host"]}:{LEDGER["orderer"]["port"]}', + 'grpcOptions': LEDGER['orderer']['grpcOptions'], + 'tlsCACerts': {'path': LEDGER['orderer']['ca']}, + 'clientKey': {'path': LEDGER['peer']['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': LEDGER['peer']['clientCert']}, # use peer creds (mutual tls) + }) -LEDGER['hfc']['client']._peers[LEDGER['peer']['name']] = target_peer + client._orderers[LEDGER['orderer']['name']] = target_orderer -target_orderer = Orderer(name=LEDGER['orderer']['name']) + return loop, client -# Need loop -target_orderer.init_with_bundle({ - 'url': f'{LEDGER["orderer"]["host"]}:{LEDGER["orderer"]["port"]}', - 'grpcOptions': LEDGER['orderer']['grpcOptions'], - 'tlsCACerts': {'path': LEDGER['orderer']['ca']}, - 'clientKey': {'path': LEDGER['peer']['clientKey']}, # use peer creds (mutual tls) - 'clientCert': {'path': LEDGER['peer']['clientCert']}, # use peer creds (mutual tls) -}) -LEDGER['hfc']['client']._orderers[LEDGER['orderer']['name']] = target_orderer +LEDGER['hfc'] = get_hfc_client diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index ca38eea97..e7495a78d 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -1,13 +1,11 @@ -import asyncio import json import logging +import contextlib from django.conf import settings from rest_framework import status LEDGER = getattr(settings, 'LEDGER', None) -if LEDGER: - asyncio.set_event_loop(LEDGER['hfc']['loop']) class LedgerError(Exception): @@ -43,80 +41,92 @@ class LedgerBadResponse(LedgerError): pass -def call_ledger(call_type, fcn, args=None, kwargs=None): - if not args: - args = [] - else: - args = [json.dumps(args)] - - peer = LEDGER['peer'] - loop = LEDGER['hfc']['loop'] - client = LEDGER['hfc']['client'] - chaincode_calls = { - 'invoke': client.chaincode_invoke, - 'query': client.chaincode_query, - } - requestor = LEDGER['hfc']['requestor'] - channel_name = LEDGER['channel_name'] - chaincode_name = LEDGER['chaincode_name'] - - # Get chaincode version - response = loop.run_until_complete( - client.query_instantiated_chaincodes( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - decode=True - )) - for ccs in response: - for cc in ccs.chaincodes: - if cc.name == chaincode_name: - chaincode_version = cc.version +@contextlib.contextmanager +def get_hfc(): + loop, client = LEDGER['hfc']() + try: + yield (loop, client) + finally: + loop.close() + del client - params = { - 'requestor': requestor, - 'channel_name': channel_name, - 'peers': [peer['name']], - 'args': args, - 'cc_name': chaincode_name, - 'cc_version': chaincode_version, - 'fcn': fcn - } - if kwargs is not None and isinstance(kwargs, dict): - params.update(kwargs) +def call_ledger(call_type, fcn, args=None, kwargs=None): - try: - response = loop.run_until_complete(chaincode_calls[call_type](**params)) - except TimeoutError as e: - raise LedgerTimeout(str(e)) - except Exception as e: - logging.exception(e) - raise LedgerError(str(e)) - - # Sanity check of the response: - if 'access denied' in response: - raise LedgerForbidden(f'Access denied for {(fcn, args)}') - elif 'no element with key' in response: - raise LedgerNotFound(f'No element founded for {(fcn, args)}') - elif 'tkey' in response: - pkhash = response.replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if len(pkhash) == 64: - raise LedgerConflict(msg='Asset conflict', pkhash=pkhash) + with get_hfc() as (loop, client): + if not args: + args = [] else: - raise LedgerBadResponse(response) + args = [json.dumps(args)] - # Deserialize the stringified json - try: - response = json.loads(response) - except json.decoder.JSONDecodeError: - raise LedgerBadResponse(response) + peer = LEDGER['peer'] + requestor = LEDGER['hfc_requestor'] + + chaincode_calls = { + 'invoke': client.chaincode_invoke, + 'query': client.chaincode_query, + } + + channel_name = LEDGER['channel_name'] + chaincode_name = LEDGER['chaincode_name'] + + # Get chaincode version + response = loop.run_until_complete( + client.query_instantiated_chaincodes( + requestor=requestor, + channel_name=channel_name, + peers=[peer['name']], + decode=True + )) + for ccs in response: + for cc in ccs.chaincodes: + if cc.name == chaincode_name: + chaincode_version = cc.version + + params = { + 'requestor': requestor, + 'channel_name': channel_name, + 'peers': [peer['name']], + 'args': args, + 'cc_name': chaincode_name, + 'cc_version': chaincode_version, + 'fcn': fcn + } + + if kwargs is not None and isinstance(kwargs, dict): + params.update(kwargs) + + try: + response = loop.run_until_complete(chaincode_calls[call_type](**params)) + except TimeoutError as e: + raise LedgerTimeout(str(e)) + except Exception as e: + logging.exception(e) + raise LedgerError(str(e)) + + # Sanity check of the response: + if 'access denied' in response: + raise LedgerForbidden(f'Access denied for {(fcn, args)}') + elif 'no element with key' in response: + raise LedgerNotFound(f'No element founded for {(fcn, args)}') + elif 'tkey' in response: + pkhash = response.replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if len(pkhash) == 64: + raise LedgerConflict(msg='Asset conflict', pkhash=pkhash) + else: + raise LedgerBadResponse(response) + + # Deserialize the stringified json + try: + response = json.loads(response) + except json.decoder.JSONDecodeError: + raise LedgerBadResponse(response) - # Check permissions - if response and 'permissions' in response and response['permissions'] != 'all': - raise LedgerForbidden('Not allowed') + # Check permissions + if response and 'permissions' in response and response['permissions'] != 'all': + raise LedgerForbidden('Not allowed') - return response + return response def query_ledger(fcn, args=None): From 790b9f55a003e0ab9ad823d5584a0106b97c2afe Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 12 Jun 2019 17:47:01 +0200 Subject: [PATCH 098/457] Useless chaincode version. --- substrabac/substrapp/ledger_utils.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index e7495a78d..8ece0211a 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -70,26 +70,13 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] - # Get chaincode version - response = loop.run_until_complete( - client.query_instantiated_chaincodes( - requestor=requestor, - channel_name=channel_name, - peers=[peer['name']], - decode=True - )) - for ccs in response: - for cc in ccs.chaincodes: - if cc.name == chaincode_name: - chaincode_version = cc.version - params = { 'requestor': requestor, 'channel_name': channel_name, 'peers': [peer['name']], 'args': args, 'cc_name': chaincode_name, - 'cc_version': chaincode_version, + 'cc_version': 'substra', 'fcn': fcn } From 309424ab240750b302e716201929a256ba5c7ac3 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 13 Jun 2019 09:00:00 +0200 Subject: [PATCH 099/457] Add missing db --- scripts/recreate_db.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/recreate_db.sh b/scripts/recreate_db.sh index 3cf57c3b8..718684aa2 100755 --- a/scripts/recreate_db.sh +++ b/scripts/recreate_db.sh @@ -11,3 +11,7 @@ psql -U ${USER} -d substrabac_owkin -c "GRANT ALL PRIVILEGES ON DATABASE substra dropdb -U ${USER} substrabac_chunantes createdb -U ${USER} -E UTF8 substrabac_chunantes psql -U ${USER} -d substrabac_chunantes -c "GRANT ALL PRIVILEGES ON DATABASE substrabac_chunantes to substrabac;ALTER ROLE substrabac WITH SUPERUSER CREATEROLE CREATEDB;" + +dropdb -U ${USER} substrabac_clb +createdb -U ${USER} -E UTF8 substrabac_clb +psql -U ${USER} -d substrabac_clb -c "GRANT ALL PRIVILEGES ON DATABASE substrabac_chunantes to substrabac;ALTER ROLE substrabac WITH SUPERUSER CREATEROLE CREATEDB;" From 5fbab5cb6a9aa7a7daae37f5cb81cc669916f8f9 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 13 Jun 2019 09:12:37 +0200 Subject: [PATCH 100/457] Prevent status from being returned from method, all response and status management is done in one master method --- substrabac/substrapp/views/datamanager.py | 16 ++++++++++++---- substrabac/substrapp/views/objective.py | 15 +++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 5bdb5adc6..0d3f4e6e3 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -49,7 +49,7 @@ def handle_dryrun(self, data_opener): err_msg = 'Opener must import substratools, please review your opener and the documentation.' return {'message': err_msg}, status.HTTP_400_BAD_REQUEST - return {'message': f'Your data opener is valid. You can remove the dryrun option.'}, status.HTTP_200_OK + return {'message': f'Your data opener is valid. You can remove the dryrun option.'} def commit(self, serializer, request): # create on ledger + db @@ -106,16 +106,23 @@ def _create(self, request, data_opener, dryrun): if dryrun: return self.handle_dryrun(data_opener) - data = self.commit(serializer, request) + # create on ledger + db + return self.commit(serializer, request) + + def _get_create_status(self, dryrun): + if dryrun: + st = status.HTTP_200_OK + else: st = get_success_create_code() - return data, st + + return st def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) data_opener = request.data.get('data_opener') try: - data, st = self._create(request, data_opener, dryrun) + data = self._create(request, data_opener, dryrun) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -124,6 +131,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) + st = self._get_create_status(dryrun) return Response(data, status=st, headers=headers) def create_or_update_datamanager(self, instance, datamanager, pk): diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 45a770438..377a95052 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -61,7 +61,7 @@ def handle_dryrun(self, pkhash, metrics, test_data_manager_key): task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' msg = f'Your dry-run has been taken in account. You can follow the task execution on {task_route}' - return {'id': task.id, 'message': msg}, status.HTTP_202_ACCEPTED + return {'id': task.id, 'message': msg} def commit(self, serializer, request): # create on local db @@ -130,15 +130,21 @@ def _create(self, request, dryrun): return self.handle_dryrun(pkhash, metrics, test_data_manager_key) # create on ledger + db - data = self.commit(serializer, request) + return self.commit(serializer, request) + + def _get_create_status(self, dryrun): + if dryrun: + st = status.HTTP_202_ACCEPTED + else: st = get_success_create_code() - return data, st + + return st def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) try: - data, st = self._create(request, dryrun) + data = self._create(request, dryrun) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -147,6 +153,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) + st = self._get_create_status(dryrun) return Response(data, status=st, headers=headers) def create_or_update_objective(self, objective, pk): From 20def9472a203c994163e150666f0ac5555f87dd Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 13 Jun 2019 09:30:02 +0200 Subject: [PATCH 101/457] Remove cc_version. --- substrabac/requirements.txt | 3 ++- substrabac/substrapp/ledger_utils.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index 749a3e07e..9629bacc8 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,4 +26,5 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -fabric-sdk-py==0.8.0 +# fabric-sdk-py==0.8.0 +git+git://github.com/hyperledger/fabric-sdk-py.git@db135d6ddd3c890d942278c7e7b340f943ab5e34 diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 8ece0211a..db377bb7c 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -76,7 +76,6 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): 'peers': [peer['name']], 'args': args, 'cc_name': chaincode_name, - 'cc_version': 'substra', 'fcn': fcn } From 8535a64a4e173aca3117af4e721aaabcacd2ec14 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 13 Jun 2019 16:22:14 +0200 Subject: [PATCH 102/457] Better invoke --- substrabac/substrabac/settings/deps/ledger.py | 79 +++++++++++++++++++ substrabac/substrapp/ledger_utils.py | 7 +- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 3eb16cda9..35593f9ea 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -3,6 +3,7 @@ import asyncio import glob import json +import tempfile from .org import ORG @@ -11,6 +12,7 @@ from hfc.fabric.user import create_user from hfc.fabric.orderer import Orderer from hfc.util.keyvaluestore import FileKeyValueStore +from hfc.fabric.block_decoder import decode_fabric_MSP_config, decode_fabric_peers_info, decode_fabric_endpoints LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/substrabac/conf.json') @@ -30,6 +32,43 @@ ) +def process_discovery(response): + results = {} + results['members'] = [] + + for res in response.results: + if res.config_result: + results['config'] = process_config_result(res.config_result) + + if res.members: + members = process_members(res.members) + results['members'].extend(members) + + return results + + +def process_config_result(config_result): + + results = {'msps': {}, + 'orderers': {}} + + for msp_name in config_result.msps: + results['msps'][msp_name] = decode_fabric_MSP_config(config_result.msps[msp_name].SerializeToString()) + + for orderer_msp in config_result.orderers: + results['orderers'][orderer_msp] = decode_fabric_endpoints(config_result.orderers[orderer_msp].endpoint) + + return results + + +def process_members(members): + peers = [] + for msp_name in members.peers_by_org: + peers.append(decode_fabric_peers_info(members.peers_by_org[msp_name].peers)) + + return peers + + def get_hfc_client(): loop = asyncio.new_event_loop() @@ -64,6 +103,46 @@ def get_hfc_client(): client._orderers[LEDGER['orderer']['name']] = target_orderer + channel = client.get_channel(LEDGER['channel_name']) + results = loop.run_until_complete( + channel._discovery( + LEDGER['hfc_requestor'], + client._peers[LEDGER['peer']['name']], + config=True, + local=False + ) + ) + results = process_discovery(results) + + msp_tls_root_certs = {} + for msp_id, msp_info in results['config']['msps'].items(): + msp_tls_root_certs[msp_id] = msp_info['tls_root_certs'].pop() + + for msp in results['members']: + + if msp and msp[0]['mspid'] != LEDGER['client']['msp_id']: + # add one peer per msp + peer_info = msp[0] + peer = Peer(name=peer_info['mspid']) + + with tempfile.NamedTemporaryFile() as tls_root_cert: + tls_root_cert.write(msp_tls_root_certs[peer_info['mspid']]) + tls_root_cert.flush() + + # Need loop + peer.init_with_bundle({ + 'url': peer_info['endpoint'], + 'grpcOptions': { + 'grpc-max-send-message-length': 15, + 'grpc.ssl_target_name_override': peer_info['endpoint'].split(':')[0] + }, + 'tlsCACerts': {'path': tls_root_cert.name}, + 'clientKey': {'path': LEDGER['peer']['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': LEDGER['peer']['clientCert']}, # use peer creds (mutual tls) + }) + + client._peers[peer_info['mspid']] = peer + return loop, client diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index db377bb7c..9334f1ddd 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -70,10 +70,15 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): channel_name = LEDGER['channel_name'] chaincode_name = LEDGER['chaincode_name'] + peers = { + 'invoke': client._peers.keys(), + 'query': [peer['name']], + } + params = { 'requestor': requestor, 'channel_name': channel_name, - 'peers': [peer['name']], + 'peers': peers[call_type], 'args': args, 'cc_name': chaincode_name, 'fcn': fcn From 5923b5d49eab7f23eb4d47192d8cdfb9132f206a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 13 Jun 2019 17:37:47 +0200 Subject: [PATCH 103/457] Discover orderer. --- docker/start.py | 2 - substrabac/substrabac/settings/deps/ledger.py | 41 ++++++++++++------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/docker/start.py b/docker/start.py index 28bafef29..d446322be 100644 --- a/docker/start.py +++ b/docker/start.py @@ -99,7 +99,6 @@ def generate_docker_compose_file(conf, launch_settings): for org in conf: org_name = org['name'] - orderer_ca = org['orderer']['ca'] peer = org['peer']['name'] tls_peer_dir = f'{SUBSTRA_FOLDER}/data/orgs/{org_name}/tls/{peer}' @@ -145,7 +144,6 @@ def generate_docker_compose_file(conf, launch_settings): f'{SUBSTRA_FOLDER}/conf/{org_name}:{SUBSTRA_FOLDER}/conf/{org_name}:ro', # HLF files - f'{orderer_ca}:{orderer_ca}:ro', f'{tls_peer_dir}:{tls_peer_dir}:ro', f'{org["core_peer_mspconfigpath"]}:{org["core_peer_mspconfigpath"]}:ro', ] diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 35593f9ea..894664346 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -90,19 +90,7 @@ def get_hfc_client(): client._peers[LEDGER['peer']['name']] = target_peer - target_orderer = Orderer(name=LEDGER['orderer']['name']) - - # Need loop - target_orderer.init_with_bundle({ - 'url': f'{LEDGER["orderer"]["host"]}:{LEDGER["orderer"]["port"]}', - 'grpcOptions': LEDGER['orderer']['grpcOptions'], - 'tlsCACerts': {'path': LEDGER['orderer']['ca']}, - 'clientKey': {'path': LEDGER['peer']['clientKey']}, # use peer creds (mutual tls) - 'clientCert': {'path': LEDGER['peer']['clientCert']}, # use peer creds (mutual tls) - }) - - client._orderers[LEDGER['orderer']['name']] = target_orderer - + # Discovery loading channel = client.get_channel(LEDGER['channel_name']) results = loop.run_until_complete( channel._discovery( @@ -118,10 +106,9 @@ def get_hfc_client(): for msp_id, msp_info in results['config']['msps'].items(): msp_tls_root_certs[msp_id] = msp_info['tls_root_certs'].pop() + # Load one peer per msp for endorsement transaction for msp in results['members']: - if msp and msp[0]['mspid'] != LEDGER['client']['msp_id']: - # add one peer per msp peer_info = msp[0] peer = Peer(name=peer_info['mspid']) @@ -143,6 +130,30 @@ def get_hfc_client(): client._peers[peer_info['mspid']] = peer + # Load one orderer + orderer_mspid, orderer_info = list(results['config']['orderers'].items())[0] + orderer_endpoint = f'{orderer_info[0]["host"]}:{orderer_info[0]["port"]}' + + target_orderer = Orderer(name=orderer_mspid) + + with tempfile.NamedTemporaryFile() as tls_root_cert: + tls_root_cert.write(msp_tls_root_certs[orderer_mspid]) + tls_root_cert.flush() + + # Need loop + target_orderer.init_with_bundle({ + 'url': orderer_endpoint, + 'grpcOptions': { + 'grpc-max-send-message-length': 15, + 'grpc.ssl_target_name_override': orderer_info[0]['host'] + }, + 'tlsCACerts': {'path': tls_root_cert.name}, + 'clientKey': {'path': LEDGER['peer']['clientKey']}, # use peer creds (mutual tls) + 'clientCert': {'path': LEDGER['peer']['clientCert']}, # use peer creds (mutual tls) + }) + + client._orderers[orderer_mspid] = target_orderer + return loop, client From 6c59b14c30936e12b2c5cdb05e9a3b29fc851302 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 14 Jun 2019 09:45:04 +0200 Subject: [PATCH 104/457] Clean up --- substrabac/substrabac/settings/deps/ledger.py | 145 ++++++++++-------- substrabac/substrapp/ledger_utils.py | 2 +- 2 files changed, 79 insertions(+), 68 deletions(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 894664346..2bb0862cb 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -22,7 +22,7 @@ PEER_PORT = LEDGER['peer']['port'][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] -LEDGER['hfc_requestor'] = create_user( +LEDGER['requestor'] = create_user( name=LEDGER['client']['name'], org=LEDGER['client']['org'], state_store=FileKeyValueStore(LEDGER['client']['state_store']), @@ -32,43 +32,6 @@ ) -def process_discovery(response): - results = {} - results['members'] = [] - - for res in response.results: - if res.config_result: - results['config'] = process_config_result(res.config_result) - - if res.members: - members = process_members(res.members) - results['members'].extend(members) - - return results - - -def process_config_result(config_result): - - results = {'msps': {}, - 'orderers': {}} - - for msp_name in config_result.msps: - results['msps'][msp_name] = decode_fabric_MSP_config(config_result.msps[msp_name].SerializeToString()) - - for orderer_msp in config_result.orderers: - results['orderers'][orderer_msp] = decode_fabric_endpoints(config_result.orderers[orderer_msp].endpoint) - - return results - - -def process_members(members): - peers = [] - for msp_name in members.peers_by_org: - peers.append(decode_fabric_peers_info(members.peers_by_org[msp_name].peers)) - - return peers - - def get_hfc_client(): loop = asyncio.new_event_loop() @@ -77,46 +40,54 @@ def get_hfc_client(): client = Client() client.new_channel(LEDGER['channel_name']) - target_peer = Peer(name=LEDGER['peer']['name']) - - # Need loop - target_peer.init_with_bundle({ + # Add peer from substrabac ledger config file + peer = Peer(name=LEDGER['peer']['name']) + peer.init_with_bundle({ 'url': f'{LEDGER["peer"]["host"]}:{PEER_PORT}', 'grpcOptions': LEDGER['peer']['grpcOptions'], 'tlsCACerts': {'path': LEDGER['peer']['tlsCACerts']}, 'clientKey': {'path': LEDGER['peer']['clientKey']}, 'clientCert': {'path': LEDGER['peer']['clientCert']}, }) + client._peers[LEDGER['peer']['name']] = peer - client._peers[LEDGER['peer']['name']] = target_peer - - # Discovery loading + # Discover orderers and peers from channel discovery channel = client.get_channel(LEDGER['channel_name']) results = loop.run_until_complete( channel._discovery( - LEDGER['hfc_requestor'], - client._peers[LEDGER['peer']['name']], + LEDGER['requestor'], + peer, config=True, local=False ) ) - results = process_discovery(results) + results = deserialize_discovery(results) - msp_tls_root_certs = {} - for msp_id, msp_info in results['config']['msps'].items(): - msp_tls_root_certs[msp_id] = msp_info['tls_root_certs'].pop() + update_client_with_discovery(client, results) + + return loop, client + + +LEDGER['hfc'] = get_hfc_client - # Load one peer per msp for endorsement transaction - for msp in results['members']: - if msp and msp[0]['mspid'] != LEDGER['client']['msp_id']: - peer_info = msp[0] + +def update_client_with_discovery(client, discovery_results): + + # Get all msp tls root cert files + tls_root_certs = {} + for mspid, msp_info in discovery_results['config']['msps'].items(): + tls_root_certs[mspid] = msp_info['tls_root_certs'].pop() + + # Load one peer per msp for endorsing transaction + for msp in discovery_results['members']: + peer_info = msp[0] + if peer_info['mspid'] != LEDGER['client']['msp_id']: peer = Peer(name=peer_info['mspid']) with tempfile.NamedTemporaryFile() as tls_root_cert: - tls_root_cert.write(msp_tls_root_certs[peer_info['mspid']]) + tls_root_cert.write(tls_root_certs[peer_info['mspid']]) tls_root_cert.flush() - # Need loop peer.init_with_bundle({ 'url': peer_info['endpoint'], 'grpcOptions': { @@ -130,19 +101,18 @@ def get_hfc_client(): client._peers[peer_info['mspid']] = peer - # Load one orderer - orderer_mspid, orderer_info = list(results['config']['orderers'].items())[0] - orderer_endpoint = f'{orderer_info[0]["host"]}:{orderer_info[0]["port"]}' + # Load one orderer for broadcasting transaction + orderer_mspid, orderer_info = list(discovery_results['config']['orderers'].items())[0] - target_orderer = Orderer(name=orderer_mspid) + orderer = Orderer(name=orderer_mspid) with tempfile.NamedTemporaryFile() as tls_root_cert: - tls_root_cert.write(msp_tls_root_certs[orderer_mspid]) + tls_root_cert.write(tls_root_certs[orderer_mspid]) tls_root_cert.flush() # Need loop - target_orderer.init_with_bundle({ - 'url': orderer_endpoint, + orderer.init_with_bundle({ + 'url': f"{orderer_info[0]['host']}:{orderer_info[0]['port']}", 'grpcOptions': { 'grpc-max-send-message-length': 15, 'grpc.ssl_target_name_override': orderer_info[0]['host'] @@ -152,9 +122,50 @@ def get_hfc_client(): 'clientCert': {'path': LEDGER['peer']['clientCert']}, # use peer creds (mutual tls) }) - client._orderers[orderer_mspid] = target_orderer + client._orderers[orderer_mspid] = orderer - return loop, client +def deserialize_discovery(response): + results = { + 'config': None, + 'members': [] + } -LEDGER['hfc'] = get_hfc_client + for res in response.results: + if res.config_result: + results['config'] = deserialize_config(res.config_result) + + if res.members: + results['members'].extend(deserialize_members(res.members)) + + return results + + +def deserialize_config(config_result): + + results = {'msps': {}, + 'orderers': {}} + + for mspid in config_result.msps: + results['msps'][mspid] = decode_fabric_MSP_config( + config_result.msps[mspid].SerializeToString() + ) + + for mspid in config_result.orderers: + results['orderers'][mspid] = decode_fabric_endpoints( + config_result.orderers[mspid].endpoint + ) + + return results + + +def deserialize_members(members): + peers = [] + + for mspid in members.peers_by_org: + peer = decode_fabric_peers_info( + members.peers_by_org[mspid].peers + ) + peers.append(peer) + + return peers diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 9334f1ddd..1e4483c51 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -60,7 +60,7 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): args = [json.dumps(args)] peer = LEDGER['peer'] - requestor = LEDGER['hfc_requestor'] + requestor = LEDGER['requestor'] chaincode_calls = { 'invoke': client.chaincode_invoke, From c2ee5fcd00296f961ab120ad8aa73c3447d76288 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 14 Jun 2019 12:14:30 +0200 Subject: [PATCH 105/457] Add ledger mvcc error. --- substrabac/requirements.txt | 3 +-- substrabac/substrapp/ledger_utils.py | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index 9629bacc8..db3fad758 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,5 +26,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -# fabric-sdk-py==0.8.0 -git+git://github.com/hyperledger/fabric-sdk-py.git@db135d6ddd3c890d942278c7e7b340f943ab5e34 +git+git://github.com/hyperledger/fabric-sdk-py.git@f6c9a1c156559b469e9c44775a2546c60a82f9a0 # fabric-sdk-py==0.8.0 diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 1e4483c51..e6acdba1c 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -37,6 +37,10 @@ class LedgerNotFound(LedgerError): status = status.HTTP_404_NOT_FOUND +class LedgerMVCCError(LedgerError): + status = status.HTTP_412_PRECONDITION_FAILED + + class LedgerBadResponse(LedgerError): pass @@ -111,7 +115,11 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): try: response = json.loads(response) except json.decoder.JSONDecodeError: - raise LedgerBadResponse(response) + + if response == 'MVCC_READ_CONFLICT': + raise LedgerMVCCError(response) + else: + raise LedgerBadResponse(response) # Check permissions if response and 'permissions' in response and response['permissions'] != 'all': From c20a09bfd5e55a86e80bb9d63ca5d19f3b506b6c Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 14 Jun 2019 15:30:00 +0200 Subject: [PATCH 106/457] Close loop after delete client. --- substrabac/substrapp/ledger_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index e6acdba1c..670ce73b4 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -51,8 +51,8 @@ def get_hfc(): try: yield (loop, client) finally: - loop.close() del client + loop.close() def call_ledger(call_type, fcn, args=None, kwargs=None): From 9990d92053ada31f682dd1b4ee3bcf41b6d58b67 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 14 Jun 2019 19:31:53 +0200 Subject: [PATCH 107/457] Fix tls root cert encoding. --- substrabac/requirements.txt | 2 +- substrabac/substrabac/settings/deps/ledger.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index db3fad758..18e255f4c 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,4 +26,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -git+git://github.com/hyperledger/fabric-sdk-py.git@f6c9a1c156559b469e9c44775a2546c60a82f9a0 # fabric-sdk-py==0.8.0 +git+git://github.com/hyperledger/fabric-sdk-py.git@4f3215acd485e0c89ac6a6af0dcf26f0abbae424 # fabric-sdk-py==0.8.0 diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 2bb0862cb..83d60d2bb 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -1,5 +1,6 @@ import os +import base64 import asyncio import glob import json @@ -76,7 +77,9 @@ def update_client_with_discovery(client, discovery_results): # Get all msp tls root cert files tls_root_certs = {} for mspid, msp_info in discovery_results['config']['msps'].items(): - tls_root_certs[mspid] = msp_info['tls_root_certs'].pop() + tls_root_certs[mspid] = base64.decodebytes( + msp_info['tls_root_certs'].pop().encode() + ) # Load one peer per msp for endorsing transaction for msp in discovery_results['members']: From 2850134392df27dde1d07d12c0547cdb8f1fd7d2 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 17 Jun 2019 10:54:59 +0200 Subject: [PATCH 108/457] queryModelDetails input args should be a single key --- substrabac/substrapp/views/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 62de758c2..86569f5fb 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -128,7 +128,7 @@ def details(self, request, *args, **kwargs): pk = self.kwargs[lookup_url_kwarg] try: - data = query_ledger(fcn='queryModelDetails', args=[f'{pk}']) + data = get_object_from_ledger(pk, self.ledger_query_call) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) From bcfd78ac4b96baedb5763b3d0c7f482073f664db Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 17 Jun 2019 16:27:58 +0200 Subject: [PATCH 109/457] fix python syntax bug If `instance.get_object()` raises an another exception than `Http404` instance is not defined in the finally clause. Avoid usage of finally clause when it's not required. --- substrabac/substrapp/views/model.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 86569f5fb..e6ec9eecd 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -63,18 +63,18 @@ def _retrieve(self, pk): instance = self.get_object() except Http404: instance = None - finally: - if not instance or not instance.file: - instance = self.create_or_update_model(data['traintuple'], - data['traintuple']['outModel']['hash']) - - # For security reason, do not give access to local file address - # Restrain data to some fields - # TODO: do we need to send creation date and/or last modified date ? - serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) - data.update(serializer.data) - - return data + + if not instance or not instance.file: + instance = self.create_or_update_model(data['traintuple'], + data['traintuple']['outModel']['hash']) + + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date ? + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) + data.update(serializer.data) + + return data def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field From 33fd5e43d0d386cb94abcaed6ca76893f7811382 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 17 Jun 2019 16:29:57 +0200 Subject: [PATCH 110/457] proper error message when getting a model from a non done traintuple When getting a model from a not done traintuple, the API returns the followed http response (400): `{'message': "'NoneType' object is not subscriptable"}` This is not very informative. Add a check to ensure that the traintuple is at a correct status. On top of that add exception logs for easier debugging (all types of exception are catched and returned to the API user as a string without any log/print/traceback in the server). --- substrabac/substrapp/views/model.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index e6ec9eecd..d6d67630a 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -55,8 +55,12 @@ def create_or_update_model(self, traintuple, pk): def _retrieve(self, pk): validate_pk(pk) - # get instance from remote node + data = get_object_from_ledger(pk, self.ledger_query_call) + if not data or not data.get('traintuple'): + raise Exception('Invalid model: missing traintuple field') + if data['traintuple'].get('status') != "done": + raise Exception("Invalid model: traintuple must be at status done") # Try to get it from local db, else create it in local db try: @@ -83,8 +87,10 @@ def retrieve(self, request, *args, **kwargs): try: data = self._retrieve(pk) except LedgerError as e: + logging.exception(e) return Response({'message': str(e.msg)}, status=e.status) except Exception as e: + logging.exception(e) return Response({'message': str(e)}, status.HTTP_400_BAD_REQUEST) else: return Response(data, status=status.HTTP_200_OK) From 12c9bf7c6cee337e63d6b22ae12a2801eb3684c8 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 17 Jun 2019 17:42:40 +0200 Subject: [PATCH 111/457] Support external peer ports of second organization --- substrabac/substrabac/settings/deps/ledger.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 83d60d2bb..04728dd51 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -91,8 +91,13 @@ def update_client_with_discovery(client, discovery_results): tls_root_cert.write(tls_root_certs[peer_info['mspid']]) tls_root_cert.flush() + url = peer_info['endpoint'] + external_port = os.environ.get('SUBSTRABAC_PEER_PORT_EXTERNAL', None) + # use case for external development + if external_port: + url = f"{peer_info['endpoint'].split(':')[0]}:{external_port}" peer.init_with_bundle({ - 'url': peer_info['endpoint'], + 'url': url, 'grpcOptions': { 'grpc-max-send-message-length': 15, 'grpc.ssl_target_name_override': peer_info['endpoint'].split(':')[0] From 0e56e7a19acfd6d3c34a2ec48b6fd7c3b172ca29 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 14 Jun 2019 17:51:20 +0200 Subject: [PATCH 112/457] (WIP) more events. --- substrabac/events/apps.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 25b9c54c6..484c1b884 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -38,9 +38,21 @@ def get_block_payload(block): return payload +def print_status(block, event='CREATED'): + + meta = None + if 'metadata' in block: + if 'metadata' in block['metadata']: + if len(block['metadata']['metadata']): + meta = block['metadata']['metadata'][-1] + print(event, '', meta) + + def on_tuple_event(block): payload = get_block_payload(block) + print_status(block, 'READY') + worker_queue = f"{LEDGER['name']}.worker" data_owner = get_hash(LEDGER['signcert']) @@ -104,11 +116,19 @@ def wait(): stream = channel_event_hub.connect(filtered=False) channel_event_hub.registerChaincodeEvent(chaincode_name, - 'traintuple-creation', + 'traintuple-ready', onEvent=on_tuple_event) channel_event_hub.registerChaincodeEvent(chaincode_name, - 'testtuple-creation', + 'testtuple-ready', onEvent=on_tuple_event) + + channel_event_hub.registerChaincodeEvent(chaincode_name, + 'traintuple-created', + onEvent=print_status) + channel_event_hub.registerChaincodeEvent(chaincode_name, + 'testtuple-created', + onEvent=print_status) + loop.run_until_complete(stream) From 086fcba9cfe39be82792ca206d35d52a0bd2ba68 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 18 Jun 2019 08:45:53 +0200 Subject: [PATCH 113/457] Update more events. --- substrabac/events/apps.py | 66 ++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 484c1b884..0ebc2291e 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -14,6 +14,7 @@ from hfc.fabric.peer import Peer from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore +from hfc.protos.peer.transaction_pb2 import TxValidationCode from substrapp.tasks.tasks import prepare_tuple from substrapp.utils import get_hash @@ -21,6 +22,18 @@ LEDGER = getattr(settings, 'LEDGER', None) +def get_tuple_type(payload): + + tuple_type = None + + if 'inModels' in payload: + tuple_type = 'traintuple' + elif 'model' in payload: + tuple_type = 'testtuple' + + return tuple_type + + @contextlib.contextmanager def get_event_loop(): loop = asyncio.new_event_loop() @@ -38,36 +51,39 @@ def get_block_payload(block): return payload -def print_status(block, event='CREATED'): +def log_tuple_status(block, tuple_type, key, event_type): - meta = None - if 'metadata' in block: - if 'metadata' in block['metadata']: - if len(block['metadata']['metadata']): - meta = block['metadata']['metadata'][-1] - print(event, '', meta) + try: + meta = block['metadata']['metadata'][-1] + if isinstance(meta, list): + meta = int(meta.pop()) + status = TxValidationCode.Name(meta) + except Exception: + print(f'[ChaincodeEvent] Received {tuple_type} "{event_type}" (key: "{key}")') + else: + print(f'[ChaincodeEvent] Received {tuple_type} "{event_type}" (key: "{key}") with status: {status}') -def on_tuple_event(block): +def on_tuple_created(block): payload = get_block_payload(block) + tuple_type = get_tuple_type(payload) + log_tuple_status(block, tuple_type, payload['key'], 'created') + - print_status(block, 'READY') +def on_tuple_ready(block): + payload = get_block_payload(block) + tuple_type = get_tuple_type(payload) + log_tuple_status(block, tuple_type, payload['key'], 'ready') worker_queue = f"{LEDGER['name']}.worker" data_owner = get_hash(LEDGER['signcert']) - if data_owner == payload['dataset']['worker']: - tuple_type = None - if 'inModels' in payload: - tuple_type = 'traintuple' - elif 'model' in payload: - tuple_type = 'testtuple' - - if tuple_type is not None: - prepare_tuple.apply_async( - (payload, tuple_type), - task_id=payload['key'], - queue=worker_queue) + if data_owner == payload['dataset']['worker'] and tuple_type is not None: + prepare_tuple.apply_async( + (payload, tuple_type), + task_id=payload['key'], + queue=worker_queue + ) def wait(): @@ -117,17 +133,17 @@ def wait(): channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-ready', - onEvent=on_tuple_event) + onEvent=on_tuple_ready) channel_event_hub.registerChaincodeEvent(chaincode_name, 'testtuple-ready', - onEvent=on_tuple_event) + onEvent=on_tuple_ready) channel_event_hub.registerChaincodeEvent(chaincode_name, 'traintuple-created', - onEvent=print_status) + onEvent=on_tuple_created) channel_event_hub.registerChaincodeEvent(chaincode_name, 'testtuple-created', - onEvent=print_status) + onEvent=on_tuple_created) loop.run_until_complete(stream) From d3a22a3a0428082d124e57c486ea70cbfcdf7e49 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 19 Jun 2019 15:39:26 +0200 Subject: [PATCH 114/457] Add signal after publish in celery + flower. --- docker/flower/Dockerfile | 17 +++++++++++++++++ docker/start.py | 15 +++++++++++++-- substrabac/substrabac/celery.py | 14 +++++++++++++- 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 docker/flower/Dockerfile diff --git a/docker/flower/Dockerfile b/docker/flower/Dockerfile new file mode 100644 index 000000000..5bf9a390b --- /dev/null +++ b/docker/flower/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.6 + +RUN apt-get update +RUN apt-get install -y python3 python3-pip python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev +RUN apt-get install -y git curl netcat + +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +COPY ./substrabac/requirements.txt /usr/src/app/. + +RUN pip3 install -r requirements.txt +RUN pip3 install flower + +COPY ./substrabac/libs /usr/src/app/libs +COPY ./substrabac/substrapp /usr/src/app/substrapp +COPY ./substrabac/substrabac /usr/src/app/substrabac diff --git a/docker/start.py b/docker/start.py index d446322be..05fa6002c 100644 --- a/docker/start.py +++ b/docker/start.py @@ -40,7 +40,6 @@ def generate_docker_compose_file(conf, launch_settings): # CELERY CELERY_BROKER_URL = f'amqp://{RABBITMQ_DEFAULT_USER}:{RABBITMQ_DEFAULT_PASS}@{RABBITMQ_DOMAIN}:{RABBITMQ_PORT}//' - try: from ruamel import yaml except ImportError: @@ -85,7 +84,7 @@ def generate_docker_compose_file(conf, launch_settings): 'container_name': 'rabbit', 'hostname': 'rabbitmq', # Must be set to be able to recover from volume 'restart': 'unless-stopped', - 'image': 'rabbitmq:3', + 'image': 'rabbitmq:3-management', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': [ f'RABBITMQ_DEFAULT_USER={RABBITMQ_DEFAULT_USER}', @@ -94,6 +93,18 @@ def generate_docker_compose_file(conf, launch_settings): f'RABBITMQ_NODENAME={RABBITMQ_NODENAME}'], 'volumes': [f'{SUBSTRA_FOLDER}/backup/rabbit-data:/var/lib/rabbitmq'] }, + 'flower': { + 'container_name': f'flower', + 'hostname': f'flower', + 'ports': ['5555:5555'], + 'image': 'substra/flower', + 'restart': 'unless-stopped', + 'command': 'celery flower -A substrabac', + 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, + 'environment': [f'CELERY_BROKER_URL={CELERY_BROKER_URL}', + 'DJANGO_SETTINGS_MODULE=substrabac.settings.common'], + 'depends_on': ['rabbit', 'postgresql'] + } }, 'path': os.path.join(dir_path, './docker-compose-dynamic.yaml')} diff --git a/substrabac/substrabac/celery.py b/substrabac/substrabac/celery.py index b862eb821..d2a4c459f 100644 --- a/substrabac/substrabac/celery.py +++ b/substrabac/substrabac/celery.py @@ -1,7 +1,8 @@ from __future__ import absolute_import, unicode_literals import os from celery import Celery - +from celery import current_app +from celery.signals import after_task_publish # set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'substrabac.settings.prod') @@ -27,3 +28,14 @@ def setup_periodic_tasks(sender, **kwargs): name='query Traintuples to prepare train task on todo traintuples') sender.add_periodic_task(period, prepare_testing_task.s(), queue='scheduler', name='query Testuples to prepare test task on todo testuples') + + +@after_task_publish.connect +def update_task_state(sender=None, headers=None, body=None, **kwargs): + # Change task.status to 'WAITING' for all tasks which are sent in. + # This allows one to distinguish between PENDING tasks which have been + # sent in and tasks which do not exist. State will change to + # SUCCESS, FAILURE, etc. once the process terminates. + task = current_app.tasks.get(sender) + backend = task.backend if task else current_app.backend + backend.store_result(headers['id'], None, 'WAITING') From aa3604d3c7c6d113498bae03fe8b01700e16dc83 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 19 Jun 2019 16:10:04 +0200 Subject: [PATCH 115/457] Add check before send prepare_tuple. --- substrabac/events/apps.py | 16 +++++++++++----- substrabac/substrapp/tasks/tasks.py | 15 +++++++++++---- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 0ebc2291e..4cc85a108 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -19,6 +19,8 @@ from substrapp.tasks.tasks import prepare_tuple from substrapp.utils import get_hash +from celery.result import AsyncResult + LEDGER = getattr(settings, 'LEDGER', None) @@ -79,11 +81,15 @@ def on_tuple_ready(block): data_owner = get_hash(LEDGER['signcert']) if data_owner == payload['dataset']['worker'] and tuple_type is not None: - prepare_tuple.apply_async( - (payload, tuple_type), - task_id=payload['key'], - queue=worker_queue - ) + tkey = payload['key'] + if AsyncResult(tkey).state == 'PENDING': + prepare_tuple.apply_async( + (payload, tuple_type), + task_id=tkey, + queue=worker_queue + ) + else: + print(f'[ChaincodeEvent] Tuple task ({tkey}) already exists') def wait(): diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index c2ba9f924..02b88bff9 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -9,6 +9,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.conf import settings from rest_framework.reverse import reverse +from celery.result import AsyncResult from substrabac.celery import app from substrapp.utils import get_hash, create_directory, get_remote_file, uncompress_content @@ -202,10 +203,16 @@ def prepare_task(tuple_type): tuples = query_tuples(tuple_type, data_owner) for subtuple in tuples: - prepare_tuple.apply_async( - (subtuple, tuple_type), - task_id=subtuple['key'], - queue=worker_queue) + tkey = subtuple['key'] + # Verify that tuple task does not already exist + if AsyncResult(tkey).state == 'PENDING': + prepare_tuple.apply_async( + (subtuple, tuple_type), + task_id=tkey, + queue=worker_queue + ) + else: + print(f'[Scheduler] Tuple task ({tkey}) already exists') @app.task(ignore_result=False) From 9181e5f432a976fa13fabce8b8921cd54418c335 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 19 Jun 2019 17:06:11 +0200 Subject: [PATCH 116/457] Improve prepare_tuple --- substrabac/substrapp/ledger_utils.py | 14 ++++++++++++- substrabac/substrapp/tasks/tasks.py | 31 +++++++++++++--------------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 670ce73b4..4d8b82399 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -12,9 +12,12 @@ class LedgerError(Exception): status = status.HTTP_400_BAD_REQUEST def __init__(self, msg): - super(LedgerError, self).__init__() + super(LedgerError, self).__init__(msg) self.msg = msg + def __repr__(self): + return self.msg + class LedgerConflict(LedgerError): @@ -24,6 +27,9 @@ def __init__(self, msg, pkhash): super(LedgerConflict, self).__init__(msg) self.pkhash = pkhash + def __repr__(self): + return self.msg + class LedgerTimeout(LedgerError): status = status.HTTP_408_REQUEST_TIMEOUT @@ -45,6 +51,10 @@ class LedgerBadResponse(LedgerError): pass +class LedgerStatusError(LedgerError): + pass + + @contextlib.contextmanager def get_hfc(): loop, client = LEDGER['hfc']() @@ -118,6 +128,8 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): if response == 'MVCC_READ_CONFLICT': raise LedgerMVCCError(response) + elif 'cannot change status' in response: + raise LedgerStatusError(response) else: raise LedgerBadResponse(response) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 02b88bff9..e2f12a278 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -10,11 +10,12 @@ from django.conf import settings from rest_framework.reverse import reverse from celery.result import AsyncResult +from celery.exceptions import Ignore from substrabac.celery import app from substrapp.utils import get_hash, create_directory, get_remote_file, uncompress_content from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, - query_tuples, LedgerError) + query_tuples, LedgerError, LedgerStatusError) from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code @@ -232,26 +233,22 @@ def prepare_tuple(subtuple, tuple_type): worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] try: - try: - log_start_tuple(tuple_type, subtuple['key']) - except LedgerError as e: - # Do not log_fail_tuple in this case, because prepare_tuple task are not unique - # in case of multiple instances of substrabac running for the same organisation - # So prepare_tuple tasks are ignored if it cannot log_start_tuple - # TODO: find a way to handle this special case to avoid silent failure in other cases. - logging.exception(e) - else: - compute_task.apply_async( - (tuple_type, subtuple, fltask), - queue=worker_queue) + log_start_tuple(tuple_type, subtuple['key']) + except LedgerStatusError as e: + # Do not log_fail_tuple in this case, because prepare_tuple task are not unique + # in case of multiple instances of substrabac running for the same organisation + # So prepare_tuple tasks are ignored if it cannot log_start_tuple + logging.exception(e) + raise Ignore() + try: + compute_task.apply_async( + (tuple_type, subtuple, fltask), + queue=worker_queue) except Exception as e: error_code = compute_error_code(e) logging.error(error_code, exc_info=True) - try: - log_fail_tuple(tuple_type, subtuple['key'], error_code) - except LedgerError as e: - logging.exception(e) + log_fail_tuple(tuple_type, subtuple['key'], error_code) @app.task(bind=True, ignore_result=False) From 1ce8b271d93dc496375cd0cb9c27398c95f33dba Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 19 Jun 2019 17:47:32 +0200 Subject: [PATCH 117/457] Fix tests --- substrabac/substrapp/tests/tests_tasks.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 000f25b19..0b0ae27d5 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -12,7 +12,7 @@ from django_celery_results.models import TaskResult from substrapp.models import DataSample -from substrapp.ledger_utils import LedgerError, LedgerBadResponse +from substrapp.ledger_utils import LedgerStatusError from substrapp.utils import compute_hash, get_computed_hash, get_remote_file, get_hash, create_directory from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, @@ -524,6 +524,7 @@ def __init__(self): mock.patch('substrapp.tasks.tasks.put_metric') as mput_metric, \ mock.patch('substrapp.tasks.tasks.put_algo') as mput_algo, \ mock.patch('substrapp.tasks.tasks.json.loads') as mjson_loads, \ + mock.patch('substrapp.tasks.tasks.AsyncResult') as masyncres, \ mock.patch('substrapp.tasks.tasks.put_model') as mput_model: msettings.return_value = FakeSettings() @@ -539,20 +540,16 @@ def __init__(self): mput_algo.return_value = 'algo' mput_model.return_value = 'model' + masyncres.return_value.state = 'PENDING' + mock_filter = MagicMock() mock_filter.count.return_value = 1 mtaskresult.return_value = mock_filter mjson_loads.return_value = {'worker': 'worker'} - with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple, \ - mock.patch('substrapp.tasks.tasks.log_fail_tuple') as mlog_fail_tuple: - mlog_start_tuple.side_effect = LedgerError("Test") - mlog_fail_tuple.return_value = 'data' - prepare_task('traintuple') - with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple: - mlog_start_tuple.side_effect = LedgerBadResponse('Bad Response') + mlog_start_tuple.side_effect = LedgerStatusError('Bad Response') prepare_task('traintuple') with mock.patch('substrapp.tasks.tasks.log_start_tuple') as mlog_start_tuple, \ From 209667c2534da5966504de28868992424fb44783 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 20 Jun 2019 16:11:19 +0200 Subject: [PATCH 118/457] Add chaincode endorsement information discovery --- substrabac/substrabac/settings/deps/ledger.py | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 04728dd51..d3fabc193 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -59,9 +59,11 @@ def get_hfc_client(): LEDGER['requestor'], peer, config=True, - local=False + local=False, + interests=[{'chaincodes': [{'name': LEDGER['chaincode_name']}]}] ) ) + results = deserialize_discovery(results) update_client_with_discovery(client, results) @@ -136,16 +138,20 @@ def update_client_with_discovery(client, discovery_results): def deserialize_discovery(response): results = { 'config': None, - 'members': [] + 'members': [], + 'cc_query_res': None } for res in response.results: - if res.config_result: + if res.config_result and res.config_result.msps and res.config_result.orderers: results['config'] = deserialize_config(res.config_result) if res.members: results['members'].extend(deserialize_members(res.members)) + if res.cc_query_res and res.cc_query_res.content: + results['cc_query_res'] = deserialize_cc_query_res(res.cc_query_res) + return results @@ -177,3 +183,34 @@ def deserialize_members(members): peers.append(peer) return peers + + +def deserialize_cc_query_res(cc_query_res): + cc_queries = [] + + for cc_query_content in cc_query_res.content: + cc_query = { + 'chaincode': cc_query_content.chaincode, + 'endorsers_by_groups': {}, + 'layouts': [] + } + + for group in cc_query_content.endorsers_by_groups: + peers = decode_fabric_peers_info( + cc_query_content.endorsers_by_groups[group].peers + ) + + cc_query['endorsers_by_groups'][group] = peers + + for layout_content in cc_query_content.layouts: + layout = { + 'quantities_by_group': { + group: int(layout_content.quantities_by_group[group]) + for group in layout_content.quantities_by_group + } + } + cc_query['layouts'].append(layout) + + cc_queries.append(cc_query) + + return cc_queries From faa08c119a219cb750955a52933b1641cc34bf7a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 21 Jun 2019 12:00:19 +0200 Subject: [PATCH 119/457] Add archive option for populate.py in order to do a full remote populate. --- populate.py | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/populate.py b/populate.py index 20cb01706..2e3449b77 100644 --- a/populate.py +++ b/populate.py @@ -84,6 +84,8 @@ def do_populate(): help='Launch populate with two orgs') group.add_argument('-th', '--three-orgs', action='store_const', dest='nb_org', const=3, help='Launch populate with three orgs') + parser.add_argument('-a', '--archive', action='store_true', + help='Launch populate with archive data samples only') parser.set_defaults(nb_org=2) args = vars(parser.parse_args()) @@ -113,21 +115,34 @@ def do_populate(): #################################################### train_data_sample_keys = [] - print(f'register train data (from server) on datamanager {org_1} (will take datamanager creator as worker)') - data_samples_path = ['./fixtures/chunantes/datasamples/train/0024306', - './fixtures/chunantes/datasamples/train/0024307'] - for d in data_samples_path: - try: - shutil.copytree(os.path.join(dir_path, d), - os.path.join(server_path, d)) - except FileExistsError: - pass - data = { - 'paths': [os.path.join(server_path, d) for d in data_samples_path], - 'data_manager_keys': [data_manager_org1_key], - 'test_only': False, - } - train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True, register=True) + + if not args['archive']: + print(f'register train data (from server) on datamanager {org_1} (will take datamanager creator as worker)') + data_samples_path = ['./fixtures/chunantes/datasamples/train/0024306', + './fixtures/chunantes/datasamples/train/0024307'] + for d in data_samples_path: + try: + shutil.copytree(os.path.join(dir_path, d), + os.path.join(server_path, d)) + except FileExistsError: + pass + data = { + 'paths': [os.path.join(server_path, d) for d in data_samples_path], + 'data_manager_keys': [data_manager_org1_key], + 'test_only': False, + } + train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True, register=True) + else: + print(f'register train data on datamanager {org_1} (will take datamanager creator as worker)') + data = { + 'paths': [ + os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024306.zip'), + os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024307.zip') + ], + 'data_manager_keys': [data_manager_org1_key], + 'test_only': False, + } + train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True, register=False) #################################################### From 15851fe0e3dde1b3cb51c07d82868532b00aa6c2 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 21 Jun 2019 14:29:09 +0200 Subject: [PATCH 120/457] update to laste version of fabric-sdk-py --- substrabac/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index 18e255f4c..db437e65e 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -26,4 +26,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -git+git://github.com/hyperledger/fabric-sdk-py.git@4f3215acd485e0c89ac6a6af0dcf26f0abbae424 # fabric-sdk-py==0.8.0 +git+git://github.com/hyperledger/fabric-sdk-py.git@4d41aef84785ab790471db4ad9226b19294a27e7 # fabric-sdk-py==0.8.0 From 1954f82182dee8a6a045c35f1eb92e9a84a86f43 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 21 Jun 2019 16:23:03 +0200 Subject: [PATCH 121/457] Update code to last fabric-sdk-py --- substrabac/substrapp/ledger_utils.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 4d8b82399..55db1306c 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -106,13 +106,15 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): except TimeoutError as e: raise LedgerTimeout(str(e)) except Exception as e: + if 'access denied' in e.details(): + raise LedgerForbidden(f'Access denied for {(fcn, args)}') + logging.exception(e) raise LedgerError(str(e)) # Sanity check of the response: - if 'access denied' in response: - raise LedgerForbidden(f'Access denied for {(fcn, args)}') - elif 'no element with key' in response: + + if 'no element with key' in response: raise LedgerNotFound(f'No element founded for {(fcn, args)}') elif 'tkey' in response: pkhash = response.replace('(', '').replace(')', '').split('tkey: ')[-1].strip() From 71996f55c36634113c51edb3c109f065119f73b6 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 24 Jun 2019 14:43:23 +0200 Subject: [PATCH 122/457] Raven dsn for env variable + fix bug in ledger exception. --- docker/start.py | 2 ++ substrabac/substrabac/settings/deps/raven.py | 2 +- substrabac/substrapp/ledger_utils.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docker/start.py b/docker/start.py index 05fa6002c..a6f9d1ada 100644 --- a/docker/start.py +++ b/docker/start.py @@ -6,6 +6,7 @@ from subprocess import call, check_output dir_path = os.path.dirname(os.path.realpath(__file__)) +raven_backend_url = "https://cff352ba26fc49f19e01692db93bf951@sentry.io/1317743" raven_dryrunner_url = "https://a1c2de65bb0f4120aa11d75bca9b47f6@sentry.io/1402760" raven_worker_url = "https://76abd6b5d11e48ea8a118831c86fc615@sentry.io/1402762" raven_scheduler_url = raven_worker_url @@ -242,6 +243,7 @@ def generate_docker_compose_file(conf, launch_settings): worker['environment'].append(f"DEFAULT_DOMAIN={default_domain}") scheduler['environment'].append(f"DEFAULT_DOMAIN={default_domain}") dryrunner['environment'].append(f"DEFAULT_DOMAIN={default_domain}") + backend['environment'].append(f"RAVEN_URL={raven_backend_url}") scheduler['environment'].append(f"RAVEN_URL={raven_scheduler_url}") worker['environment'].append(f"RAVEN_URL={raven_worker_url}") dryrunner['environment'].append(f"RAVEN_URL={raven_dryrunner_url}") diff --git a/substrabac/substrabac/settings/deps/raven.py b/substrabac/substrabac/settings/deps/raven.py index a3f847886..e21214d6c 100644 --- a/substrabac/substrabac/settings/deps/raven.py +++ b/substrabac/substrabac/settings/deps/raven.py @@ -3,6 +3,6 @@ from sentry_sdk.integrations.django import DjangoIntegration sentry_sdk.init( - dsn=os.environ.get("RAVEN_URL", "https://cff352ba26fc49f19e01692db93bf951@sentry.io/1317743"), + dsn=os.environ.get("RAVEN_URL"), integrations=[DjangoIntegration()] ) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 55db1306c..5366da232 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -106,7 +106,7 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): except TimeoutError as e: raise LedgerTimeout(str(e)) except Exception as e: - if 'access denied' in e.details(): + if hasattr(e, 'details') and 'access denied' in e.details(): raise LedgerForbidden(f'Access denied for {(fcn, args)}') logging.exception(e) From aade9982ed83196fbbe99b3549af31f48d4f4dd6 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 25 Jun 2019 15:55:13 +0200 Subject: [PATCH 123/457] fix issue related to macos environnement #262 --- substrabac/substrapp/tasks/utils.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index b8bf4682f..0de2044be 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -5,6 +5,8 @@ import time import logging + +from subprocess import check_output from django.conf import settings DOCKER_LABEL = 'substra_task' @@ -264,9 +266,6 @@ def join(self, timeout=None): class ResourcesManager(): __concurrency = int(getattr(settings, 'CELERY_WORKER_CONCURRENCY')) - __memory_mb = int(os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024. ** 2)) - __memory_mb_per_task = __memory_mb // __concurrency - __cpu_count = os.cpu_count() __cpu_sets = get_cpu_sets(__cpu_count, __concurrency) @@ -280,7 +279,11 @@ class ResourcesManager(): @classmethod def memory_limit_mb(cls): - return cls.__memory_mb_per_task + try: + return int(os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024. ** 2)) // cls.__concurrency + except ValueError: + # fixes macOS issue https://github.com/SubstraFoundation/substrabac/issues/262 + return int(check_output(['sysctl', '-n', 'hw.memsize']).strip()) // cls.__concurrency @classmethod def get_cpu_gpu_sets(cls): From 6b3f6dc78b285984a61c032f3e539069f8de34df Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Thu, 20 Jun 2019 16:42:56 +0200 Subject: [PATCH 124/457] Handle status from ledger --- substrabac/substrapp/ledger_utils.py | 41 ++++++++++++++++++---------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 5366da232..bb23c1a38 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -19,7 +19,14 @@ def __repr__(self): return self.msg -class LedgerConflict(LedgerError): +class LedgerResponseError(LedgerError): + + @classmethod + def from_response(cls, response): + return LedgerResponseError(response.get("error")) + + +class LedgerConflict(LedgerResponseError): status = status.HTTP_409_CONFLICT @@ -30,16 +37,21 @@ def __init__(self, msg, pkhash): def __repr__(self): return self.msg + @classmethod + def from_response(cls, response): + pkhash = response["error"].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + return LedgerConflict(response.get("error"), pkhash=pkhash) + class LedgerTimeout(LedgerError): status = status.HTTP_408_REQUEST_TIMEOUT -class LedgerForbidden(LedgerError): +class LedgerForbidden(LedgerResponseError): status = status.HTTP_403_FORBIDDEN -class LedgerNotFound(LedgerError): +class LedgerNotFound(LedgerResponseError): status = status.HTTP_404_NOT_FOUND @@ -47,7 +59,7 @@ class LedgerMVCCError(LedgerError): status = status.HTTP_412_PRECONDITION_FAILED -class LedgerBadResponse(LedgerError): +class LedgerBadResponse(LedgerResponseError): pass @@ -112,17 +124,6 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): logging.exception(e) raise LedgerError(str(e)) - # Sanity check of the response: - - if 'no element with key' in response: - raise LedgerNotFound(f'No element founded for {(fcn, args)}') - elif 'tkey' in response: - pkhash = response.replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if len(pkhash) == 64: - raise LedgerConflict(msg='Asset conflict', pkhash=pkhash) - else: - raise LedgerBadResponse(response) - # Deserialize the stringified json try: response = json.loads(response) @@ -135,6 +136,16 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): else: raise LedgerBadResponse(response) + status_to_exception = { + status.HTTP_400_BAD_REQUEST: LedgerBadResponse, + status.HTTP_403_FORBIDDEN: LedgerForbidden, + status.HTTP_404_NOT_FOUND: LedgerNotFound, + status.HTTP_409_CONFLICT: LedgerConflict, + } + if response and "error" in response: + status_code = response.get("status", status.HTTP_500_INTERNAL_SERVER_ERROR) + exception_class = status_to_exception.get(status_code, LedgerBadResponse) + raise exception_class.from_response(response) # Check permissions if response and 'permissions' in response and response['permissions'] != 'all': raise LedgerForbidden('Not allowed') From 3909de1d242a7dc13b3449e02a2c35b650ad61e2 Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Fri, 21 Jun 2019 16:12:02 +0200 Subject: [PATCH 125/457] Fix minor dict access --- substrabac/substrapp/ledger_utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index bb23c1a38..fb26fbcf9 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -23,7 +23,7 @@ class LedgerResponseError(LedgerError): @classmethod def from_response(cls, response): - return LedgerResponseError(response.get("error")) + return LedgerResponseError(response['error']) class LedgerConflict(LedgerResponseError): @@ -39,8 +39,8 @@ def __repr__(self): @classmethod def from_response(cls, response): - pkhash = response["error"].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - return LedgerConflict(response.get("error"), pkhash=pkhash) + pkhash = response['error'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + return LedgerConflict(response['error'], pkhash=pkhash) class LedgerTimeout(LedgerError): @@ -142,8 +142,8 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): status.HTTP_404_NOT_FOUND: LedgerNotFound, status.HTTP_409_CONFLICT: LedgerConflict, } - if response and "error" in response: - status_code = response.get("status", status.HTTP_500_INTERNAL_SERVER_ERROR) + if response and 'error' in response: + status_code = response['status'] exception_class = status_to_exception.get(status_code, LedgerBadResponse) raise exception_class.from_response(response) # Check permissions From 6dbb969bfd6f7f65a44ee2a682db489918b46598 Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Tue, 25 Jun 2019 17:30:44 +0200 Subject: [PATCH 126/457] Update exception mech after review --- substrabac/substrapp/ledger_utils.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index fb26fbcf9..9dcff5350 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -40,6 +40,8 @@ def __repr__(self): @classmethod def from_response(cls, response): pkhash = response['error'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() + if 'tkey: ' not in response['error'] or len(pkhash) != 64: + return LedgerBadResponse(response['error']) return LedgerConflict(response['error'], pkhash=pkhash) @@ -67,6 +69,14 @@ class LedgerStatusError(LedgerError): pass +STATUS_TO_EXCEPTION = { + status.HTTP_400_BAD_REQUEST: LedgerBadResponse, + status.HTTP_403_FORBIDDEN: LedgerForbidden, + status.HTTP_404_NOT_FOUND: LedgerNotFound, + status.HTTP_409_CONFLICT: LedgerConflict, +} + + @contextlib.contextmanager def get_hfc(): loop, client = LEDGER['hfc']() @@ -136,15 +146,9 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): else: raise LedgerBadResponse(response) - status_to_exception = { - status.HTTP_400_BAD_REQUEST: LedgerBadResponse, - status.HTTP_403_FORBIDDEN: LedgerForbidden, - status.HTTP_404_NOT_FOUND: LedgerNotFound, - status.HTTP_409_CONFLICT: LedgerConflict, - } if response and 'error' in response: status_code = response['status'] - exception_class = status_to_exception.get(status_code, LedgerBadResponse) + exception_class = STATUS_TO_EXCEPTION.get(status_code, LedgerBadResponse) raise exception_class.from_response(response) # Check permissions if response and 'permissions' in response and response['permissions'] != 'all': From 8830197edd61c37e56f7e56863430fd43503e3b8 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 24 Jun 2019 16:48:20 +0200 Subject: [PATCH 127/457] add datasample: separate local from remote files --- substrabac/substrapp/views/datasample.py | 94 ++++++++++++------------ 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index e2aba1c43..3d4baa313 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -86,54 +86,58 @@ def commit(serializer, ledger_data): def compute_data(self, request): data = {} - # files, should be archive - for k, file in request.FILES.items(): - pkhash = get_dir_hash(file) # can raise - # check pkhash does not belong to the list - try: - existing = data[pkhash] - except KeyError: - pass - else: - raise Exception(f'Your data sample archives contain same files leading to same pkhash, ' - f'please review the content of your achives. ' - f'Archives {file} and {existing["file"]} are the same') - data[pkhash] = { - 'pkhash': pkhash, - 'file': file - } - # path/paths case - path = request.POST.get('path', None) - paths = request.POST.getlist('paths', []) - - if path and paths: - raise Exception('Cannot use path and paths together.') - - if path is not None: - paths = [path] - - # paths, should be directories - for path in paths: - if not os.path.isdir(path): - raise Exception(f'One of your paths does not exist, ' - f'is not a directory or is not an absolute path: {path}') - pkhash = dirhash(path, 'sha256') - try: - existing = data[pkhash] - except KeyError: - pass - else: - # existing can be a dict with a field path or file - raise Exception(f'Your data sample directory contain same files leading to same pkhash. ' - f'Invalid path: {path}.') + # files can be uploaded inside the HTTP request or can already be + # available on local disk + if len(request.FILES) > 0: - data[pkhash] = { - 'pkhash': pkhash, - 'path': normpath(path) - } + for k, file in request.FILES.items(): + pkhash = get_dir_hash(file) + try: + existing = data[pkhash] + except KeyError: + pass + else: + raise Exception( + f'Your data sample archives contain same files leading to same pkhash, ' + f'please review the content of your achives. ' + f'Archives {file} and {existing["file"]} are the same') + + data[pkhash] = { + 'pkhash': pkhash, + 'file': file + } + + else: # files must be available on local filesystem + path = request.POST.get('path') + paths = request.POST.getlist('paths') + + if path and paths: + raise Exception('Cannot use path and paths together.') + if path is not None: + paths = [path] + + # paths, should be directories + for path in paths: + if not os.path.isdir(path): + raise Exception(f'One of your paths does not exist, ' + f'is not a directory or is not an absolute path: {path}') + pkhash = dirhash(path, 'sha256') + try: + existing = data[pkhash] + except KeyError: + pass + else: + # existing can be a dict with a field path or file + raise Exception(f'Your data sample directory contain same files leading to same pkhash. ' + f'Invalid path: {path}.') + + data[pkhash] = { + 'pkhash': pkhash, + 'path': normpath(path) + } - if not data: # data empty + if not data: raise Exception(f'No data sample provided.') return list(data.values()) From 3935e333d8b69a4cec580a9d03ce0367e7b1dd02 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 24 Jun 2019 17:11:45 +0200 Subject: [PATCH 128/457] add datasample: path/paths could be a dir of datasamples --- .../tests/views/tests_views_datasample.py | 35 +++++++++++++++++++ substrabac/substrapp/views/datasample.py | 10 ++++++ 2 files changed, 45 insertions(+) diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 43ba2e1ea..24734bc4a 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -160,6 +160,41 @@ def test_data_create(self): data['file'].close() + def test_data_create_parent_path(self): + url = reverse('substrapp:data_sample-list') + + dir_path = os.path.dirname(os.path.realpath(__file__)) + + data_zip_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') + data_parent_path = os.path.join(MEDIA_ROOT, 'data_samples') + data_path = os.path.join(data_parent_path, '0024700') + + with open(data_zip_path, 'rb') as data_zip: + uncompress_content(data_zip.read(), data_path) + + # dir hash + pkhash = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' + + data_manager_keys = [ + get_hash(os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'))] + + data = { + 'path': data_parent_path, + 'data_manager_keys': data_manager_keys, + 'test_only': False, + 'multiple': True, + } + + with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ + mock.patch.object(LedgerDataSampleSerializer, 'create') as mcreate: + + mdatamanager.return_value = FakeFilterDataManager(1) + mcreate.return_value = {'keys': [pkhash]} + response = self.client.post(url, data=data, format='multipart', **self.extra) + + self.assertEqual(response.data[0]['pkhash'], pkhash) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + def test_data_create_path(self): url = reverse('substrapp:data_sample-list') diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 3d4baa313..c7155a4cf 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -117,6 +117,16 @@ def compute_data(self, request): if path is not None: paths = [path] + recursive_dir = request.POST.get('multiple', 'false').lower() == 'true' + if recursive_dir: + # list all directories from parent directories + parent_paths = paths + paths = [] + for parent_path in parent_paths: + subdirs = next(os.walk(parent_path))[1] + subdirs = [os.path.join(parent_path, s) for s in subdirs] + paths.extend(subdirs) + # paths, should be directories for path in paths: if not os.path.isdir(path): From 66536ec9690d51559c1754b3e420fee6e657fa3e Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 25 Jun 2019 09:17:21 +0200 Subject: [PATCH 129/457] add datasample: add some checks --- substrabac/substrapp/views/datasample.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index c7155a4cf..08444f188 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -125,6 +125,9 @@ def compute_data(self, request): for parent_path in parent_paths: subdirs = next(os.walk(parent_path))[1] subdirs = [os.path.join(parent_path, s) for s in subdirs] + if not subdirs: + raise Exception( + f'No data sample directories in folder {parent_path}') paths.extend(subdirs) # paths, should be directories From fad72e89acbe514cf5e52ac643b9f5a1b9e9ef0a Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 1 Jul 2019 17:21:21 +0200 Subject: [PATCH 130/457] fix read from POST in datasamples view --- substrabac/substrapp/views/datasample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 08444f188..615738053 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -117,7 +117,7 @@ def compute_data(self, request): if path is not None: paths = [path] - recursive_dir = request.POST.get('multiple', 'false').lower() == 'true' + recursive_dir = str(request.POST.get('multiple', 'false')).lower() == 'true' if recursive_dir: # list all directories from parent directories parent_paths = paths From cb77f4e85c9f09de5f88f960404246555ebd875e Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 2 Jul 2019 10:05:29 +0200 Subject: [PATCH 131/457] rename data_manager to dataset --- populate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/populate.py b/populate.py index 2e3449b77..6c49b7033 100644 --- a/populate.py +++ b/populate.py @@ -56,7 +56,7 @@ def get_or_create(data, profile, asset, dryrun=False, register=False): def update_datamanager(data_manager_key, data, profile): client.set_config(profile) try: - r = client.update('data_manager', data_manager_key, data) + r = client.update('dataset', data_manager_key, data) except substra.exceptions.AlreadyExists as e: r = e.response.json() @@ -110,7 +110,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/chunantes/datamanagers/datamanager0/description.md'), 'permissions': 'all', } - data_manager_org1_key = get_or_create(data, org_1, 'data_manager', dryrun=True) + data_manager_org1_key = get_or_create(data, org_1, 'dataset', dryrun=True) #################################################### @@ -154,7 +154,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/description.md'), 'permissions': 'all' } - data_manager_org0_key = get_or_create(data, org_0, 'data_manager') + data_manager_org0_key = get_or_create(data, org_0, 'dataset') #################################################### From e45e70fbfdfb48f87f660557f722c802abfae4ae Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 2 Jul 2019 17:49:49 +0200 Subject: [PATCH 132/457] Improve hlf files loading to be compatible to path change in substrabac conf. --- docker/start.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker/start.py b/docker/start.py index a6f9d1ada..af33cf5f8 100644 --- a/docker/start.py +++ b/docker/start.py @@ -111,9 +111,6 @@ def generate_docker_compose_file(conf, launch_settings): for org in conf: org_name = org['name'] - peer = org['peer']['name'] - tls_peer_dir = f'{SUBSTRA_FOLDER}/data/orgs/{org_name}/tls/{peer}' - org_name_stripped = org_name.replace('-', '') port = BACKEND_PORT[org_name_stripped] @@ -156,10 +153,13 @@ def generate_docker_compose_file(conf, launch_settings): f'{SUBSTRA_FOLDER}/conf/{org_name}:{SUBSTRA_FOLDER}/conf/{org_name}:ro', # HLF files - f'{tls_peer_dir}:{tls_peer_dir}:ro', f'{org["core_peer_mspconfigpath"]}:{org["core_peer_mspconfigpath"]}:ro', ] + # HLF files + for tls_key in ['tlsCACerts', 'clientCert', 'clientKey']: + hlf_volumes.append(f'{org["peer"][tls_key]}:{org["peer"][tls_key]}:ro') + backend = { 'container_name': f'{org_name_stripped}.substrabac', 'image': 'substra/substrabac', From 1e333eecbe71531634bf8162810396dc6cdb2e2a Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 25 Jun 2019 16:33:31 +0200 Subject: [PATCH 133/457] add list data samples method --- substrabac/substrapp/views/datasample.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index e2aba1c43..a24b55abd 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -26,13 +26,14 @@ from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import find_primary_key_error, LedgerException, ValidationException, \ get_success_create_code -from substrapp.ledger_utils import LedgerError, LedgerTimeout +from substrapp.ledger_utils import query_ledger, LedgerError, LedgerTimeout logger = logging.getLogger('django.request') class DataSampleViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, + mixins.ListModelMixin, GenericViewSet): queryset = DataSample.objects.all() serializer_class = DataSampleSerializer @@ -211,6 +212,16 @@ def create(self, request, *args, **kwargs): headers = self.get_success_headers(data) return Response(data, status=st, headers=headers) + def list(self, request, *args, **kwargs): + try: + data = query_ledger(fcn='queryDataSamples', args=[]) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + + data = data if data else [] + + return Response(data, status=status.HTTP_200_OK) + def validate_bulk_update(self, data): try: data_manager_keys = data.getlist('data_manager_keys') From f81c88692bf37b51814a5ab167f588c42c9d9aae Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 25 Jun 2019 17:16:35 +0200 Subject: [PATCH 134/457] add tests --- .../substrapp/tests/views/tests_views_datasample.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 43ba2e1ea..bd5201c2e 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -253,3 +253,16 @@ def test_data_sample_compute_dryrun(self): with mock.patch.object(DataManager.objects, 'get') as mdatamanager: mdatamanager.return_value = FakeDataManager(opener_path) data_sample_compute_dryrun(data_files, data_manager_keys) + + def test_datasamples_list(self): + url = reverse('substrapp:data_sample-list') + with mock.patch('substrapp.views.datasample.query_ledger') as mquery_ledger: + mquery_ledger.side_effect = [None, ['DataSampleA', 'DataSampleB']] + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, []) + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, ['DataSampleA', 'DataSampleB']) From 8d10474a01394f804b75482a4f7eb93321e05953 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 5 Jul 2019 11:09:29 +0200 Subject: [PATCH 135/457] Handle new event structure. --- substrabac/events/apps.py | 53 ++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 4cc85a108..1b9dc60e7 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -53,38 +53,46 @@ def get_block_payload(block): return payload -def log_tuple_status(block, tuple_type, key, event_type): +def log_tuple_status(status, tuple_type, key, event_type): + print(f'[ChaincodeEvent] Received {tuple_type} "{event_type}" (key: "{key}") with status: {status}') + +def on_tuples_updated(block): try: meta = block['metadata']['metadata'][-1] if isinstance(meta, list): meta = int(meta.pop()) status = TxValidationCode.Name(meta) except Exception: - print(f'[ChaincodeEvent] Received {tuple_type} "{event_type}" (key: "{key}")') - else: - print(f'[ChaincodeEvent] Received {tuple_type} "{event_type}" (key: "{key}") with status: {status}') - + status = None -def on_tuple_created(block): payload = get_block_payload(block) - tuple_type = get_tuple_type(payload) - log_tuple_status(block, tuple_type, payload['key'], 'created') + for tuple_type, values in payload.items(): + for key, _tuples in values.items(): + if key == 'created': + for _tuple in _tuples: + on_tuple_created(status, _tuple, tuple_type) + if key == 'ready': + for _tuple in _tuples: + on_tuple_ready(status, _tuple, tuple_type) -def on_tuple_ready(block): - payload = get_block_payload(block) - tuple_type = get_tuple_type(payload) - log_tuple_status(block, tuple_type, payload['key'], 'ready') + +def on_tuple_created(status, _tuple, tuple_type): + log_tuple_status(status, tuple_type, _tuple['key'], 'created') + + +def on_tuple_ready(status, _tuple, tuple_type): + log_tuple_status(status, tuple_type, _tuple['key'], 'ready') worker_queue = f"{LEDGER['name']}.worker" data_owner = get_hash(LEDGER['signcert']) - if data_owner == payload['dataset']['worker'] and tuple_type is not None: - tkey = payload['key'] + if data_owner == _tuple['dataset']['worker'] and tuple_type is not None: + tkey = _tuple['key'] if AsyncResult(tkey).state == 'PENDING': prepare_tuple.apply_async( - (payload, tuple_type), + (_tuple, tuple_type), task_id=tkey, queue=worker_queue ) @@ -138,19 +146,8 @@ def wait(): stream = channel_event_hub.connect(filtered=False) channel_event_hub.registerChaincodeEvent(chaincode_name, - 'traintuple-ready', - onEvent=on_tuple_ready) - channel_event_hub.registerChaincodeEvent(chaincode_name, - 'testtuple-ready', - onEvent=on_tuple_ready) - - channel_event_hub.registerChaincodeEvent(chaincode_name, - 'traintuple-created', - onEvent=on_tuple_created) - channel_event_hub.registerChaincodeEvent(chaincode_name, - 'testtuple-created', - onEvent=on_tuple_created) - + 'tuples-updated', + onEvent=on_tuples_updated) loop.run_until_complete(stream) From 5f323c755b3cb441e2727a3fb87bde677aa01bc1 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 5 Jul 2019 11:57:33 +0200 Subject: [PATCH 136/457] Fix asset creation which is not deleted in case of failure. --- substrabac/substrapp/views/algo.py | 4 ++++ substrabac/substrapp/views/datamanager.py | 4 ++++ substrabac/substrapp/views/datasample.py | 4 ++++ substrabac/substrapp/views/objective.py | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 12deefc5b..b361644d1 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -55,7 +55,11 @@ def commit(self, serializer, request): data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) except LedgerError as e: + instance.delete() raise LedgerException(str(e.msg), e.status) + except Exception: + instance.delete() + raise d = dict(serializer.data) d.update(data) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 0d3f4e6e3..c36b3e0bb 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -79,7 +79,11 @@ def commit(self, serializer, request): data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) except LedgerError as e: + instance.delete() raise LedgerException(str(e.msg), e.status) + except Exception: + instance.delete() + raise d = dict(serializer.data) d.update(data) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index e2aba1c43..de17652d5 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -72,7 +72,11 @@ def commit(serializer, ledger_data): data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) except LedgerError as e: + instance.delete() raise LedgerException(str(e.msg), e.status) + except Exception: + instance.delete() + raise st = get_success_create_code() diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 377a95052..61ba6c80a 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -101,7 +101,11 @@ def commit(self, serializer, request): data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) except LedgerError as e: + instance.delete() raise LedgerException(str(e.msg), e.status) + except Exception: + instance.delete() + raise d = dict(serializer.data) d.update(data) From 419ee001018f014182c50bc138ff1b4871917635 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 5 Jul 2019 13:32:46 +0200 Subject: [PATCH 137/457] Verify that folder exists. --- substrabac/substrapp/signals/algo/post_delete.py | 3 ++- substrabac/substrapp/signals/datamanager/post_delete.py | 3 ++- substrabac/substrapp/signals/datasample/post_delete.py | 3 ++- substrabac/substrapp/signals/model/post_delete.py | 3 ++- substrabac/substrapp/signals/objective/post_delete.py | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/signals/algo/post_delete.py b/substrabac/substrapp/signals/algo/post_delete.py index 274af3e72..75411107e 100644 --- a/substrabac/substrapp/signals/algo/post_delete.py +++ b/substrabac/substrapp/signals/algo/post_delete.py @@ -8,4 +8,5 @@ def algo_post_delete(sender, instance, **kwargs): instance.description.delete(False) directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'algos/{0}'.format(instance.pk)) - shutil.rmtree(directory) + if path.exists(directory): + shutil.rmtree(directory) diff --git a/substrabac/substrapp/signals/datamanager/post_delete.py b/substrabac/substrapp/signals/datamanager/post_delete.py index e6642f3f1..ede34bfa4 100644 --- a/substrabac/substrapp/signals/datamanager/post_delete.py +++ b/substrabac/substrapp/signals/datamanager/post_delete.py @@ -8,4 +8,5 @@ def datamanager_post_delete(sender, instance, **kwargs): instance.description.delete(False) directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'datamanagers/{0}'.format(instance.pk)) - shutil.rmtree(directory) + if path.exists(directory): + shutil.rmtree(directory) diff --git a/substrabac/substrapp/signals/datasample/post_delete.py b/substrabac/substrapp/signals/datasample/post_delete.py index 75cff65db..39a9ba6f1 100644 --- a/substrabac/substrapp/signals/datasample/post_delete.py +++ b/substrabac/substrapp/signals/datasample/post_delete.py @@ -7,4 +7,5 @@ def data_sample_post_delete(sender, instance, **kwargs): # remove created folder directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'datasamples', instance.pk) - rmtree(directory) + if path.exists(directory): + rmtree(directory) diff --git a/substrabac/substrapp/signals/model/post_delete.py b/substrabac/substrapp/signals/model/post_delete.py index d26eeb1c1..003c0100a 100644 --- a/substrabac/substrapp/signals/model/post_delete.py +++ b/substrabac/substrapp/signals/model/post_delete.py @@ -7,4 +7,5 @@ def model_post_delete(sender, instance, **kwargs): instance.file.delete(False) directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'models/{0}'.format(instance.pk)) - shutil.rmtree(directory) + if path.exists(directory): + shutil.rmtree(directory) diff --git a/substrabac/substrapp/signals/objective/post_delete.py b/substrabac/substrapp/signals/objective/post_delete.py index 5b1f71ced..fac5e04b4 100644 --- a/substrabac/substrapp/signals/objective/post_delete.py +++ b/substrabac/substrapp/signals/objective/post_delete.py @@ -8,4 +8,5 @@ def objective_post_delete(sender, instance, **kwargs): instance.metrics.delete(False) directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'objectives/{0}'.format(instance.pk)) - shutil.rmtree(directory) + if path.exists(directory): + shutil.rmtree(directory) From 197725c761e9d172a6927eb8966d2d40ef2aea5e Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 5 Jul 2019 13:35:04 +0200 Subject: [PATCH 138/457] Loop over instances --- substrabac/substrapp/views/datasample.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index de17652d5..056795fe9 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -72,10 +72,12 @@ def commit(serializer, ledger_data): data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) except LedgerError as e: - instance.delete() + for instance in instances: + instance.delete() raise LedgerException(str(e.msg), e.status) except Exception: - instance.delete() + for instance in instances: + instance.delete() raise st = get_success_create_code() From 43658465456de37502642a468e395ab43aa2c280 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 5 Jul 2019 14:31:10 +0200 Subject: [PATCH 139/457] Improve events. --- substrabac/events/apps.py | 45 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 1b9dc60e7..1eddb303c 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -24,18 +24,6 @@ LEDGER = getattr(settings, 'LEDGER', None) -def get_tuple_type(payload): - - tuple_type = None - - if 'inModels' in payload: - tuple_type = 'traintuple' - elif 'model' in payload: - tuple_type = 'testtuple' - - return tuple_type - - @contextlib.contextmanager def get_event_loop(): loop = asyncio.new_event_loop() @@ -53,37 +41,30 @@ def get_block_payload(block): return payload -def log_tuple_status(status, tuple_type, key, event_type): - print(f'[ChaincodeEvent] Received {tuple_type} "{event_type}" (key: "{key}") with status: {status}') - - -def on_tuples_updated(block): +def on_tuples(block): try: meta = block['metadata']['metadata'][-1] if isinstance(meta, list): meta = int(meta.pop()) - status = TxValidationCode.Name(meta) + tx_validation_code = TxValidationCode.Name(meta) except Exception: - status = None + tx_validation_code = None payload = get_block_payload(block) - for tuple_type, values in payload.items(): - for key, _tuples in values.items(): - if key == 'created': - for _tuple in _tuples: - on_tuple_created(status, _tuple, tuple_type) - if key == 'ready': - for _tuple in _tuples: - on_tuple_ready(status, _tuple, tuple_type) + for tuple_type, _tuples in payload.items(): + for _tuple in _tuples: + tuple_key = _tuple['key'] + tuple_status = _tuple['status'] + print(f'[ChaincodeEvent] Received {tuple_type} "{tuple_status}" ' + f'(key: "{tuple_key}") with tx status: {tx_validation_code}') -def on_tuple_created(status, _tuple, tuple_type): - log_tuple_status(status, tuple_type, _tuple['key'], 'created') + if tuple_status == 'todo': + launch_tuple(_tuple, tuple_type) -def on_tuple_ready(status, _tuple, tuple_type): - log_tuple_status(status, tuple_type, _tuple['key'], 'ready') +def launch_tuple(_tuple, tuple_type): worker_queue = f"{LEDGER['name']}.worker" data_owner = get_hash(LEDGER['signcert']) @@ -147,7 +128,7 @@ def wait(): channel_event_hub.registerChaincodeEvent(chaincode_name, 'tuples-updated', - onEvent=on_tuples_updated) + onEvent=on_tuples) loop.run_until_complete(stream) From 3c7c76233d059c591435004b8ee78f38d98cfe0c Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 5 Jul 2019 14:34:38 +0200 Subject: [PATCH 140/457] Add logging. --- substrabac/events/apps.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 1eddb303c..c982f2a5f 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -21,6 +21,8 @@ from celery.result import AsyncResult +import logging + LEDGER = getattr(settings, 'LEDGER', None) @@ -57,8 +59,8 @@ def on_tuples(block): tuple_key = _tuple['key'] tuple_status = _tuple['status'] - print(f'[ChaincodeEvent] Received {tuple_type} "{tuple_status}" ' - f'(key: "{tuple_key}") with tx status: {tx_validation_code}') + logging.info(f'[ChaincodeEvent] Received {tuple_type} "{tuple_status}" ' + f'(key: "{tuple_key}") with tx status: {tx_validation_code}') if tuple_status == 'todo': launch_tuple(_tuple, tuple_type) From e45df1ff392526a940e2e6f79c21e5aaec8d00fb Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 5 Jul 2019 17:28:58 +0200 Subject: [PATCH 141/457] ledger utils fix exception handling --- substrabac/substrapp/ledger_utils.py | 41 ++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 9dcff5350..44fd20aea 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -5,6 +5,9 @@ from django.conf import settings from rest_framework import status +from hfc.protos.peer.proposal_response_pb2 import ProposalResponse + + LEDGER = getattr(settings, 'LEDGER', None) @@ -87,6 +90,25 @@ def get_hfc(): loop.close() +def _exception_get_proposal_responses(e): + if ( + e.args and + isinstance(e.args[0], list) and + e.args[0] and + all([isinstance(r, ProposalResponse) for r in e.args[0]]) + ): + return e.args[0] + else: + return None + + +def _proposal_responses_find_error(proposal_responses): + for p in proposal_responses: + if p.response.status != 200: + return p + return None + + def call_ledger(call_type, fcn, args=None, kwargs=None): with get_hfc() as (loop, client): @@ -128,17 +150,24 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): except TimeoutError as e: raise LedgerTimeout(str(e)) except Exception as e: - if hasattr(e, 'details') and 'access denied' in e.details(): - raise LedgerForbidden(f'Access denied for {(fcn, args)}') - - logging.exception(e) - raise LedgerError(str(e)) + # XXX When the chaincode responds with a status code different than + # 200 a standard python Exception is raised with all the + # responses in protobuf format as first argument. To handle + # properly theses exceptions, check raised exception and parse + # protobuf responses. This should be handled properly in the + # fabric-sdk-py. + proposal_responses = _exception_get_proposal_responses(e) + + if not proposal_responses: + logging.exception(e) + raise LedgerError(str(e)) + pb_error = _proposal_responses_find_error(proposal_responses) + response = pb_error.response.message # Deserialize the stringified json try: response = json.loads(response) except json.decoder.JSONDecodeError: - if response == 'MVCC_READ_CONFLICT': raise LedgerMVCCError(response) elif 'cannot change status' in response: From a0f703f28737cb3a9ce42e3840ba277136090bf3 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 8 Jul 2019 08:39:22 +0200 Subject: [PATCH 142/457] Update events processing. --- substrabac/events/apps.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index c982f2a5f..eb4dd28fa 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -55,15 +55,16 @@ def on_tuples(block): payload = get_block_payload(block) for tuple_type, _tuples in payload.items(): - for _tuple in _tuples: - tuple_key = _tuple['key'] - tuple_status = _tuple['status'] + if _tuples: + for _tuple in _tuples: + tuple_key = _tuple['key'] + tuple_status = _tuple['status'] - logging.info(f'[ChaincodeEvent] Received {tuple_type} "{tuple_status}" ' - f'(key: "{tuple_key}") with tx status: {tx_validation_code}') + logging.info(f'[ChaincodeEvent] Received {tuple_type} "{tuple_status}" ' + f'(key: "{tuple_key}") with tx status: {tx_validation_code}') - if tuple_status == 'todo': - launch_tuple(_tuple, tuple_type) + if tuple_status == 'todo': + launch_tuple(_tuple, tuple_type) def launch_tuple(_tuple, tuple_type): From 1b693b165af3f3cc13ed0cdcfdba851535e7f517 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 8 Jul 2019 09:36:54 +0200 Subject: [PATCH 143/457] update after review --- substrabac/substrapp/ledger_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 44fd20aea..a1c203646 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -94,7 +94,6 @@ def _exception_get_proposal_responses(e): if ( e.args and isinstance(e.args[0], list) and - e.args[0] and all([isinstance(r, ProposalResponse) for r in e.args[0]]) ): return e.args[0] From 7b1f2d5e4f0f03b6213af19e8afad3f4b084cee3 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 2 Jul 2019 13:49:37 +0200 Subject: [PATCH 144/457] Query ledger: fail faster When querying assets the ledger should always return a list in case of success. If the ledger does not return a list the server should fail and not hide the failure. --- substrabac/substrapp/views/algo.py | 2 -- substrabac/substrapp/views/datamanager.py | 2 -- substrabac/substrapp/views/model.py | 2 -- substrabac/substrapp/views/objective.py | 2 -- substrabac/substrapp/views/testtuple.py | 2 -- substrabac/substrapp/views/traintuple.py | 4 ---- 6 files changed, 14 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 12deefc5b..f5223901c 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -163,8 +163,6 @@ def list(self, request, *args, **kwargs): except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - data = data if data else [] - algos_list = [data] # parse filters diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 0d3f4e6e3..6f135cbc9 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -226,8 +226,6 @@ def list(self, request, *args, **kwargs): except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - data = data if data else [] - data_managers_list = [data] # parse filters diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index d6d67630a..5ed0f0c97 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -101,8 +101,6 @@ def list(self, request, *args, **kwargs): except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - data = data if data else [] - models_list = [data] query_params = request.query_params.get('search', None) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 377a95052..cd3db8aa3 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -226,8 +226,6 @@ def list(self, request, *args, **kwargs): except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - data = data if data else [] - objectives_list = [data] query_params = request.query_params.get('search', None) diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index f29039af4..4f06a7929 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -68,8 +68,6 @@ def list(self, request, *args, **kwargs): data = query_ledger(fcn='queryTesttuples', args=[]) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - - data = data if data else [] return Response(data, status=status.HTTP_200_OK) def _retrieve(self, pk): diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 6317d5f4a..05ab08bc2 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -69,14 +69,10 @@ def create(self, request, *args, **kwargs): return Response(data, status=st, headers=headers) def list(self, request, *args, **kwargs): - try: data = query_ledger(fcn='queryTraintuples', args=[]) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - - data = data if data else [] - return Response(data, status=status.HTTP_200_OK) def _retrieve(self, pk): From eef35fc9981bc3b096516c3ada22f70b2aefd831 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 2 Jul 2019 13:55:38 +0200 Subject: [PATCH 145/457] tests: update mock of ledger --- substrabac/substrapp/tests/views/tests_views_algo.py | 2 +- substrabac/substrapp/tests/views/tests_views_datamanager.py | 2 +- substrabac/substrapp/tests/views/tests_views_model.py | 2 +- substrabac/substrapp/tests/views/tests_views_objective.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index bef8eb799..68c3162be 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -53,7 +53,7 @@ def tearDown(self): def test_algo_list_empty(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [None, ['ISIC']] + mquery_ledger.side_effect = [[], ['ISIC']] response = self.client.get(url, **self.extra) r = response.json() diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index d0746415b..8d585b464 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -50,7 +50,7 @@ def tearDown(self): def test_datamanager_list_empty(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [None, ['ISIC']] + mquery_ledger.side_effect = [[], ['ISIC']] response = self.client.get(url, **self.extra) r = response.json() diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substrabac/substrapp/tests/views/tests_views_model.py index 57196c09e..d53d15d1c 100644 --- a/substrabac/substrapp/tests/views/tests_views_model.py +++ b/substrabac/substrapp/tests/views/tests_views_model.py @@ -48,7 +48,7 @@ def tearDown(self): def test_model_list_empty(self): url = reverse('substrapp:model-list') with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [None, ['ISIC']] + mquery_ledger.side_effect = [[], ['ISIC']] response = self.client.get(url, **self.extra) r = response.json() diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index e595fdf2f..ffd2c3b86 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -63,7 +63,7 @@ def tearDown(self): def test_objective_list_empty(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [None, ['ISIC']] + mquery_ledger.side_effect = [[], ['ISIC']] response = self.client.get(url, **self.extra) r = response.json() From e101de0098b0bb68ff2c28168f03951f4bb9f870 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 8 Jul 2019 11:50:25 +0200 Subject: [PATCH 146/457] comment fixes after review --- substrabac/substrapp/ledger_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index a1c203646..a0ae31e40 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -152,7 +152,7 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): # XXX When the chaincode responds with a status code different than # 200 a standard python Exception is raised with all the # responses in protobuf format as first argument. To handle - # properly theses exceptions, check raised exception and parse + # properly these exceptions, check raised exception and parse # protobuf responses. This should be handled properly in the # fabric-sdk-py. proposal_responses = _exception_get_proposal_responses(e) From 2932c775cb823aba528796ed60285b80a70f5ad1 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 10 Jul 2019 11:32:22 +0200 Subject: [PATCH 147/457] fix after review --- substrabac/substrapp/ledger_utils.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index a0ae31e40..a25f356a8 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -149,6 +149,9 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): except TimeoutError as e: raise LedgerTimeout(str(e)) except Exception as e: + if hasattr(e, 'details') and 'access denied' in e.details(): + raise LedgerForbidden(f'Access denied for {(fcn, args)}') + # XXX When the chaincode responds with a status code different than # 200 a standard python Exception is raised with all the # responses in protobuf format as first argument. To handle @@ -160,7 +163,12 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): if not proposal_responses: logging.exception(e) raise LedgerError(str(e)) + pb_error = _proposal_responses_find_error(proposal_responses) + if not pb_error: + logging.exception(e) + raise LedgerError(str(e)) + response = pb_error.response.message # Deserialize the stringified json From dfb0f995cfb0aecbae40463e87d1d185bce50e9e Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 10 Jul 2019 11:39:18 +0200 Subject: [PATCH 148/457] Fix objective dryrun removal before raising Exception. --- substrabac/substrapp/views/objective.py | 1 + 1 file changed, 1 insertion(+) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 3a173be05..548454b0c 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -280,6 +280,7 @@ def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): os.remove(metrics_path) if not test_data_manager_key: + remove_subtuple_materials(subtuple_directory) raise Exception('Cannot do a objective dryrun without a data manager key.') datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') From b964b3e84c7672352d88f996ec7af1b10ca1702d Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 10 Jul 2019 16:28:22 +0200 Subject: [PATCH 149/457] Correctly transform a string value from post request to a boolean --- populate.py | 6 +++--- substrabac/substrabac/settings/deps/ledger.py | 3 +-- substrabac/substrapp/views/datasample.py | 4 +++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/populate.py b/populate.py index 6c49b7033..2e3449b77 100644 --- a/populate.py +++ b/populate.py @@ -56,7 +56,7 @@ def get_or_create(data, profile, asset, dryrun=False, register=False): def update_datamanager(data_manager_key, data, profile): client.set_config(profile) try: - r = client.update('dataset', data_manager_key, data) + r = client.update('data_manager', data_manager_key, data) except substra.exceptions.AlreadyExists as e: r = e.response.json() @@ -110,7 +110,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/chunantes/datamanagers/datamanager0/description.md'), 'permissions': 'all', } - data_manager_org1_key = get_or_create(data, org_1, 'dataset', dryrun=True) + data_manager_org1_key = get_or_create(data, org_1, 'data_manager', dryrun=True) #################################################### @@ -154,7 +154,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/description.md'), 'permissions': 'all' } - data_manager_org0_key = get_or_create(data, org_0, 'dataset') + data_manager_org0_key = get_or_create(data, org_0, 'data_manager') #################################################### diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index d3fabc193..723b7f968 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -39,7 +39,7 @@ def get_hfc_client(): asyncio.set_event_loop(loop) client = Client() - client.new_channel(LEDGER['channel_name']) + channel = client.new_channel(LEDGER['channel_name']) # Add peer from substrabac ledger config file peer = Peer(name=LEDGER['peer']['name']) @@ -53,7 +53,6 @@ def get_hfc_client(): client._peers[LEDGER['peer']['name']] = peer # Discover orderers and peers from channel discovery - channel = client.get_channel(LEDGER['channel_name']) results = loop.run_until_complete( channel._discovery( LEDGER['requestor'], diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 71467ce9a..c27ba2e1e 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -12,6 +12,7 @@ from rest_framework import status, mixins from rest_framework.decorators import action from rest_framework.exceptions import ValidationError +from rest_framework.fields import BooleanField from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from rest_framework.reverse import reverse @@ -124,7 +125,8 @@ def compute_data(self, request): if path is not None: paths = [path] - recursive_dir = str(request.POST.get('multiple', 'false')).lower() == 'true' + recursive_dir_field = BooleanField() + recursive_dir = recursive_dir_field.to_internal_value(request.data.get('multiple', 'false')) if recursive_dir: # list all directories from parent directories parent_paths = paths From 6e2f4906f70a25ac268a551499b1ec2941333cf7 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 10 Jul 2019 16:30:53 +0200 Subject: [PATCH 150/457] remove files which should not be in this pr --- populate.py | 6 +++--- substrabac/substrabac/settings/deps/ledger.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/populate.py b/populate.py index 2e3449b77..6c49b7033 100644 --- a/populate.py +++ b/populate.py @@ -56,7 +56,7 @@ def get_or_create(data, profile, asset, dryrun=False, register=False): def update_datamanager(data_manager_key, data, profile): client.set_config(profile) try: - r = client.update('data_manager', data_manager_key, data) + r = client.update('dataset', data_manager_key, data) except substra.exceptions.AlreadyExists as e: r = e.response.json() @@ -110,7 +110,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/chunantes/datamanagers/datamanager0/description.md'), 'permissions': 'all', } - data_manager_org1_key = get_or_create(data, org_1, 'data_manager', dryrun=True) + data_manager_org1_key = get_or_create(data, org_1, 'dataset', dryrun=True) #################################################### @@ -154,7 +154,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/description.md'), 'permissions': 'all' } - data_manager_org0_key = get_or_create(data, org_0, 'data_manager') + data_manager_org0_key = get_or_create(data, org_0, 'dataset') #################################################### diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 723b7f968..d3fabc193 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -39,7 +39,7 @@ def get_hfc_client(): asyncio.set_event_loop(loop) client = Client() - channel = client.new_channel(LEDGER['channel_name']) + client.new_channel(LEDGER['channel_name']) # Add peer from substrabac ledger config file peer = Peer(name=LEDGER['peer']['name']) @@ -53,6 +53,7 @@ def get_hfc_client(): client._peers[LEDGER['peer']['name']] = peer # Discover orderers and peers from channel discovery + channel = client.get_channel(LEDGER['channel_name']) results = loop.run_until_complete( channel._discovery( LEDGER['requestor'], From beee498e6efd3d0b84f0b719333cee0c03ef7e62 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 10 Jul 2019 16:29:26 +0200 Subject: [PATCH 151/457] fix after review --- substrabac/substrapp/ledger_utils.py | 41 ++-------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index a25f356a8..b798e8b3a 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -1,12 +1,9 @@ import json -import logging import contextlib from django.conf import settings from rest_framework import status -from hfc.protos.peer.proposal_response_pb2 import ProposalResponse - LEDGER = getattr(settings, 'LEDGER', None) @@ -90,24 +87,6 @@ def get_hfc(): loop.close() -def _exception_get_proposal_responses(e): - if ( - e.args and - isinstance(e.args[0], list) and - all([isinstance(r, ProposalResponse) for r in e.args[0]]) - ): - return e.args[0] - else: - return None - - -def _proposal_responses_find_error(proposal_responses): - for p in proposal_responses: - if p.response.status != 200: - return p - return None - - def call_ledger(call_type, fcn, args=None, kwargs=None): with get_hfc() as (loop, client): @@ -152,25 +131,11 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): if hasattr(e, 'details') and 'access denied' in e.details(): raise LedgerForbidden(f'Access denied for {(fcn, args)}') - # XXX When the chaincode responds with a status code different than - # 200 a standard python Exception is raised with all the - # responses in protobuf format as first argument. To handle - # properly these exceptions, check raised exception and parse - # protobuf responses. This should be handled properly in the - # fabric-sdk-py. - proposal_responses = _exception_get_proposal_responses(e) - - if not proposal_responses: - logging.exception(e) + try: # get first failed response from list of protobuf ProposalResponse + response = [r for r in e.args[0] if r.response.status != 200][0].response.message + except Exception: raise LedgerError(str(e)) - pb_error = _proposal_responses_find_error(proposal_responses) - if not pb_error: - logging.exception(e) - raise LedgerError(str(e)) - - response = pb_error.response.message - # Deserialize the stringified json try: response = json.loads(response) From 34fd1aa747018eb9ace2ab48bd00b89a14adde0c Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 10 Jul 2019 16:32:11 +0200 Subject: [PATCH 152/457] Correctly init channel --- substrabac/substrabac/settings/deps/ledger.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index d3fabc193..723b7f968 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -39,7 +39,7 @@ def get_hfc_client(): asyncio.set_event_loop(loop) client = Client() - client.new_channel(LEDGER['channel_name']) + channel = client.new_channel(LEDGER['channel_name']) # Add peer from substrabac ledger config file peer = Peer(name=LEDGER['peer']['name']) @@ -53,7 +53,6 @@ def get_hfc_client(): client._peers[LEDGER['peer']['name']] = peer # Discover orderers and peers from channel discovery - channel = client.get_channel(LEDGER['channel_name']) results = loop.run_until_complete( channel._discovery( LEDGER['requestor'], From f9b4767dd9a36d7b6fa249fe02cf3c90cb08dd78 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 3 Jul 2019 12:20:23 +0200 Subject: [PATCH 153/457] Fix do no uncompress data samples files twice. --- .../commands/bulkcreatedatasample.py | 4 +- .../substrapp/signals/datasample/pre_save.py | 1 + .../tests/query/tests_query_datasample.py | 17 ++-- substrabac/substrapp/utils.py | 26 +++++- substrabac/substrapp/views/datasample.py | 82 +++++++++++-------- 5 files changed, 87 insertions(+), 43 deletions(-) diff --git a/substrabac/substrapp/management/commands/bulkcreatedatasample.py b/substrabac/substrapp/management/commands/bulkcreatedatasample.py index ff43f6b60..ac159e150 100644 --- a/substrabac/substrapp/management/commands/bulkcreatedatasample.py +++ b/substrabac/substrapp/management/commands/bulkcreatedatasample.py @@ -10,7 +10,7 @@ from substrapp.serializers.datasample import DataSampleSerializer from substrapp.views import DataSampleViewSet -from substrapp.utils import get_dir_hash +from substrapp.utils import get_dir_hash_only from substrapp.views.datasample import LedgerException @@ -49,7 +49,7 @@ def map_data_sample(paths): with open(file_or_path, 'rb') as f: filename = path_leaf(file_or_path) file = ContentFile(f.read(), filename) - pkhash = get_dir_hash(file) + pkhash = get_dir_hash_only(file) check(file_or_path, pkhash, data_sample) diff --git a/substrabac/substrapp/signals/datasample/pre_save.py b/substrabac/substrapp/signals/datasample/pre_save.py index 75ed866ec..e3940ff7d 100644 --- a/substrabac/substrapp/signals/datasample/pre_save.py +++ b/substrabac/substrapp/signals/datasample/pre_save.py @@ -23,6 +23,7 @@ def data_sample_pre_save(sender, instance, **kwargs): directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'datasamples/{0}'.format(instance.pk)) # uncompress file if an archive + # Should not be necessary with get_dir_hash if isinstance(instance.path, File): try: content = instance.path.read() diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substrabac/substrapp/tests/query/tests_query_datasample.py index 2fe4908a3..f74972748 100644 --- a/substrabac/substrapp/tests/query/tests_query_datasample.py +++ b/substrabac/substrapp/tests/query/tests_query_datasample.py @@ -17,7 +17,7 @@ from substrapp.models import DataManager, DataSample from substrapp.serializers import LedgerDataSampleSerializer, DataSampleSerializer -from substrapp.utils import get_hash, get_dir_hash +from substrapp.utils import get_hash, get_dir_hash_only from substrapp.ledger_utils import LedgerError, LedgerTimeout from substrapp.views import DataSampleViewSet @@ -60,7 +60,7 @@ def add_default_data_manager(self): data_opener=self.data_data_opener2) def get_default_datasample_data(self): - expected_hash = get_dir_hash(self.data_file.file) + expected_hash = get_dir_hash_only(self.data_file.file) self.data_file.file.seek(0) data = { 'file': self.data_file, @@ -119,15 +119,15 @@ def test_bulk_add_data_sample_sync_ok(self): with mock.patch('substrapp.serializers.ledger.datasample.util.create_ledger_assets') as mcreate_ledger_assets: self.data_file.seek(0) self.data_file_2.seek(0) - ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': True} + ledger_data = {'pkhash': [get_dir_hash_only(file_mock), get_dir_hash_only(file_mock2)], 'validated': True} mcreate_ledger_assets.return_value = ledger_data response = self.client.post(url, data, format='multipart', **extra) r = response.json() self.assertEqual(len(r), 2) - self.assertEqual(r[0]['pkhash'], get_dir_hash(file_mock)) - self.assertTrue(r[0]['path'].endswith(f'/datasamples/{get_dir_hash(file_mock)}')) + self.assertEqual(r[0]['pkhash'], get_dir_hash_only(file_mock)) + self.assertTrue(r[0]['path'].endswith(f'/datasamples/{get_dir_hash_only(file_mock)}')) self.assertEqual(response.status_code, status.HTTP_201_CREATED) @override_settings(LEDGER_SYNC_ENABLED=False) @@ -265,7 +265,7 @@ def test_add_data_sample_ko_408(self): r = response.json() self.assertEqual( r['message'], - {'pkhash': [get_dir_hash(file_mock)], 'validated': False}) + {'pkhash': [get_dir_hash_only(file_mock)], 'validated': False}) self.assertEqual(response.status_code, status.HTTP_408_REQUEST_TIMEOUT) def test_bulk_add_data_sample_ko_408(self): @@ -296,7 +296,8 @@ def test_bulk_add_data_sample_ko_408(self): mget_validators.return_value = [] self.data_file.seek(0) self.data_tar_file.seek(0) - # ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} + # ledger_data = {'pkhash': [get_dir_hash_only(file_mock), + # get_dir_hash_only(file_mock2)], 'validated': False} mcreate.side_effect = LedgerTimeout('Timeout') response = self.client.post(url, data, format='multipart', **extra) @@ -333,7 +334,7 @@ def test_bulk_add_data_sample_ko_same_pkhash(self): mget_validators.return_value = [] self.data_file.seek(0) self.data_tar_file.seek(0) - ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} + ledger_data = {'pkhash': [get_dir_hash_only(file_mock), get_dir_hash_only(file_mock2)], 'validated': False} mcreate.return_value = ledger_data, status.HTTP_408_REQUEST_TIMEOUT response = self.client.post(url, data, format='multipart', **extra) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 1992b1280..034ccd089 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -4,7 +4,9 @@ import logging import os import tempfile +from os import path from os.path import isfile, isdir +import shutil import requests import tarfile @@ -22,7 +24,7 @@ def __init__(self, msg): super(JsonException, self).__init__() -def get_dir_hash(archive_content): +def get_dir_hash_only(archive_content): with tempfile.TemporaryDirectory() as temp_dir: try: content = archive_content.read() @@ -35,6 +37,28 @@ def get_dir_hash(archive_content): return dirhash(temp_dir, 'sha256') +def get_dir_hash(archive_content): + + try: + content = archive_content.read() + archive_content.seek(0) + except Exception as e: + logging.error(e) + raise e + + datasamples_file_hash = compute_hash(content) + datasamples_path = path.join(getattr(settings, 'MEDIA_ROOT'), + 'datasamples/{0}'.format(datasamples_file_hash)) + try: + uncompress_content(content, datasamples_path) + except Exception as e: + shutil.rmtree(datasamples_path, ignore_errors=True) + logging.error(e) + raise e + else: + return dirhash(datasamples_path, 'sha256'), datasamples_path + + def get_hash(file, key=None): if file is None: return '' diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index c27ba2e1e..1a7d84bc2 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -5,6 +5,7 @@ import os import ntpath import uuid +import shutil from checksumdir import dirhash from django.conf import settings @@ -32,6 +33,18 @@ logger = logging.getLogger('django.request') +class DataSamplesPathsFromFilesRemoval(object): + def __enter__(self): + global datasamples_paths_from_files + datasamples_paths_from_files = [] + + def __exit__(self, exc_type, exc_val, traceback): + global datasamples_paths_from_files + # Remove gpath as they are hard linked with pre save signals + for gpath in datasamples_paths_from_files: + shutil.rmtree(gpath, ignore_errors=True) + + class DataSampleViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, @@ -93,27 +106,31 @@ def commit(serializer, ledger_data): return serializer.data, st def compute_data(self, request): + data = {} # files can be uploaded inside the HTTP request or can already be # available on local disk if len(request.FILES) > 0: + pkhash_map = {} + global datasamples_paths_from_files for k, file in request.FILES.items(): - pkhash = get_dir_hash(file) + # Get dir hash uncompress the file into a directory + pkhash, datasamples_path_from_file = get_dir_hash(file) # can raise + datasamples_paths_from_files.append(datasamples_path_from_file) + # check pkhash does not belong to the list try: - existing = data[pkhash] + data[pkhash] except KeyError: - pass + pkhash_map[pkhash] = file else: - raise Exception( - f'Your data sample archives contain same files leading to same pkhash, ' - f'please review the content of your achives. ' - f'Archives {file} and {existing["file"]} are the same') - + raise Exception(f'Your data sample archives contain same files leading to same pkhash, ' + f'please review the content of your achives. ' + f'Archives {file} and {pkhash_map[pkhash]} are the same') data[pkhash] = { 'pkhash': pkhash, - 'file': file + 'path': datasamples_path_from_file } else: # files must be available on local filesystem @@ -146,7 +163,7 @@ def compute_data(self, request): f'is not a directory or is not an absolute path: {path}') pkhash = dirhash(path, 'sha256') try: - existing = data[pkhash] + data[pkhash] except KeyError: pass else: @@ -193,32 +210,33 @@ def handle_dryrun(self, data, data_manager_keys): def _create(self, request, data_manager_keys, test_only, dryrun): - if not data_manager_keys: - raise Exception("missing or empty field 'data_manager_keys'") + with DataSamplesPathsFromFilesRemoval(): + if not data_manager_keys: + raise Exception("missing or empty field 'data_manager_keys'") - self.check_datamanagers(data_manager_keys) # can raise + self.check_datamanagers(data_manager_keys) # can raise - computed_data = self.compute_data(request) + computed_data = self.compute_data(request) - serializer = self.get_serializer(data=computed_data, many=True) + serializer = self.get_serializer(data=computed_data, many=True) - try: - serializer.is_valid(raise_exception=True) - except Exception as e: - pkhashes = [x['pkhash'] for x in computed_data] - st = status.HTTP_400_BAD_REQUEST - if find_primary_key_error(e): - st = status.HTTP_409_CONFLICT - raise ValidationException(e.args, pkhashes, st) - else: - if dryrun: - return self.handle_dryrun(computed_data, data_manager_keys) - - # create on ledger + db - ledger_data = {'test_only': test_only, - 'data_manager_keys': data_manager_keys} - data, st = self.commit(serializer, ledger_data) - return data, st + try: + serializer.is_valid(raise_exception=True) + except Exception as e: + pkhashes = [x['pkhash'] for x in computed_data] + st = status.HTTP_400_BAD_REQUEST + if find_primary_key_error(e): + st = status.HTTP_409_CONFLICT + raise ValidationException(e.args, pkhashes, st) + else: + if dryrun: + return self.handle_dryrun(computed_data, data_manager_keys) + + # create on ledger + db + ledger_data = {'test_only': test_only, + 'data_manager_keys': data_manager_keys} + data, st = self.commit(serializer, ledger_data) + return data, st def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) From fa67a67e86e4e9f96eb386f0bbfed76c99d9f6f1 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 3 Jul 2019 15:31:25 +0200 Subject: [PATCH 154/457] Improve context manager for datasample. --- .../commands/bulkcreatedatasample.py | 4 +-- .../tests/query/tests_query_datasample.py | 18 ++++++------- substrabac/substrapp/utils.py | 12 ++++----- substrabac/substrapp/views/datasample.py | 25 +++++++++++-------- 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/substrabac/substrapp/management/commands/bulkcreatedatasample.py b/substrabac/substrapp/management/commands/bulkcreatedatasample.py index ac159e150..ff43f6b60 100644 --- a/substrabac/substrapp/management/commands/bulkcreatedatasample.py +++ b/substrabac/substrapp/management/commands/bulkcreatedatasample.py @@ -10,7 +10,7 @@ from substrapp.serializers.datasample import DataSampleSerializer from substrapp.views import DataSampleViewSet -from substrapp.utils import get_dir_hash_only +from substrapp.utils import get_dir_hash from substrapp.views.datasample import LedgerException @@ -49,7 +49,7 @@ def map_data_sample(paths): with open(file_or_path, 'rb') as f: filename = path_leaf(file_or_path) file = ContentFile(f.read(), filename) - pkhash = get_dir_hash_only(file) + pkhash = get_dir_hash(file) check(file_or_path, pkhash, data_sample) diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substrabac/substrapp/tests/query/tests_query_datasample.py index f74972748..b60f02621 100644 --- a/substrabac/substrapp/tests/query/tests_query_datasample.py +++ b/substrabac/substrapp/tests/query/tests_query_datasample.py @@ -17,7 +17,7 @@ from substrapp.models import DataManager, DataSample from substrapp.serializers import LedgerDataSampleSerializer, DataSampleSerializer -from substrapp.utils import get_hash, get_dir_hash_only +from substrapp.utils import get_hash, get_dir_hash from substrapp.ledger_utils import LedgerError, LedgerTimeout from substrapp.views import DataSampleViewSet @@ -60,7 +60,7 @@ def add_default_data_manager(self): data_opener=self.data_data_opener2) def get_default_datasample_data(self): - expected_hash = get_dir_hash_only(self.data_file.file) + expected_hash = get_dir_hash(self.data_file.file) self.data_file.file.seek(0) data = { 'file': self.data_file, @@ -119,15 +119,15 @@ def test_bulk_add_data_sample_sync_ok(self): with mock.patch('substrapp.serializers.ledger.datasample.util.create_ledger_assets') as mcreate_ledger_assets: self.data_file.seek(0) self.data_file_2.seek(0) - ledger_data = {'pkhash': [get_dir_hash_only(file_mock), get_dir_hash_only(file_mock2)], 'validated': True} + ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': True} mcreate_ledger_assets.return_value = ledger_data response = self.client.post(url, data, format='multipart', **extra) r = response.json() self.assertEqual(len(r), 2) - self.assertEqual(r[0]['pkhash'], get_dir_hash_only(file_mock)) - self.assertTrue(r[0]['path'].endswith(f'/datasamples/{get_dir_hash_only(file_mock)}')) + self.assertEqual(r[0]['pkhash'], get_dir_hash(file_mock)) + self.assertTrue(r[0]['path'].endswith(f'/datasamples/{get_dir_hash(file_mock)}')) self.assertEqual(response.status_code, status.HTTP_201_CREATED) @override_settings(LEDGER_SYNC_ENABLED=False) @@ -265,7 +265,7 @@ def test_add_data_sample_ko_408(self): r = response.json() self.assertEqual( r['message'], - {'pkhash': [get_dir_hash_only(file_mock)], 'validated': False}) + {'pkhash': [get_dir_hash(file_mock)], 'validated': False}) self.assertEqual(response.status_code, status.HTTP_408_REQUEST_TIMEOUT) def test_bulk_add_data_sample_ko_408(self): @@ -296,8 +296,8 @@ def test_bulk_add_data_sample_ko_408(self): mget_validators.return_value = [] self.data_file.seek(0) self.data_tar_file.seek(0) - # ledger_data = {'pkhash': [get_dir_hash_only(file_mock), - # get_dir_hash_only(file_mock2)], 'validated': False} + # ledger_data = {'pkhash': [get_dir_hash(file_mock), + # get_dir_hash(file_mock2)], 'validated': False} mcreate.side_effect = LedgerTimeout('Timeout') response = self.client.post(url, data, format='multipart', **extra) @@ -334,7 +334,7 @@ def test_bulk_add_data_sample_ko_same_pkhash(self): mget_validators.return_value = [] self.data_file.seek(0) self.data_tar_file.seek(0) - ledger_data = {'pkhash': [get_dir_hash_only(file_mock), get_dir_hash_only(file_mock2)], 'validated': False} + ledger_data = {'pkhash': [get_dir_hash(file_mock), get_dir_hash(file_mock2)], 'validated': False} mcreate.return_value = ledger_data, status.HTTP_408_REQUEST_TIMEOUT response = self.client.post(url, data, format='multipart', **extra) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 034ccd089..abdae6cd0 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -24,11 +24,11 @@ def __init__(self, msg): super(JsonException, self).__init__() -def get_dir_hash_only(archive_content): +def get_dir_hash(archive_object): with tempfile.TemporaryDirectory() as temp_dir: try: - content = archive_content.read() - archive_content.seek(0) + content = archive_object.read() + archive_object.seek(0) uncompress_content(content, temp_dir) except Exception as e: logging.error(e) @@ -37,11 +37,11 @@ def get_dir_hash_only(archive_content): return dirhash(temp_dir, 'sha256') -def get_dir_hash(archive_content): +def store_datasamples_archive(archive_object): try: - content = archive_content.read() - archive_content.seek(0) + content = archive_object.read() + archive_object.seek(0) except Exception as e: logging.error(e) raise e diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 1a7d84bc2..16e237fed 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -24,7 +24,7 @@ from substrapp.serializers import DataSampleSerializer, LedgerDataSampleSerializer from substrapp.serializers.ledger.datasample.util import updateLedgerDataSample from substrapp.serializers.ledger.datasample.tasks import updateLedgerDataSampleAsync -from substrapp.utils import uncompress_path, get_dir_hash +from substrapp.utils import uncompress_path, store_datasamples_archive from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import find_primary_key_error, LedgerException, ValidationException, \ get_success_create_code @@ -34,16 +34,21 @@ class DataSamplesPathsFromFilesRemoval(object): + + def __init__(self): + self.datasamples_paths_from_files = [] + def __enter__(self): - global datasamples_paths_from_files - datasamples_paths_from_files = [] + return self def __exit__(self, exc_type, exc_val, traceback): - global datasamples_paths_from_files # Remove gpath as they are hard linked with pre save signals - for gpath in datasamples_paths_from_files: + for gpath in self.datasamples_paths_from_files: shutil.rmtree(gpath, ignore_errors=True) + def add_path(self, path): + self.datasamples_paths_from_files.append(path) + class DataSampleViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, @@ -105,7 +110,7 @@ def commit(serializer, ledger_data): return serializer.data, st - def compute_data(self, request): + def compute_data(self, request, remover): data = {} @@ -117,8 +122,8 @@ def compute_data(self, request): for k, file in request.FILES.items(): # Get dir hash uncompress the file into a directory - pkhash, datasamples_path_from_file = get_dir_hash(file) # can raise - datasamples_paths_from_files.append(datasamples_path_from_file) + pkhash, datasamples_path_from_file = store_datasamples_archive(file) # can raise + remover.add_path(datasamples_path_from_file) # check pkhash does not belong to the list try: data[pkhash] @@ -210,13 +215,13 @@ def handle_dryrun(self, data, data_manager_keys): def _create(self, request, data_manager_keys, test_only, dryrun): - with DataSamplesPathsFromFilesRemoval(): + with DataSamplesPathsFromFilesRemoval() as remover: if not data_manager_keys: raise Exception("missing or empty field 'data_manager_keys'") self.check_datamanagers(data_manager_keys) # can raise - computed_data = self.compute_data(request) + computed_data = self.compute_data(request, remover) serializer = self.get_serializer(data=computed_data, many=True) From b93240f9a8bf472e0286852d7592ac3db3279550 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 8 Jul 2019 11:44:37 +0200 Subject: [PATCH 155/457] Remove comment. --- substrabac/substrapp/signals/datasample/pre_save.py | 1 - 1 file changed, 1 deletion(-) diff --git a/substrabac/substrapp/signals/datasample/pre_save.py b/substrabac/substrapp/signals/datasample/pre_save.py index e3940ff7d..75ed866ec 100644 --- a/substrabac/substrapp/signals/datasample/pre_save.py +++ b/substrabac/substrapp/signals/datasample/pre_save.py @@ -23,7 +23,6 @@ def data_sample_pre_save(sender, instance, **kwargs): directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'datasamples/{0}'.format(instance.pk)) # uncompress file if an archive - # Should not be necessary with get_dir_hash if isinstance(instance.path, File): try: content = instance.path.read() From 0c6943bd5da0c29d7c4d5b8fa73ea427c594a964 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 10 Jul 2019 15:51:06 +0200 Subject: [PATCH 156/457] Update along the review. --- .../substrapp/signals/datasample/pre_save.py | 53 +++------------ substrabac/substrapp/tasks/tasks.py | 1 + .../tests/query/tests_query_datasample.py | 6 +- substrabac/substrapp/tests/tests_tasks.py | 13 ++-- .../tests/views/tests_views_datasample.py | 19 +++++- substrabac/substrapp/utils.py | 2 +- substrabac/substrapp/views/datasample.py | 66 +++++-------------- 7 files changed, 55 insertions(+), 105 deletions(-) diff --git a/substrabac/substrapp/signals/datasample/pre_save.py b/substrabac/substrapp/signals/datasample/pre_save.py index 75ed866ec..32ef04843 100644 --- a/substrabac/substrapp/signals/datasample/pre_save.py +++ b/substrabac/substrapp/signals/datasample/pre_save.py @@ -1,13 +1,7 @@ -import logging -import shutil -from os import path, rename, link, walk, makedirs +from os import path, link, walk, makedirs from os.path import normpath -from checksumdir import dirhash from django.conf import settings -from django.core.files import File - -from substrapp.utils import uncompress_content def create_hard_links(base_dir, directory): @@ -22,41 +16,12 @@ def create_hard_links(base_dir, directory): def data_sample_pre_save(sender, instance, **kwargs): directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'datasamples/{0}'.format(instance.pk)) - # uncompress file if an archive - if isinstance(instance.path, File): - try: - content = instance.path.read() - instance.path.seek(0) - uncompress_content(content, directory) - except Exception as e: - logging.exception(e) - raise e - else: - # compute new hash - sha256hash = dirhash(directory, 'sha256') - # rename directory to new hash if does not exist - new_directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'datasamples', sha256hash) - try: - rename(directory, new_directory) - except OSError as e: - # new_directory already exists with same exact data sample inside - # created by a previous save, delete directory entitled pkhash - # for avoiding duplicates - shutil.rmtree(directory) - logging.exception(e) - - # override defaults - instance.pkhash = sha256hash - instance.path = new_directory - - # make an hardlink on all files if a path + # try to make an hard link to keep a free copy of the data + # if not possible, keep the real path location + try: + create_hard_links(normpath(instance.path), directory) + except Exception: + pass else: - # try to make an hard link to keep a free copy of the data - # if not possible, keep the real path location - try: - create_hard_links(normpath(instance.path), directory) - except Exception: - pass - else: - # override path for getting our hardlink - instance.path = directory + # override path for getting our hardlink + instance.path = directory diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index e2f12a278..f22159d28 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -142,6 +142,7 @@ def put_data_sample(subtuple, subtuple_directory): data_sample = DataSample.objects.get(pk=data_sample_key) data_sample_hash = dirhash(data_sample.path, 'sha256') if data_sample_hash != data_sample_key: + print(data_sample_hash, data_sample_key) raise Exception('Data Sample Hash in Subtuple is not the same as in local db') # create a symlink on the folder containing data diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substrabac/substrapp/tests/query/tests_query_datasample.py index b60f02621..51a910c3d 100644 --- a/substrabac/substrapp/tests/query/tests_query_datasample.py +++ b/substrabac/substrapp/tests/query/tests_query_datasample.py @@ -17,7 +17,7 @@ from substrapp.models import DataManager, DataSample from substrapp.serializers import LedgerDataSampleSerializer, DataSampleSerializer -from substrapp.utils import get_hash, get_dir_hash +from substrapp.utils import get_hash, get_dir_hash, store_datasamples_archive from substrapp.ledger_utils import LedgerError, LedgerTimeout from substrapp.views import DataSampleViewSet @@ -194,7 +194,9 @@ def test_add_data_sample_ko_already_exists(self): file_mock.read = MagicMock(return_value=self.data_file.file.read()) file_mock.open = MagicMock(return_value=file_mock) - d = DataSample(path=file_mock) + _, datasamples_path_from_file = store_datasamples_archive(file_mock) + + d = DataSample(path=datasamples_path_from_file) # trigger pre save d.save() diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 0b0ae27d5..acc78d3d5 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -13,6 +13,7 @@ from substrapp.models import DataSample from substrapp.ledger_utils import LedgerStatusError +from substrapp.utils import store_datasamples_archive from substrapp.utils import compute_hash, get_computed_hash, get_remote_file, get_hash, create_directory from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, @@ -208,7 +209,9 @@ def test_put_opener(self): def test_put_data_sample_zip(self): - data_sample = DataSample(pkhash='foo', path=self.data_sample) + dir_pkhash, datasamples_path_from_file = store_datasamples_archive(self.data_sample) + + data_sample = DataSample(pkhash=dir_pkhash, path=datasamples_path_from_file) data_sample.save() subtuple = { @@ -226,7 +229,7 @@ def test_put_data_sample_zip(self): # check folder has been correctly renamed with pk of directory containing uncompressed data sample self.assertFalse( os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', 'foo'))) - dir_pkhash = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' + # dir_pkhash = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' self.assertTrue( os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', dir_pkhash))) @@ -268,7 +271,9 @@ def test_put_data_sample_zip_fail(self): def test_put_data_tar(self): - data_sample = DataSample(pkhash='foo', path=self.data_sample_tar) + dir_pkhash, datasamples_path_from_file = store_datasamples_archive(self.data_sample_tar) + + data_sample = DataSample(pkhash=dir_pkhash, path=datasamples_path_from_file) data_sample.save() subtuple = { @@ -285,7 +290,7 @@ def test_put_data_tar(self): # check folder has been correctly renamed with pk of directory containing uncompressed data_sample self.assertFalse(os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', 'foo'))) - dir_pkhash = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' + # dir_pkhash = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', dir_pkhash))) # check subtuple folder has been created and sym links exists diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index b751ff095..5f16cab92 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -1,4 +1,5 @@ import os +import io import shutil import logging @@ -14,10 +15,12 @@ from substrapp.serializers import LedgerDataSampleSerializer from substrapp.views.datasample import path_leaf, compute_dryrun as data_sample_compute_dryrun -from substrapp.utils import get_hash, uncompress_content +from substrapp.utils import get_hash, uncompress_content, store_datasamples_archive from substrapp.models import DataManager +from django.core.files.uploadedfile import InMemoryUploadedFile + from ..common import get_sample_datamanager from ..common import FakeFilterDataManager, FakeDataManager @@ -275,10 +278,20 @@ def test_data_sample_compute_dryrun(self): opener_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') - pkhash = get_hash(data_path) + file_filename = "file.zip" + + archive_data = io.BytesIO() + with open(os.path.join(data_path), 'rb') as zip_file: + alen = archive_data.write(zip_file.read()) + + archive_object = InMemoryUploadedFile(archive_data, None, file_filename, + 'application/zip', alen, None) + archive_object.seek(0) + + pkhash, datasamples_path_from_file = store_datasamples_archive(archive_object) data = { - 'filepath': os.path.join(MEDIA_ROOT, '0024700.zip'), + 'path': datasamples_path_from_file, 'pkhash': pkhash, } diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index abdae6cd0..d96b33a7e 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -48,7 +48,7 @@ def store_datasamples_archive(archive_object): datasamples_file_hash = compute_hash(content) datasamples_path = path.join(getattr(settings, 'MEDIA_ROOT'), - 'datasamples/{0}'.format(datasamples_file_hash)) + f'datasamples/{datasamples_file_hash}') try: uncompress_content(content, datasamples_path) except Exception as e: diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 16e237fed..05607aa61 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -24,7 +24,7 @@ from substrapp.serializers import DataSampleSerializer, LedgerDataSampleSerializer from substrapp.serializers.ledger.datasample.util import updateLedgerDataSample from substrapp.serializers.ledger.datasample.tasks import updateLedgerDataSampleAsync -from substrapp.utils import uncompress_path, store_datasamples_archive +from substrapp.utils import store_datasamples_archive from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import find_primary_key_error, LedgerException, ValidationException, \ get_success_create_code @@ -33,23 +33,6 @@ logger = logging.getLogger('django.request') -class DataSamplesPathsFromFilesRemoval(object): - - def __init__(self): - self.datasamples_paths_from_files = [] - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, traceback): - # Remove gpath as they are hard linked with pre save signals - for gpath in self.datasamples_paths_from_files: - shutil.rmtree(gpath, ignore_errors=True) - - def add_path(self, path): - self.datasamples_paths_from_files.append(path) - - class DataSampleViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, @@ -110,7 +93,7 @@ def commit(serializer, ledger_data): return serializer.data, st - def compute_data(self, request, remover): + def compute_data(self, request, paths_to_remove): data = {} @@ -118,12 +101,11 @@ def compute_data(self, request, remover): # available on local disk if len(request.FILES) > 0: pkhash_map = {} - global datasamples_paths_from_files for k, file in request.FILES.items(): # Get dir hash uncompress the file into a directory pkhash, datasamples_path_from_file = store_datasamples_archive(file) # can raise - remover.add_path(datasamples_path_from_file) + paths_to_remove.append(datasamples_path_from_file) # check pkhash does not belong to the list try: data[pkhash] @@ -187,27 +169,8 @@ def compute_data(self, request, remover): return list(data.values()) def handle_dryrun(self, data, data_manager_keys): - data_dry_run = [] - - # write uploaded file to disk - for d in data: - pkhash = d['pkhash'] - if 'file' in d: - file_path = os.path.join(getattr(settings, 'DRYRUN_ROOT'), - f'data_{pkhash}.zip') - with open(file_path, 'wb') as f: - f.write(d['file'].open().read()) - - data_dry_run.append({ - 'pkhash': pkhash, - 'file': file_path - }) - - if 'path' in d: - data_dry_run.append(d) - try: - task, msg = self.dryrun_task(data_dry_run, data_manager_keys) + task, msg = self.dryrun_task(data, data_manager_keys) except Exception as e: raise Exception(f'Could not launch data creation with dry-run on this instance: {str(e)}') else: @@ -215,13 +178,15 @@ def handle_dryrun(self, data, data_manager_keys): def _create(self, request, data_manager_keys, test_only, dryrun): - with DataSamplesPathsFromFilesRemoval() as remover: + paths_to_remove = [] + + try: if not data_manager_keys: raise Exception("missing or empty field 'data_manager_keys'") self.check_datamanagers(data_manager_keys) # can raise - computed_data = self.compute_data(request, remover) + computed_data = self.compute_data(request, paths_to_remove) serializer = self.get_serializer(data=computed_data, many=True) @@ -242,6 +207,9 @@ def _create(self, request, data_manager_keys, test_only, dryrun): 'data_manager_keys': data_manager_keys} data, st = self.commit(serializer, ledger_data) return data, st + finally: + for gpath in paths_to_remove: + shutil.rmtree(gpath, ignore_errors=True) def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) @@ -339,16 +307,12 @@ def compute_dryrun(self, data_samples, data_manager_keys): try: for data_sample in data_samples: - # uncompress only for file - if 'file' in data_sample: - uncompress_path(data_sample['file'], os.path.join(data_path, data_sample['pkhash'])) # for all data paths, we need to create symbolic links inside data_path # and add real path to volume bind docker - elif 'path' in data_sample: - os.symlink(data_sample['path'], os.path.join(data_path, data_sample['pkhash'])) - volumes.update({ - data_sample['path']: {'bind': data_sample['path'], 'mode': 'ro'} - }) + os.symlink(data_sample['path'], os.path.join(data_path, data_sample['pkhash'])) + volumes.update({ + data_sample['path']: {'bind': data_sample['path'], 'mode': 'ro'} + }) for datamanager_key in data_manager_keys: datamanager = DataManager.objects.get(pk=datamanager_key) From 44dfb3958208b223df9e5cccf3696369d00c28f0 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 11 Jul 2019 10:20:27 +0200 Subject: [PATCH 157/457] Clean and fix minor issue. --- docker/start.py | 19 +++++---------- substrabac/substrabac/settings/dev.py | 3 --- substrabac/substrabac/settings/prod.py | 1 - .../substrapp/signals/datasample/pre_save.py | 17 ++++---------- substrabac/substrapp/tasks/tasks.py | 1 - .../tests/query/tests_query_datasample.py | 2 -- substrabac/substrapp/tests/tests_tasks.py | 2 -- .../substrapp/tests/views/tests_views_algo.py | 1 - .../tests/views/tests_views_datasample.py | 1 - .../tests/views/tests_views_objective.py | 1 - substrabac/substrapp/views/datasample.py | 23 ++++++++++++++----- substrabac/substrapp/views/objective.py | 8 +++++-- 12 files changed, 33 insertions(+), 46 deletions(-) diff --git a/docker/start.py b/docker/start.py index af33cf5f8..22db32aba 100644 --- a/docker/start.py +++ b/docker/start.py @@ -170,9 +170,8 @@ def generate_docker_compose_file(conf, launch_settings): 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), 'volumes': [ - f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias', - f'{SUBSTRA_FOLDER}/dryrun:{SUBSTRA_FOLDER}/dryrun', - f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias', + f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias:rw', + f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro', f'{SUBSTRA_FOLDER}/static:/usr/src/app/substrabac/statics'] + hlf_volumes, 'depends_on': ['postgresql', 'rabbit']} @@ -201,8 +200,8 @@ def generate_docker_compose_file(conf, launch_settings): 'environment': backend_global_env.copy(), 'volumes': [ '/var/run/docker.sock:/var/run/docker.sock', - f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias', - f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias'] + hlf_volumes, + f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias:rw', + f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro'] + hlf_volumes, 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} dryrunner = { @@ -217,9 +216,8 @@ def generate_docker_compose_file(conf, launch_settings): 'environment': backend_global_env.copy(), 'volumes': [ '/var/run/docker.sock:/var/run/docker.sock', - f'{SUBSTRA_FOLDER}/dryrun:{SUBSTRA_FOLDER}/dryrun', - f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias', - f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias'] + hlf_volumes, + f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias:rw', + f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro'] + hlf_volumes, 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} # Check if we have nvidia docker @@ -228,14 +226,9 @@ def generate_docker_compose_file(conf, launch_settings): if launch_settings == 'dev': media_root = f'MEDIA_ROOT={SUBSTRA_FOLDER}/medias/{org_name_stripped}' - dryrun_root = f'DRYRUN_ROOT={SUBSTRA_FOLDER}/dryrun/{org_name}' - worker['environment'].append(media_root) dryrunner['environment'].append(media_root) backend['environment'].append(media_root) - - dryrunner['environment'].append(dryrun_root) - backend['environment'].append(dryrun_root) else: default_domain = os.environ.get('SUBSTRABAC_DEFAULT_DOMAIN', '') if default_domain: diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index c8294cef9..125fca43a 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -25,10 +25,7 @@ } MEDIA_ROOT = os.environ.get('MEDIA_ROOT', os.path.join(PROJECT_ROOT, f'medias/{ORG_NAME}')) -DRYRUN_ROOT = os.environ.get('DRYRUN_ROOT', os.path.join(PROJECT_ROOT, f'dryrun/{ORG}')) -if not os.path.exists(DRYRUN_ROOT): - os.makedirs(DRYRUN_ROOT, exist_ok=True) SITE_HOST = f'{ORG_NAME}.substrabac' SITE_PORT = DEFAULT_PORT diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 27ba82362..8d70b2d12 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -39,7 +39,6 @@ } MEDIA_ROOT = f'/substra/medias/{ORG_NAME}' -DRYRUN_ROOT = f'/substra/dryrun/{ORG}' SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substrabac') diff --git a/substrabac/substrapp/signals/datasample/pre_save.py b/substrabac/substrapp/signals/datasample/pre_save.py index 32ef04843..193e8fa57 100644 --- a/substrabac/substrapp/signals/datasample/pre_save.py +++ b/substrabac/substrapp/signals/datasample/pre_save.py @@ -1,27 +1,18 @@ -from os import path, link, walk, makedirs +from os import path, link from os.path import normpath - +import shutil from django.conf import settings -def create_hard_links(base_dir, directory): - makedirs(directory, exist_ok=True) - for root, subdirs, files in walk(base_dir): - for file in files: - link(path.join(root, file), path.join(directory, file)) - for subdir in subdirs: - create_hard_links(root, subdir) - - def data_sample_pre_save(sender, instance, **kwargs): directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'datasamples/{0}'.format(instance.pk)) # try to make an hard link to keep a free copy of the data # if not possible, keep the real path location try: - create_hard_links(normpath(instance.path), directory) + shutil.copytree(normpath(instance.path), directory, copy_function=link) except Exception: - pass + shutil.rmtree(directory, ignore_errors=True) else: # override path for getting our hardlink instance.path = directory diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index f22159d28..e2f12a278 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -142,7 +142,6 @@ def put_data_sample(subtuple, subtuple_directory): data_sample = DataSample.objects.get(pk=data_sample_key) data_sample_hash = dirhash(data_sample.path, 'sha256') if data_sample_hash != data_sample_key: - print(data_sample_hash, data_sample_key) raise Exception('Data Sample Hash in Subtuple is not the same as in local db') # create a symlink on the folder containing data diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substrabac/substrapp/tests/query/tests_query_datasample.py index 51a910c3d..201f93114 100644 --- a/substrabac/substrapp/tests/query/tests_query_datasample.py +++ b/substrabac/substrapp/tests/query/tests_query_datasample.py @@ -298,8 +298,6 @@ def test_bulk_add_data_sample_ko_408(self): mget_validators.return_value = [] self.data_file.seek(0) self.data_tar_file.seek(0) - # ledger_data = {'pkhash': [get_dir_hash(file_mock), - # get_dir_hash(file_mock2)], 'validated': False} mcreate.side_effect = LedgerTimeout('Timeout') response = self.client.post(url, data, format='multipart', **extra) diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index acc78d3d5..2ae77e656 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -229,7 +229,6 @@ def test_put_data_sample_zip(self): # check folder has been correctly renamed with pk of directory containing uncompressed data sample self.assertFalse( os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', 'foo'))) - # dir_pkhash = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' self.assertTrue( os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', dir_pkhash))) @@ -290,7 +289,6 @@ def test_put_data_tar(self): # check folder has been correctly renamed with pk of directory containing uncompressed data_sample self.assertFalse(os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', 'foo'))) - # dir_pkhash = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' self.assertTrue(os.path.exists(os.path.join(MEDIA_ROOT, 'datasamples', dir_pkhash))) # check subtuple folder has been created and sym links exists diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index 68c3162be..435150525 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -26,7 +26,6 @@ # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(DRYRUN_ROOT=MEDIA_ROOT) @override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 5f16cab92..a4e53653b 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -29,7 +29,6 @@ # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(DRYRUN_ROOT=MEDIA_ROOT) @override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(DEFAULT_DOMAIN='https://localhost') diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index ffd2c3b86..e437c27f8 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -28,7 +28,6 @@ # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(DRYRUN_ROOT=MEDIA_ROOT) @override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(DEFAULT_DOMAIN='https://localhost') diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 05607aa61..ba37fb41d 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -169,6 +169,7 @@ def compute_data(self, request, paths_to_remove): return list(data.values()) def handle_dryrun(self, data, data_manager_keys): + try: task, msg = self.dryrun_task(data, data_manager_keys) except Exception as e: @@ -178,6 +179,11 @@ def handle_dryrun(self, data, data_manager_keys): def _create(self, request, data_manager_keys, test_only, dryrun): + # compute_data will uncompress data archives to paths which will be + # hardlinked thanks to datasample pre_save signal. In case of dryrun + # we must keep those references, which will be removed by the dryrun tasks. + # In all other cases, we need to remove those references. + paths_to_remove = [] try: @@ -186,6 +192,7 @@ def _create(self, request, data_manager_keys, test_only, dryrun): self.check_datamanagers(data_manager_keys) # can raise + # will uncompress data archives to paths computed_data = self.compute_data(request, paths_to_remove) serializer = self.get_serializer(data=computed_data, many=True) @@ -205,11 +212,14 @@ def _create(self, request, data_manager_keys, test_only, dryrun): # create on ledger + db ledger_data = {'test_only': test_only, 'data_manager_keys': data_manager_keys} - data, st = self.commit(serializer, ledger_data) + data, st = self.commit(serializer, ledger_data) # pre_save signal executed return data, st finally: - for gpath in paths_to_remove: - shutil.rmtree(gpath, ignore_errors=True) + if not dryrun: + # Remove the reference paths of uncompressed data archive as they were all + # harlinked in the commit. We must keep them for the dryrun case + for gpath in paths_to_remove: + shutil.rmtree(gpath, ignore_errors=True) def create(self, request, *args, **kwargs): dryrun = request.data.get('dryrun', False) @@ -325,7 +335,7 @@ def compute_dryrun(self, data_samples, data_manager_keys): data_docker_name = f'{data_docker}_{dryrun_uuid}' volumes.update({ - data_path: {'bind': '/sandbox/data', 'mode': 'rw'}, + data_path: {'bind': '/sandbox/data', 'mode': 'ro'}, opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'} }) @@ -361,6 +371,7 @@ def compute_dryrun(self, data_samples, data_manager_keys): remove_subtuple_materials(subtuple_directory) + # Clean dryrun materials for data_sample in data_samples: - if 'file' in data_sample and os.path.exists(data_sample['file']): - os.remove(data_sample['file']) + # Remove all possible data (data in servermedias is read-only) + shutil.rmtree(data_sample['path'], ignore_errors=True) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 548454b0c..5c804d52f 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -23,7 +23,7 @@ from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout -from substrapp.utils import get_hash, get_computed_hash, get_from_node +from substrapp.utils import get_hash, get_computed_hash, get_from_node, create_directory from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ get_success_create_code, ValidationException, LedgerException @@ -47,7 +47,11 @@ def perform_create(self, serializer): def handle_dryrun(self, pkhash, metrics, test_data_manager_key): try: - metrics_path = os.path.join(getattr(settings, 'DRYRUN_ROOT'), f'metrics_{pkhash}.py') + dryrun_directory = os.path.join(getattr(settings, 'MEDIA_ROOT'), 'dryrun') + create_directory(dryrun_directory) + + metrics_path = os.path.join(dryrun_directory, f'metrics_{pkhash}.py') + with open(metrics_path, 'wb') as metrics_file: metrics_file.write(metrics.open().read()) task = compute_dryrun.apply_async( From 58eb4cf851daac56f25bf5e9f1038f98742907ed Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 16 Jul 2019 09:23:17 +0200 Subject: [PATCH 158/457] Improve after review. --- substrabac/substrapp/views/datasample.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index ba37fb41d..334f9ecc3 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -184,14 +184,14 @@ def _create(self, request, data_manager_keys, test_only, dryrun): # we must keep those references, which will be removed by the dryrun tasks. # In all other cases, we need to remove those references. - paths_to_remove = [] + if not data_manager_keys: + raise Exception("missing or empty field 'data_manager_keys'") - try: - if not data_manager_keys: - raise Exception("missing or empty field 'data_manager_keys'") + self.check_datamanagers(data_manager_keys) # can raise - self.check_datamanagers(data_manager_keys) # can raise + paths_to_remove = [] + try: # will uncompress data archives to paths computed_data = self.compute_data(request, paths_to_remove) From d6fedaf59e19f96279aaed5fb1322d35793ca640 Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 5 Jul 2019 15:46:54 +0200 Subject: [PATCH 159/457] update populate with latest sdk --- populate.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/populate.py b/populate.py index 6c49b7033..f2d7aa154 100644 --- a/populate.py +++ b/populate.py @@ -4,7 +4,7 @@ import shutil import time -import substra_sdk_py as substra +import substra from termcolor import colored @@ -25,12 +25,16 @@ def get_or_create(data, profile, asset, dryrun=False, register=False): client.set_config(profile) - method = client.add if not register else client.register + method_kwargs = {} + if register: + method_kwargs['local'] = False + + method = getattr(client, f'add_{asset}') if dryrun: print('dryrun') try: - r = method(asset, data, dryrun=True) + r = method(data, dryrun=True, **method_kwargs) except substra.exceptions.AlreadyExists as e: r = e.response.json() print(colored(json.dumps(r, indent=2), 'cyan')) @@ -39,7 +43,7 @@ def get_or_create(data, profile, asset, dryrun=False, register=False): print('real') try: - r = method(asset, data) + r = method(data, **method_kwargs) except substra.exceptions.AlreadyExists as e: r = e.response.json() @@ -56,7 +60,7 @@ def get_or_create(data, profile, asset, dryrun=False, register=False): def update_datamanager(data_manager_key, data, profile): client.set_config(profile) try: - r = client.update('dataset', data_manager_key, data) + r = client.update_dataset(data_manager_key, data) except substra.exceptions.AlreadyExists as e: r = e.response.json() @@ -302,7 +306,7 @@ def do_populate(): #################################################### client.set_config(org_1) - res = client.get('traintuple', traintuple_key) + res = client.get_traintuple(traintuple_key) print(colored(json.dumps(res, indent=2), 'green')) # create testtuple @@ -314,7 +318,7 @@ def do_populate(): testtuple_key = get_or_create(data, org_1, 'testtuple') client.set_config(org_1) - res_t = client.get('testtuple', testtuple_key) + res_t = client.get_testtuple(testtuple_key) print(colored(json.dumps(res_t, indent=2), 'yellow')) testtuple_status = None @@ -323,8 +327,8 @@ def do_populate(): client.set_config(org_1) while traintuple_status not in ('done', 'failed') or testtuple_status not in ('done', 'failed'): - res = client.get('traintuple', traintuple_key) - res_t = client.get('testtuple', testtuple_key) + res = client.get_traintuple(traintuple_key) + res_t = client.get_testtuple(testtuple_key) if traintuple_status != res['status'] or testtuple_status != res_t['status']: traintuple_status = res['status'] testtuple_status = res_t['status'] From 1f816640db4c28169aaf016dd2dea5ffc55a7485 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 18 Jul 2019 11:22:21 +0200 Subject: [PATCH 160/457] populate: sdk expects data sample folders --- .../datasamples/test/0024900/IMG_0024900.jpg | Bin 0 -> 272185 bytes .../test/0024900/LABEL_0024900.csv | 1 + .../datasamples/test/0024901/IMG_0024901.jpg | Bin 0 -> 339960 bytes .../test/0024901/LABEL_0024901.csv | 1 + .../datasamples/test/0024902/IMG_0024902.jpg | Bin 0 -> 249153 bytes .../test/0024902/LABEL_0024902.csv | 1 + .../datasamples/test/0024903/IMG_0024903.jpg | Bin 0 -> 273349 bytes .../test/0024903/LABEL_0024903.csv | 1 + .../datasamples/test/0024904/IMG_0024904.jpg | Bin 0 -> 223385 bytes .../test/0024904/LABEL_0024904.csv | 1 + .../datasamples/test/0024905/IMG_0024905.jpg | Bin 0 -> 277965 bytes .../test/0024905/LABEL_0024905.csv | 1 + populate.py | 24 +++++++++--------- 13 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 fixtures/owkin/datasamples/test/0024900/IMG_0024900.jpg create mode 100644 fixtures/owkin/datasamples/test/0024900/LABEL_0024900.csv create mode 100644 fixtures/owkin/datasamples/test/0024901/IMG_0024901.jpg create mode 100644 fixtures/owkin/datasamples/test/0024901/LABEL_0024901.csv create mode 100644 fixtures/owkin/datasamples/test/0024902/IMG_0024902.jpg create mode 100644 fixtures/owkin/datasamples/test/0024902/LABEL_0024902.csv create mode 100644 fixtures/owkin/datasamples/test/0024903/IMG_0024903.jpg create mode 100644 fixtures/owkin/datasamples/test/0024903/LABEL_0024903.csv create mode 100644 fixtures/owkin/datasamples/test/0024904/IMG_0024904.jpg create mode 100644 fixtures/owkin/datasamples/test/0024904/LABEL_0024904.csv create mode 100644 fixtures/owkin/datasamples/test/0024905/IMG_0024905.jpg create mode 100644 fixtures/owkin/datasamples/test/0024905/LABEL_0024905.csv diff --git a/fixtures/owkin/datasamples/test/0024900/IMG_0024900.jpg b/fixtures/owkin/datasamples/test/0024900/IMG_0024900.jpg new file mode 100644 index 0000000000000000000000000000000000000000..086f863c32a20ed2146c636558035a530f05fe6e GIT binary patch literal 272185 zcmbq)^;^_W*zRYSrMnvzSQ?}|m)u3VB&EBNkS;+wg)bo;($XoVlyrlHAfU(sQqpyN z&w2lYGr!DS*Id{A%rkk7gc z40;*_7ytkbK>NSo!2e4SbPO;WCJ4a7#`#wdCj!7=FbD!dLjz-gAOJuJ0;3T_NSFY0 zQf2`%K{y7Bj)D~?xsa|`1Pn{j+FLlS5nD+wGQD_~!lq>4$3F-<(El0${jUW84T25^ zVE~v||7w;0HRgZ7A!ryF|5E^PL11DuCINs14$&cHw(=5;NJCdBZX7rvW6_=caVli( zjS<;Iu9yxJ)_Ya*8I#o}>g;J1z(WK5a|(?ZkOQ6o!M^RVgUtuMC*Y<}?!qne_WXh{ zc=93SR_~&DtYI?un|NVq*pSD`C0(m)^3XHcIptgbi?IEeH043tsRxPg6m<9glZPQ+ zo`7e}OZ#CLgx|I!dAZ0Xh3>iE(P~JJe(-n;qNo#27aL_Qju7m6SUdXO_XOxa0l(!Q zj6!D*xEAhI4?nhm>Qr)A17EfuJ^@6O6+^inPYNBi!{JQvah@g#9Tvy!*AkBcq2W&e z-4pO-YT%JQ>}~#+`}4ocD8z33YxX3$i90^O2<ns}Qm7Ya=~->&E`-gFX?5C#>g;e>qd?$LW^87hxZ%FncPvL*&7rGzqHk9% z?0u0I}6r3LMp}x!m5ABq@p{_)5x{J&Y=A84+nff2kzG}}|rUHp8BNU{f zGv*82N?WNO5T(h)kq;I1#e>9MYA=@FJf~(K;Q|zA!0%F=y?Gs7ru9J`Xpp!I5`J6I z&3!9Gl9iRri1kb|c?>b@{zVR#ZbB>l`;4LUMM^dOMPzwL zV=TG@ZDPRdqXS@{ADcb}mge#0?-L;PMnMPl=5T4$L$6_1+#@Aip8QDl&WGx|<{&k# zTDtOEQg_Qi|DL}{083~zJb3vDuwW|j>Q>lQIu
    <52YAPk>0I~nAFdOD^DE=Taw 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
    y6hRgUnx?@u8)!U} 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 literal 0 HcmV?d00001 diff --git a/fixtures/owkin/datasamples/test/0024900/LABEL_0024900.csv b/fixtures/owkin/datasamples/test/0024900/LABEL_0024900.csv new file mode 100644 index 000000000..d8044bb00 --- /dev/null +++ b/fixtures/owkin/datasamples/test/0024900/LABEL_0024900.csv @@ -0,0 +1 @@ +1.0,0.0,0.0,0.0,0.0,0.0,0.0 diff --git a/fixtures/owkin/datasamples/test/0024901/IMG_0024901.jpg b/fixtures/owkin/datasamples/test/0024901/IMG_0024901.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f1cb6344cb6f7e98d47d9356f532adf9b2845d04 GIT binary patch literal 339960 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
  1. oAICMSb85F@)9Er{+W?WNr#NV$8GUh_z_x; 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%0DT;-zXvn1<3+t|npbrqklQM%A zZ|o^Q6M`}c?liT;23qk-t8(er9nSUFhP+1O$8r5PALE*uYG+5t0X%hE*~_gxZ`G%d z^Ozs>*jYdI7V1^40_-c(mYbTUiERPB7F#fV1_xJNB69ZeN!9WWwuj5;rRk7*c~YV2 zF_!V>(w<)DaNuThLuomyUj>#p0IKNTE?g6)hFIVP^w7$MwB&Ks*A)Vvy(&s{ z*I%i>UB}B8#%_JHb*7Sp+==JCbR*l}@$0U51dUetQOZ-9D<8&_QJ^LdKEYX`EyZRV zQZ1yml!Nc(n74xN%4d_giN{>0bElSsdGAi0O!RtgOXWvmYgO(IZ$NHn)}5TS-~RxI z)xJNL%N|Zx^Za{ham8}r+}3m)iE&*r?sF^FjkXU}97)+#X0*1W*(N7n)C9@BO|#s) zWH|CAnh&)-MVAb`?cmC9RmlGU%_jOk;o@)k^mcT7om!bbAA3f3DiOP9DW~h1p2uah z3#%vjHziloE~dQLaZkC*X^viTyOGx(5^KC#8Rluz$7g$|@jp8jN~$r$)=pAY zrZ#H0@!v7mDFvzTw?@smKau$LhU?mlZYNDnO00{ov?NBpO8)?b{{RPC$Lsu9;`sEW z(OsK!(5PxKKkjQvT7)Kt`)E|Zp}&vGc}kkd$L+j$X8G;$%GsX#D_cNW+#Y>Fk;N+A zO|R=1mb?D|YH^$R`CailLu&fgl5F!n4MF&>P(+T987x(w+tZqMilum{3>Xpuu?4Y< zJCMn8UWls1@!~VQlT$N~T*siSntT5M#QftDt$ew3aqS+2H}s>Y&idYy(~k`Cvl_z9 zBpDf4zmUL1iU&o!f@x@kd0X>zf6oU4e7sFMkHc1TmMD}d8 z5hY%ZCbt{f>q8svj!SQe0}Wl|7(NObgtFbTFL2|;5`g)Rx#OQpJ7G^U0ISiFFT+Eq)Xzpkp$8YrqDJ3By zYC_ALYf+mVtnO}UfZo3N=+mRFJ9_C4Tf(BW>XTYAn$%1b36Awy>(VF<&SQYcXCQK) zrcP&cnX+c%IP*+l#8-ID>>rT>j+=eiEDGs|i9H*eIJn`+( zIQd+C^|Y4+l{6U@Q{zxINO_)HMNN6FLRXYMdBqSlwng#fQI3g=hF=|5{-GDP{z3J@ zPdb)Gok$4NEQzM|ZY#wOLnaflq8;~jLnT!0m5P7qiB6RHQ>SFfIKvh>_VOZS;!~H3 z?y@$;>IO5Yx ztxppoNj0X#5CIwEKE`X|b8@<$rdgc@>CCe(hsrutK5gKQTB=q}ceGOD@*Ulm`EGV>cy zYbD`$R~{;{?yQ>9Pf~-fBLFfK_na$u8Y;q~WAD(LPOd`WwdZu0-0%yl^Bs zT9Zx`Vp-WkUT2jmskIaUB7nj6!*F8DZMjn>7}p$mvJrmey5sH?E!uVcvODQCt$tY4 zW~!0cZjI}262HniM?~>{{W`~UX4XD3(NFN i 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

    izs2Vc%}l&P~?t0bYcoZTn18N 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%0DdXJs){NVF1f0(5Hb`L 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�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 MA*xSlAT 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�M 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

    V{9{_h|fw&v^nRS+oGO9dsQkY*iP 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 literal 0 HcmV?d00001 diff --git a/fixtures/owkin/datasamples/test/0024902/LABEL_0024902.csv b/fixtures/owkin/datasamples/test/0024902/LABEL_0024902.csv new file mode 100644 index 000000000..ff746af51 --- /dev/null +++ b/fixtures/owkin/datasamples/test/0024902/LABEL_0024902.csv @@ -0,0 +1 @@ +0.0,1.0,0.0,0.0,0.0,0.0,0.0 diff --git a/fixtures/owkin/datasamples/test/0024903/IMG_0024903.jpg b/fixtures/owkin/datasamples/test/0024903/IMG_0024903.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6525fccea2e6b6f103db50a1fd6606cbefa55c3c GIT binary patch literal 273349 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

    9u+ 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�dAUKaTh0Om&``n%tg<*^^cg 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 OP9DU4L0Wc*x-8% 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

    (Z9nzgu)=9pN7$(xPAk8F5fiu_`S!YB~2+Hp%v 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≤$-M4#VIm~j8 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�}+@ zE-PFrI&}n1{jYnS{<`7mRXK@Exr>$#e0_FsP6#UyGLIep<+k6zV%Nczeq`T!?*MQn z_TGC8Q0$0cV1aA&m)jUCC-E4gP}qf$GA^DtxAt++fb%13dgJ7%rXDrb{BNhRg{s!0 zQJB>dIWca$9-VvRcs(^bh!$yv>FoJz1iYkb02?1no;Tlp_P-HnINEB2Z2a5kK>|8H z9YIoq6y{9Luek(mZ!U4E=UmlwL}|IVQviRb<-Z1QZVIxhfVrLR*4(gu%`Dkq&a*vt zA8Zd>3R1}+nTY%Tn{GFbyGO4?B&etYOR?nP`3<7+%Lhv(BcDw@adog&=oTSlKm$=A z#DN4~>ucg=LQ?9Y2WJ@07)_j(;pb_*al&=e*5FPsx+WVhO2;? zBXcvwr|n_vV3JMGqj<)@#ySyVNN*nxQZNnrrxsx#fg}^tsp+uf5^z-ah=~wG3Ahq% zzgWX`=(1Iri9-@(5)FexShR1c#p+iS6LLfk%x@Qozaswt)^NZ;X%p1oYc5Mb78_u* zO{vSw#+^j(>q#K=w*!BCe58O00%PlesHZ7Ol3ApQ2a|067@171GNU#cL|j4Sf-NGz zi^c?0Qj$_y+CHtZ-vLU=aSS;PUE1;EI2lt$~18=4!q{

    6%i(7L0{?}OwUctzT+IB!=jLKp73zwmTr#L zaQeCAan;oA3#rL>{{T_{0OCi}62C@V0SH7y#0~^VnUlX;{cu&OzyOAuees;--1zes z)%nlk5V4mnl&Fwon|fvj{{U~S{RTTpE~n6V{yBNzYN(P)1-uFTV0}wV3sF9s?Iz=E zlXC|C_;jgF1&-`7*CIvmBCqE|Xcsm+PTzPiBHdy}GSwCcDsle+Xbrcqjb~Q>08hpb zWtnrXGpR`;RDtr7Bn?E)$8p7=0fwkhQosr?eFNRc=Ki?BSaRfpt2p{$mXjfp7D9{? zqo`?^Fd|Ityqk;l#Y%KikQg&V$$p%-x8EG8#HhG-cCdmsU_X5r+?;PK(y{_A1w~LG zOi1217yCiOAQ2AxLttfAV(}*6?SEVtVwo+3jV8b-+T}gW$?SiS!u6&PA?R==C^-Z; z9NPsGezuvg`D`bzwh-y*fE1;RjSi=86MsE%0+!HPi~^K_0D%O}$G3Aa+Z+i4PGSDo z`83LDcA?yua$TemF=N&n0<$;JlrKyLDKHX~vF|fz>u$aFv;q#?wDx?kT4*T>2jy4< zhPi9<@FBLwb5mTFmQ2c&NCMUb?-6_6_ZUbzR02y2@4vrte5y#Z25XC31Aoj3QF+xQ zgqs7@M&MZc#7}%XOr#(wQmL11<)3Z+Ve^!&J(!0s8J;A`oo05xO5D*-%A6nxIz_oK zIDvnzIgO$?3&!~d_SXQdcN2sKaRDtT=Mc@E7-qW{CO;-|X z**QV-65{96pC`ckH3AKrS!s@kuQ2 zTl@T+W&RhvGloV(3iyLkX@izi-1N$2E)IzFJ3Z{G65<|EU#Eztkaf;MaoeJ>L>F@wS1Son>lQPCXzPjZ*|0%+LG#&MPG=N>Uf|Gam^0LBJA}<{&(_ zQa8Io+hF#tr8@{D3wl2>_QL*h`^C@-R8V9C`H~cDbtnRNn+S_>fmZl}fl_Ir5JqJ< zha&o&m~+v{V~0*sm~%004z{;F?HK1SqNyuF(Wn`^M#Vi-?l%Lp;)f4XrBo$JQ%_g7 zlU{kt;FT&RP8g z_G6DV#8t|ok@6__i`mOr`dR182a`&Lrs*L`KQSU?Z)p|->HPk!@cLvDvH=rgyJ%0g zZLo^V9KeF!I<>E^*db3+hE?S}w1@!!E0Cx%I>*~<>~N^bNz$MgLQA!rkp-qNIx#ru zLWs-*gC^dB>^GLz3{>w^=rCklf)pSob_2QoTgEnpg9%TA_3)ed?}6&t`}fNhP?nw{ zK{|q9q<&#-{+s^*OW@28&24{Z-|dgHW$$eN0E=LYRt zKQOks>9nwcYeo}MDo{M$$CS$-4uD~Jx$y4+8a-1ZpRC2r_ZQmO24a<}Ah(QP!wn|G zp!2ue2HUGc$QqC*(h{Np6A}6o7a}*9#VRV!hg_d>?!?EBTzrsOj2V+ZN5lfDl&qmf zNF*DZ83N)tv_-eZl%ynp23LLMx;?R?z+La5VdCFx5=#iE-7*Q1p(FqW#2a_C^VfV1Lc(IE7Sl#n{j=BFqr49tZ+3ZrP8ou0>#^FfOqA)W9U`j-@FdHN81C} zn57|P%CB&uEG7X+{>7)hKFqNM&q43+zBUlxOL$;=`Gp$Pvb3cuQc6m_DI^b+EnBFG z*xu8On$(n&nM|pMUC)Op+T8KnjdL9@?8XvvIx1%hl-Wtu2T$Zz5N$Gk);N#F0Xa!I zjB{q)n*Dm>j}Kg;6=2MMy!rL@2y)PYEe$H13&^(P(nY-RzC{vCK{xW!81nqS zBzrn&$OIU<^#WjiS)QVxP+kW3?_#{bG4h=}r>~r0a;~|j)}*R$ z1QG!TVn`zQGJ2e3SE5-A;!0S#xpvkk%J_DjC8Y`M#zpF<0q)Uza^^S3dIlPBorKu? z9pDb5jzQxXND3em2gc7f_v?Z#zChtnv%X@JYk1L{%O?nK#F01555;KX#m zlU-{Bk=}L#UVcIU01t=LNTdRLukxFSlL6hpA@q5`=c?QVL>cxo5y0SoayY>X)Sv{0KQ`EGQZKp?dyh=Qn2C-!7xBDL70-GBkKog!wNvCl1iBGsFu@l z&})QhaV)0QHyb=$Zx-j%6@C>yWCEQq1&I2X24wZ^afwwZfUpx)^BK5pj+dM+y7|E+ zB!Le5_-fkT#Nm>Toe2rjLah=fbNvAywjHCxWk~NkJn}9<1D`|S_)SZa$!%HrdUW)| z6&9AaDPv(C?Rx`0L=Te^brI3GhmBWQb;NKwLQDho zzis>2alQjqx(Dj%1|7Lh7@~!hWh1(#DmzArGhysuGOIMXMx_Wa2qIwI4#4+_5-^$K z2~!;}0z3ziX^?s1f+&V8=3r0N+S1d|HU&LW+p#ts2@qApM8|VDGFBEK+TvmPkT$`> zLKv3{&@pJcFldY46c&WZgK{o5j>C?Jt_p$!zuyd@V>AA!a9yn)lYDn+FbYUBrV;{e zJ${?_{V>>CK)!%$qjKef_TeN1NY>-*{{Ws>$ImDDNdX5?JIoIA)=%4O&JwRFZQOk^ z@vfB+RA4(^<+*-*F=~ONm3*Q~l5IPM9&Z+de)s7;955;kCEu&~U-veGr9z^XNG49K z^Wmg;+e~OQRE>FPD@p4R2dwkBBYxjpSVbfXNd)}2(@pnwv;GmNrXAa-!sH0w!^4$I z#*(F}DF8>zne`2b)IR?J-SD+&8D2k6n0@_m+G+$DlP8y^?|?7UuEZv8wDpaECN2Eq z0YWn^vT>4ez6}}KfR~1b*Xw=uVWtbwd&dympjVK5JjMk_B}7Y_x-lVRZY^w05xDE&}p&K?SUG|uufLLhez=n z-SnvLRvHCK0FV!JdxZyq=9?&m@yr2nBnUG1N zt_+?TL=5w@PVW{Pb-)*1Ai3M7htKvn?N^riRizqEn6}&7c`57Z2b=GW{{U{n0rEd@ zV`Gd{uIkF=_F@_|ECGTX1F*bdMyD)wYao&VGbC_&U!eM4CkI6x27L^+dO^CNk8QguwEAaFZv?LJ8E=QUF0Ll8dt`l8k1u4=CYVn}~$Y`b zPmu21&%Yb>!2w{PZyIcI!WvMM7VESP$==^v+Y?GurI3*3KAipeV~ftig~ zgcjOQsF_ldkeG;>R{KuJv>V44O^k>hZhiaLbkjZN&XLml8y^E4iEJz?y=|x{+Ehdm zsRI3o;B7z47)l)5sdw?`t{GsYi3Og_)9(KOTnEha73eEFs3^cvjOrT!2ch}Dort|VKg$yea{iFxW`26$*auZsqI4v} zQ^bM@xg>PF?|#@>bwMlzo&C2g2qnI4ZO_ZY3l;CUpsr9s7gB`sAQ9CdT2DL96yg)x zC5#AgCe!u1H>NfiMxssIo)qh|CDNu8X666~W6%*kskkEh;UnBoK<8)cdwTSEz(@pw z{RtN2Ztcqpm06)vODZ~4w4KP>&?IdgcIQez>i8;A#cb%AcVvR;*A41ZFdVu2krqZ9GkPKmu?h#Q; zqRJO6@6nrXQgBKs$(X4jMKaF9Z9khCz!0}kzcWUyNrj}FE(gq;7$A^F_U70@RO|MM zT3x|#4zO-*q(>_ZAHIZup^(d|fj^jt;1Y0C zR-JK{uXT1%A&OiwXIGs71Zw#DomHc{WCG;c4<M``RYp*@TNiYLnh!LP%=?kPg%$FbQs!76%fowoN0L;knc~GlR3TbW zqLE^3H-ZJe+xK3TZYP4MDJjYnd#c+nBIET-o7m%3lqw)CCBO$X+c%rowlz9h;pB#b zf>xy1%p{R%99rOwx^gk4wu%VZm-~ zY(OgCN{LX_eM$h_j!yt;=p>HtajMm7DJ4Nx0iY;`BFFZD(+mzCnM#!@U~Z?kC^Nma zwfU)6#3YSmE(VpR*56464Xh0B6WB+ol>-K};n@h&`6!l(vxLC zxI6E>THh|XKQGE9-V4Nj#&LjvB%gfnB~^|tQsgKPl4)vyM?vTCNm1kY?QV z=F#MEfI!~(vrk@7e5Dz? z_Qd1G8b`e*&zYZHj)&W}2DBACyR@@yqv>a{z77huo(9OTZY|@{J!{HsH%cW2?$0*daqXLgS7E; z1oaBO;(B)oDyj;KSdaBl{as^0gHlVV7`eE8G1;b6=}w=t&H0bhZO+!m3JS}9_q*)g zxMfvFRw)cMcIyqVGlI?2!3kJ55C=}ALAB)D9~vZo$Y{a3Z?69UwiH!T6Kh&Vr{433 zU&%fo>Tb%7piBufxcd)z9O9=8DWoz4Bvu;nW1S>1L0QpQ3#oxjkoN{aict4kG zOQ)6IDvepP5D2Tfmv{eWLY71sPEZCgGe97aC2X*j}ortINrC zw-mGzv%JU`gS6V;XxcC{TD>w!!00#P2Huup}Om%lXtL%1{q3SzE%kV=K8#wY!29!w7LjMLA*dBG?D(UckKsb zbAnQ!dqkv$6FmVobJF8m;B^*;PE(sGBWG|&G8x`|FlbWhZcUU(Bo5OcszA9Th#Sc` zq^cf~RI+!HG963u(4KVu-e)vS15~fg_$cJap+eRG~phA_{f0 z>t~CRh1bN2fdvK9n-ZUx%eW=O7aZB~Wp&jJq=b?Pk+;no&7-OQxY6Qrx>;L0jeWO{ zCRGHjM0c|v0V7{_jB`m$ zlBB4tmnIm)54`J#sVOXs-Oz^$P?Dz%9CbV5yDvI-h>a%P-Xiwr?anlXsJ@o>IAxRr zgu$|u%C|rocXyU%!Fpm8EOimEJ!I{?@!Om{g;^$VK4#cjp-@OxS2~hN=^X=Y;TSH% z0bmd>y@Gz$1Mi1Y9J96on2k;*Gz)i4fJvCW$q{(8N53CK@~Ej-00FD`F$~52lNj!G zZ|Q<`6iu|SR5XA=;LMBjJCklEcgGVzQ&qtq#5GvST+GIUVeZ&*rAS%=MZg5y z$nDdcfjzdzS5Yn9Jp^ya>C^U6N(Deopf{ZR^u(@FHeK`5tstPb;#CB$NYbc->KhZv zK-w;%fl+tgNqFaurCD%3p$#D3Zjd9t?CL7S5y*Zw*O=uF*eW69Z!Xi<6j*s7 zM4J*%6SQ6;@PFHE6s+ZScb(e637sYR?bjVEQ4NFC^}u|pgv4A)QHcklf1GWBD2X;0 z6+ztv_bk?y4>RHS!TK7ovL<5Cl?ft2o9)+|4r~G4I)Q_TonL-fO1UoS4W}z=ZvrfL zI4)}2Po_3AxRE`lo!sdJ_o=-Z$zlKrtM|a1SdA>nuQEBUmrgZ#6;Wsm` zKw5y>eI{bzBoPAE{{U_ADzdxRNDO7-1KJ;{v%Z+$dhYz70{rm0DiZ2~0+X!zhzDWR zpV>S|d@hm{GXOccZidgeu)x%!U?sVe;by=r&bg!|K`I0{B#>n5>^AHF03r_*3oE;3 zmx(f6zb<_7gn}-ozwNyH(-~%QUR-#U7&j>Z_4z>J_M2E?e$2b6FU~`KIt*(H_1TaK zP(tMCw128D0gHAq!L{wfOz9)1*VC>(#$}vl8a&Tg)JXvD2PO=~tt1Q1_`@_eqk3Sp z%r@HY`1Q+naS?09t!Os(?TLr}qB^JRih}+J=y5!eRNc?2Lc97-{eHMI@8S12`9Jg& zbp}0g6LxjLEHuOmTTa;eknf(O{{Yt*;r{^XsOvv`5uyO4asl*>@3_AGdBqj!&HmUO zQhP>n&SB!;z9>8Zs?r1k(Atko3~*bnw7IAeJX#BcS&)W7N{ z$NvCn!8nhZKlcxy$JLFu@nrdEkP!z;WJxo}F^*IK(Beq|kg7~t&I`8Bt6_>n<+-wT z!OBoPptJ!$;M{YvlHVFi-Jxpy{9o;ZgTgU7%JqP`C`+xkY!!-Ux z^u`zS9}lJ(6b6%F#~tv(>^k5o`G4|1Q;3)+T*;YD=lD$NgjHBirKSPR{;z4A{ z2h^>=KbO82_=J>$BOJv@5ca65jV3GV)4mBHb^K{3JrU(B3F#;4CKjJY; zfhLkkE_>2v^&DM&2rLj%k^wLZL=QpQ*2Am~3NAlgKmE!4oDYU4v_Nvj$(x*pdf^(q z2t$h~LQ;JfN zKUwRF&wvpi0Cgtuefr^br8(Jy0Re|E$@9n5uAlo){?mdKX-<%IiPWJmI$$)?l2+*k zMZh{>RsLW({{Z^G*9`Q4X%^X5?S3%#4wSux_8X@GA9M9MVnv&^w*FYRObLOf-xKP7 zuD^U#e&lx&d;8<+fJ6;+>5Nf5LqI;q25ATI=bK^FeEuK* z0Co`KNr2^_?S=|({{WO>)fNPZG4;UkVXx2GHo=KKkuNM~#{;RSkJ}woOq>2u{{ZEL zD-)G6epMUl=5V>!kYeNf8>92f>9?jCgOklP8?7DGyec_`ixA-61xi# z7VdFLA1LwqoM#ga$NvB?{{SI{xSI~2agHzK9Y6iB&6g9T-|{Q}0L0^{`A3h`;T4|n zPWkv+_d@K_hLy^G+bw`A_}7d^1b_qPidb!wR_| z2C*^$^>claBlp1mA94QxaQ^_@FitPzS5*D6q^ITo0OCJ%q;vh6BWZ)F1YrrVmEw>VEhn$NeBUh5q9iAM^($Exd*^`q$K8JxBdQd6GYDW|zv3 z53V$ym~|Ld%}Fj?lX3f}`k%S$hOlJ+0M$=J^i~n;ly$jtwC-@dYt$NM1JO8goz>KR z0s7z-a+TzppZa}IQHXp=F*^OR#r((KgBjjxrAfK6l@~VkBNG%!T$B3!0dFlZ;(*Fy zZ>|6|qZI~B%7n?Cm5wBwf=$)0Oe(L}{{W5_9wep7B+Qc}+|K8&97p{F;r{@<<0|=& zhtnD6YEPcKn=JreZ<}tICNqS$)O^&5F*`|()sM0E5Od;u#fi6+fBeuez6noX557PD E*#x&*HUIzs literal 0 HcmV?d00001 diff --git a/fixtures/owkin/datasamples/test/0024904/LABEL_0024904.csv b/fixtures/owkin/datasamples/test/0024904/LABEL_0024904.csv new file mode 100644 index 000000000..8f42c719c --- /dev/null +++ b/fixtures/owkin/datasamples/test/0024904/LABEL_0024904.csv @@ -0,0 +1 @@ +0.0,0.0,0.0,0.0,0.0,0.0,1.0 diff --git a/fixtures/owkin/datasamples/test/0024905/IMG_0024905.jpg b/fixtures/owkin/datasamples/test/0024905/IMG_0024905.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d9e6460b2ae511f5250de0098d701a990bb7a08 GIT binary patch literal 277965 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 SJag62Us22UuRZIYzyH~P>e({@ literal 0 HcmV?d00001 diff --git a/fixtures/owkin/datasamples/test/0024905/LABEL_0024905.csv b/fixtures/owkin/datasamples/test/0024905/LABEL_0024905.csv new file mode 100644 index 000000000..ff746af51 --- /dev/null +++ b/fixtures/owkin/datasamples/test/0024905/LABEL_0024905.csv @@ -0,0 +1 @@ +0.0,1.0,0.0,0.0,0.0,0.0,0.0 diff --git a/populate.py b/populate.py index f2d7aa154..10270a0ca 100644 --- a/populate.py +++ b/populate.py @@ -21,12 +21,12 @@ def setup_config(): client.create_config('clb', 'http://clb.substrabac:8002', '0.0') -def get_or_create(data, profile, asset, dryrun=False, register=False): +def get_or_create(data, profile, asset, dryrun=False, local=True): client.set_config(profile) method_kwargs = {} - if register: + if not local: method_kwargs['local'] = False method = getattr(client, f'add_{asset}') @@ -135,18 +135,18 @@ def do_populate(): 'data_manager_keys': [data_manager_org1_key], 'test_only': False, } - train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True, register=True) + train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True, local=False) else: print(f'register train data on datamanager {org_1} (will take datamanager creator as worker)') data = { 'paths': [ - os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024306.zip'), - os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024307.zip') + os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024306'), + os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024307') ], 'data_manager_keys': [data_manager_org1_key], 'test_only': False, } - train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True, register=False) + train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True) #################################################### @@ -165,8 +165,8 @@ def do_populate(): print('register test data') data = { 'paths': [ - os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024900.zip'), - os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024901.zip') + os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024900'), + os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024901') ], 'data_manager_keys': [data_manager_org0_key], 'test_only': True, @@ -178,8 +178,8 @@ def do_populate(): print('register test data 2') data = { 'paths': [ - os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024902.zip'), - os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024903.zip') + os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024902'), + os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024903') ], 'data_manager_keys': [data_manager_org0_key], 'test_only': True, @@ -191,8 +191,8 @@ def do_populate(): print('register test data 3') data = { 'paths': [ - os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024904.zip'), - os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024905.zip') + os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024904'), + os.path.join(dir_path, './fixtures/owkin/datasamples/test/0024905') ], 'data_manager_keys': [data_manager_org0_key], 'test_only': True, From 1404bd036218b3ce2035efdefd5b8654e3aa5e50 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 22 Jul 2019 15:00:31 +0200 Subject: [PATCH 161/457] Add comments --- substrabac/substrapp/utils.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index d96b33a7e..19ec53700 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -46,17 +46,22 @@ def store_datasamples_archive(archive_object): logging.error(e) raise e - datasamples_file_hash = compute_hash(content) - datasamples_path = path.join(getattr(settings, 'MEDIA_ROOT'), - f'datasamples/{datasamples_file_hash}') + # Temporary directory for uncompress + # We take here the hash of the file content to have a common unique id + # but we can take a uuid instead. + datasamples_uuid = compute_hash(content) + tmp_datasamples_path = path.join(getattr(settings, 'MEDIA_ROOT'), + f'datasamples/{datasamples_uuid}') try: - uncompress_content(content, datasamples_path) + uncompress_content(content, tmp_datasamples_path) except Exception as e: - shutil.rmtree(datasamples_path, ignore_errors=True) + shutil.rmtree(tmp_datasamples_path, ignore_errors=True) logging.error(e) raise e else: - return dirhash(datasamples_path, 'sha256'), datasamples_path + # return the directory hash of the uncompressed file and the path of + # the temporary directory. The removal should be handled externally. + return dirhash(tmp_datasamples_path, 'sha256'), tmp_datasamples_path def get_hash(file, key=None): From e4d1deb75aa0b0d31d3432fe5fae291931545127 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 22 Jul 2019 15:47:57 +0200 Subject: [PATCH 162/457] Use uuid instead of compute hash --- substrabac/substrapp/utils.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 19ec53700..c26eb9412 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -11,6 +11,7 @@ import requests import tarfile import zipfile +import uuid from checksumdir import dirhash @@ -47,9 +48,7 @@ def store_datasamples_archive(archive_object): raise e # Temporary directory for uncompress - # We take here the hash of the file content to have a common unique id - # but we can take a uuid instead. - datasamples_uuid = compute_hash(content) + datasamples_uuid = uuid.uuid4().hex tmp_datasamples_path = path.join(getattr(settings, 'MEDIA_ROOT'), f'datasamples/{datasamples_uuid}') try: From 2e3dfe2ff0390e85dbf7dc3005b4020a86c5b87e Mon Sep 17 00:00:00 2001 From: Camille Marini Date: Tue, 23 Jul 2019 11:40:12 +0200 Subject: [PATCH 163/457] modified codeowners to match the team orga --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3b61902ed..f8ec605f1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,4 +2,4 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @camillemarini @GuillaumeCisco +* @GuillaumeCisco @Kelvin-M From 32fce7d1eb8d9748687aaeb67b25db3ae306523c Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 24 Jul 2019 10:28:25 +0200 Subject: [PATCH 164/457] tests: update generate script and rerun it --- substrabac/substrapp/tests/assets.py | 251 ++++++++++++------ substrabac/substrapp/tests/generate_assets.py | 19 +- .../substrapp/tests/views/tests_views_algo.py | 4 +- .../tests/views/tests_views_datamanager.py | 2 +- .../tests/views/tests_views_model.py | 14 +- .../tests/views/tests_views_objective.py | 2 +- 6 files changed, 195 insertions(+), 97 deletions(-) diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index 24c6fd30e..c4f0a4e60 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -11,7 +11,7 @@ "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" }, - "owner": "fba9c2538319fe2b45ac7047e21b4bc7196537367814d5da7f0aae020d3be5f7", + "owner": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", "testDataset": None, "permissions": "all" }, @@ -27,13 +27,14 @@ "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" }, - "owner": "fba9c2538319fe2b45ac7047e21b4bc7196537367814d5da7f0aae020d3be5f7", + "owner": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", "testDataset": { - "dataManagerKey": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "dataManagerKey": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", "dataSampleKeys": [ "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf", "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a" - ] + ], + "worker": "" }, "permissions": "all" } @@ -52,7 +53,7 @@ "hash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", "storageAddress": "http://testserver/data_manager/615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7/opener/" }, - "owner": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "owner": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "permissions": "all", "type": "Images" }, @@ -60,15 +61,15 @@ "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "description": { "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", - "storageAddress": "http://testserver/data_manager/615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7/description/" + "storageAddress": "http://testserver/data_manager/82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2/description/" }, - "key": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "key": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", "name": "Simplified ISIC 2018", "opener": { - "hash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", - "storageAddress": "http://testserver/data_manager/615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7/opener/" + "hash": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", + "storageAddress": "http://testserver/data_manager/82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2/opener/" }, - "owner": "fba9c2538319fe2b45ac7047e21b4bc7196537367814d5da7f0aae020d3be5f7", + "owner": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", "permissions": "all", "type": "Images" } @@ -86,60 +87,60 @@ "hash": "b9463411a01ea00869bdffce6e59a5c100a4e635c0a9386266cad3c77eb28e9e", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/description/" }, - "owner": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "owner": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "permissions": "all" }, { - "key": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", - "name": "Logistic regression", + "key": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "name": "Random Forest", "content": { - "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, "description": { - "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/description/" + "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" }, - "owner": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "owner": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "permissions": "all" }, { - "key": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "name": "Random Forest", + "key": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", + "name": "Logistic regression", "content": { - "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" + "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", + "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" }, "description": { - "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" + "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", + "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/description/" }, - "owner": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "owner": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", "permissions": "all" } ] traintuple = [ { + "key": "e0db5d9206a9049dd57736943e6c79b7b0b5d369971725284bada0ad10b6d2e4", "algo": { - "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "name": "Neural Network", + "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" }, - "creator": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "dataset": { + "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", - "perf": 0, - "worker": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426" + "perf": 0 }, "fltask": "", "inModels": None, - "key": "c4e3116dd3f895986b77e4d445178330630bd3f52407f10462dd4778e40090e0", - "log": "[00-01-0032-7cc5b61]", + "log": "[00-01-0032-5246056]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -154,25 +155,25 @@ "tag": "My super tag" }, { + "key": "e60b3a73927eda5ccd94620693e3dd056dee289bce0a3a0865b03b3359ab0ce4", "algo": { - "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", "name": "Logistic regression", + "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" }, - "creator": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "dataset": { + "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", - "perf": 1, - "worker": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426" + "perf": 1 }, "fltask": "", "inModels": None, - "key": "3979576752e014adddadfc360d79c67cdccb0f4bae46936f35ce09c64e5832c8", - "log": "Train - CPU:173.81 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB; ", + "log": "Train - CPU:89.48 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -181,8 +182,8 @@ } }, "outModel": { - "hash": "592242f9b162178994897c5b8aa49450a17cc395bb9bc9864b830a6cdba6a075", - "storageAddress": "http://testserver/model/592242f9b162178994897c5b8aa49450a17cc395bb9bc9864b830a6cdba6a075/file/" + "hash": "72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080", + "storageAddress": "http://testserver/model/72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080/file/" }, "permissions": "all", "rank": 0, @@ -190,25 +191,25 @@ "tag": "substra" }, { + "key": "689990aac749b241b080fb6ee2c73aa30f442cb9056bd9803e75a7606dcdfb91", "algo": { - "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", "name": "Random Forest", + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, - "creator": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "dataset": { + "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", - "perf": 0, - "worker": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426" + "perf": 0 }, "fltask": "", "inModels": None, - "key": "c6beed3a4ee5ead0c4246faac7931a944fc2286e193454bb1b851dee0c5a5f59", - "log": "[00-01-0032-139c39e]", + "log": "[00-01-0032-c370fb8]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -226,28 +227,28 @@ testtuple = [ { - "key": "b7b9291e5ff96ec7d16d38ab49915cbe15055347bb933a824887f2a76fb57c9a", + "key": "915fdcc3406b6bf149a9d178f6e61d6c87a057a9ed8c10b369422b74ce4d3394", "algo": { "name": "Logistic regression", "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" }, "certified": True, - "creator": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "dataset": { - "worker": "fba9c2538319fe2b45ac7047e21b4bc7196537367814d5da7f0aae020d3be5f7", + "worker": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", "keys": [ "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" ], - "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "openerHash": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", "perf": 0 }, - "log": "Test - CPU:179.46 % - Mem:0.09 GB - GPU:0.00 % - GPU Mem:0.00 GB; ", + "log": "Test - CPU:0.00 % - Mem:0.00 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "model": { - "traintupleKey": "3979576752e014adddadfc360d79c67cdccb0f4bae46936f35ce09c64e5832c8", - "hash": "592242f9b162178994897c5b8aa49450a17cc395bb9bc9864b830a6cdba6a075", - "storageAddress": "http://testserver/model/592242f9b162178994897c5b8aa49450a17cc395bb9bc9864b830a6cdba6a075/file/" + "traintupleKey": "e60b3a73927eda5ccd94620693e3dd056dee289bce0a3a0865b03b3359ab0ce4", + "hash": "72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080", + "storageAddress": "http://testserver/model/72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -264,29 +265,113 @@ model = [ { + "traintuple": { + "key": "e0db5d9206a9049dd57736943e6c79b7b0b5d369971725284bada0ad10b6d2e4", + "algo": { + "name": "Neural Network", + "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" + }, + "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "dataset": { + "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "perf": 0 + }, + "fltask": "", + "inModels": None, + "log": "[00-01-0032-5246056]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": "all", + "rank": 0, + "status": "failed", + "tag": "My super tag" + }, "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "permissions": "", + "status": "", + "tag": "" + } + }, + { + "traintuple": { + "key": "e60b3a73927eda5ccd94620693e3dd056dee289bce0a3a0865b03b3359ab0ce4", "algo": { + "name": "Logistic regression", "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", + "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" + }, + "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "dataset": { + "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "perf": 1 + }, + "fltask": "", + "inModels": None, + "log": "Train - CPU:89.48 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080", + "storageAddress": "http://testserver/model/72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080/file/" + }, + "permissions": "all", + "rank": 0, + "status": "done", + "tag": "substra" + }, + "testtuple": { + "key": "915fdcc3406b6bf149a9d178f6e61d6c87a057a9ed8c10b369422b74ce4d3394", + "algo": { "name": "Logistic regression", + "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" }, "certified": True, - "creator": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "dataset": { + "worker": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", "keys": [ "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" ], - "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", - "perf": 0, - "worker": "fba9c2538319fe2b45ac7047e21b4bc7196537367814d5da7f0aae020d3be5f7" + "openerHash": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", + "perf": 0 }, - "key": "b7b9291e5ff96ec7d16d38ab49915cbe15055347bb933a824887f2a76fb57c9a", - "log": "Test - CPU:179.46 % - Mem:0.09 GB - GPU:0.00 % - GPU Mem:0.00 GB; ", + "log": "Test - CPU:0.00 % - Mem:0.00 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "model": { - "hash": "592242f9b162178994897c5b8aa49450a17cc395bb9bc9864b830a6cdba6a075", - "storageAddress": "http://testserver/model/592242f9b162178994897c5b8aa49450a17cc395bb9bc9864b830a6cdba6a075/file/", - "traintupleKey": "3979576752e014adddadfc360d79c67cdccb0f4bae46936f35ce09c64e5832c8" + "traintupleKey": "e60b3a73927eda5ccd94620693e3dd056dee289bce0a3a0865b03b3359ab0ce4", + "hash": "72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080", + "storageAddress": "http://testserver/model/72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -298,27 +383,29 @@ "permissions": "all", "status": "done", "tag": "" - }, + } + }, + { "traintuple": { + "key": "689990aac749b241b080fb6ee2c73aa30f442cb9056bd9803e75a7606dcdfb91", "algo": { - "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", - "name": "Logistic regression", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" + "name": "Random Forest", + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, - "creator": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426", + "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "dataset": { + "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", - "perf": 1, - "worker": "2cb13d299b337fae2969da1ff4ddd9a2f3004be52d64f671d13d9513f5a79426" + "perf": 0 }, "fltask": "", "inModels": None, - "key": "3979576752e014adddadfc360d79c67cdccb0f4bae46936f35ce09c64e5832c8", - "log": "Train - CPU:173.81 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB; ", + "log": "[00-01-0032-c370fb8]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -326,14 +413,24 @@ "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, - "outModel": { - "hash": "592242f9b162178994897c5b8aa49450a17cc395bb9bc9864b830a6cdba6a075", - "storageAddress": "http://testserver/model/592242f9b162178994897c5b8aa49450a17cc395bb9bc9864b830a6cdba6a075/file/" - }, + "outModel": None, "permissions": "all", "rank": 0, - "status": "done", - "tag": "substra" + "status": "failed", + "tag": "" + }, + "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "permissions": "", + "status": "", + "tag": "" } } ] diff --git a/substrabac/substrapp/tests/generate_assets.py b/substrabac/substrapp/tests/generate_assets.py index ea0447a02..40dd7bb1d 100644 --- a/substrabac/substrapp/tests/generate_assets.py +++ b/substrabac/substrapp/tests/generate_assets.py @@ -1,9 +1,10 @@ import os import json -from substra_sdk_py import Client +from substra import Client -dir_path = os.path.dirname(os.path.realpath(__file__)) +dir_path = os.path.dirname(__file__) +assets_path = os.path.join(dir_path, 'assets.py') def main(): @@ -14,16 +15,16 @@ def main(): client.set_config('owkin') assets = {} - assets['objective'] = json.dumps(client.list('objective'), indent=4) - assets['datamanager'] = json.dumps(client.list('data_manager'), indent=4) - assets['algo'] = json.dumps(client.list('algo'), indent=4) - assets['traintuple'] = json.dumps(client.list('traintuple'), indent=4) - assets['testtuple'] = json.dumps(client.list('testtuple'), indent=4) + assets['objective'] = json.dumps(client.list_objective(), indent=4) + assets['datamanager'] = json.dumps(client.list_dataset(), indent=4) + assets['algo'] = json.dumps(client.list_algo(), indent=4) + assets['traintuple'] = json.dumps(client.list_traintuple(), indent=4) + assets['testtuple'] = json.dumps(client.list_testtuple(), indent=4) - assets['model'] = json.dumps([res for res in client.list('model') + assets['model'] = json.dumps([res for res in client._list('model') if ('traintuple' in res and 'testtuple' in res)], indent=4) - with open(os.path.join(dir_path, '../substrapp/tests/assets.py'), 'w') as f: + with open(assets_path, 'w') as f: for k, v in assets.items(): v = v.replace('owkin.substrabac:8000', 'testserver') v = v.replace('chunantes.substrabac:8001', 'testserver') diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index 68c3162be..df7b30284 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -91,7 +91,7 @@ def test_algo_list_filter_dual(self): mquery_ledger.return_value = algo search_params = '?search=algo%253Aname%253ALogistic%2520regression' - search_params += f'%2Calgo%253Aowner%253A{algo[0]["owner"]}' + search_params += f'%2Calgo%253Aowner%253A{algo[2]["owner"]}' response = self.client.get(url + search_params, **self.extra) r = response.json() @@ -130,7 +130,7 @@ def test_algo_list_filter_model(self): mquery_ledger.return_value = algo mquery_ledger2.return_value = traintuple - pkhash = model[0]['traintuple']['outModel']['hash'] + pkhash = model[1]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' response = self.client.get(url + search_params, **self.extra) r = response.json() diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 8d585b464..87d9545c0 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -101,7 +101,7 @@ def test_datamanager_list_filter_model(self): mock.patch('substrapp.views.filters_utils.query_ledger') as mquery_ledger2: mquery_ledger.return_value = datamanager mquery_ledger2.return_value = traintuple - pkhash = model[0]['traintuple']['outModel']['hash'] + pkhash = model[1]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' response = self.client.get(url + search_params, **self.extra) r = response.json() diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substrabac/substrapp/tests/views/tests_views_model.py index d53d15d1c..e5dbf2f5e 100644 --- a/substrabac/substrapp/tests/views/tests_views_model.py +++ b/substrabac/substrapp/tests/views/tests_views_model.py @@ -74,7 +74,7 @@ def test_model_list_filter_hash(self): with mock.patch('substrapp.views.model.query_ledger') as mquery_ledger: mquery_ledger.return_value = model - pkhash = model[0]['traintuple']['outModel']['hash'] + pkhash = model[1]['traintuple']['outModel']['hash'] url = reverse('substrapp:model-list') search_params = f'?search=model%253Ahash%253A{pkhash}' response = self.client.get(url + search_params, **self.extra) @@ -92,7 +92,7 @@ def test_model_list_filter_datamanager(self): response = self.client.get(url + search_params, **self.extra) r = response.json() - self.assertEqual(len(r[0]), 1) + self.assertEqual(len(r[0]), 3) def test_model_list_filter_objective(self): url = reverse('substrapp:model-list') @@ -105,7 +105,7 @@ def test_model_list_filter_objective(self): response = self.client.get(url + search_params, **self.extra) r = response.json() - self.assertEqual(len(r[0]), 1) + self.assertEqual(len(r[0]), 3) def test_model_list_filter_algo(self): url = reverse('substrapp:model-list') @@ -125,18 +125,18 @@ def test_model_retrieve(self): with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger, \ mock.patch('substrapp.views.model.get_from_node') as mrequestsget, \ mock.patch('substrapp.views.model.ModelViewSet.compute_hash') as mcomputed_hash: - mget_object_from_ledger.return_value = model[0] + mget_object_from_ledger.return_value = model[1] mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, content=self.model.read().encode()) - mcomputed_hash.return_value = model[0]['traintuple']['outModel']['hash'] + mcomputed_hash.return_value = model[1]['traintuple']['outModel']['hash'] url = reverse('substrapp:model-list') - search_params = model[0]['traintuple']['outModel']['hash'] + '/' + search_params = model[1]['traintuple']['outModel']['hash'] + '/' response = self.client.get(url + search_params, **self.extra) r = response.json() - self.assertEqual(r, model[0]) + self.assertEqual(r, model[1]) def test_model_retrieve_fail(self): diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index ffd2c3b86..8ab940220 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -126,7 +126,7 @@ def test_objective_list_filter_model(self): mquery_ledger.return_value = objective mquery_ledger2.return_value = traintuple - pkhash = model[0]['traintuple']['outModel']['hash'] + pkhash = model[1]['traintuple']['outModel']['hash'] search_params = f'?search=model%253Ahash%253A{pkhash}' response = self.client.get(url + search_params, **self.extra) r = response.json() From aacfed879b8467a5ee92db3ef657d178aa51f48b Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 24 Jul 2019 16:59:12 +0200 Subject: [PATCH 165/457] Add substra path --- docker/start.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/start.py b/docker/start.py index 22db32aba..09a9bfdee 100644 --- a/docker/start.py +++ b/docker/start.py @@ -20,7 +20,7 @@ 'clb': 8002 } -SUBSTRA_FOLDER = '/substra' +SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') def generate_docker_compose_file(conf, launch_settings): From 15b04de847ffb4ad18e9dee9f804e62f2fe3b138 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 25 Jul 2019 08:45:08 +0200 Subject: [PATCH 166/457] Add label --- docker/start.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docker/start.py b/docker/start.py index 09a9bfdee..66d2f839e 100644 --- a/docker/start.py +++ b/docker/start.py @@ -55,6 +55,7 @@ def generate_docker_compose_file(conf, launch_settings): 'substrabac_tools': { 'postgresql': { 'container_name': 'postgresql', + 'labels': ['substra'], 'image': 'library/postgres:10.5', 'restart': 'unless-stopped', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, @@ -69,6 +70,7 @@ def generate_docker_compose_file(conf, launch_settings): }, 'celerybeat': { 'container_name': 'celerybeat', + 'labels': ['substra'], 'hostname': 'celerybeat', 'image': 'substra/celerybeat', 'restart': 'unless-stopped', @@ -83,6 +85,7 @@ def generate_docker_compose_file(conf, launch_settings): }, 'rabbit': { 'container_name': 'rabbit', + 'labels': ['substra'], 'hostname': 'rabbitmq', # Must be set to be able to recover from volume 'restart': 'unless-stopped', 'image': 'rabbitmq:3-management', @@ -96,6 +99,7 @@ def generate_docker_compose_file(conf, launch_settings): }, 'flower': { 'container_name': f'flower', + 'labels': ['substra'], 'hostname': f'flower', 'ports': ['5555:5555'], 'image': 'substra/flower', @@ -162,6 +166,7 @@ def generate_docker_compose_file(conf, launch_settings): backend = { 'container_name': f'{org_name_stripped}.substrabac', + 'labels': ['substra'], 'image': 'substra/substrabac', 'restart': 'unless-stopped', 'ports': [f'{port}:{port}'], @@ -177,6 +182,7 @@ def generate_docker_compose_file(conf, launch_settings): scheduler = { 'container_name': f'{org_name_stripped}.scheduler', + 'labels': ['substra'], 'hostname': f'{org_name}.scheduler', 'image': 'substra/celeryworker', 'restart': 'unless-stopped', @@ -190,6 +196,7 @@ def generate_docker_compose_file(conf, launch_settings): worker = { 'container_name': f'{org_name_stripped}.worker', + 'labels': ['substra'], 'hostname': f'{org_name}.worker', 'image': 'substra/celeryworker', 'restart': 'unless-stopped', @@ -206,6 +213,7 @@ def generate_docker_compose_file(conf, launch_settings): dryrunner = { 'container_name': f'{org_name_stripped}.dryrunner', + 'labels': ['substra'], 'hostname': f'{org_name}.dryrunner', 'image': 'substra/celeryworker', 'restart': 'unless-stopped', @@ -286,7 +294,8 @@ def start(conf, launch_settings, no_backup): print('start docker-compose', flush=True) call(['docker-compose', '-f', docker_compose['path'], '--project-directory', os.path.join(dir_path, '../'), 'up', '-d', '--remove-orphans', '--build']) - call(['docker', 'ps', '-a', '--format', 'table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}']) + call(['docker', 'ps', '-a', '--format', 'table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}', + '--filter', 'label=substra']) if __name__ == "__main__": From de16c0485a631d3561033a20acf4f83fef871655 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 26 Jul 2019 10:18:58 +0200 Subject: [PATCH 167/457] Change Postgresql docker init --- docker/postgresql/Dockerfile | 3 +++ docker/start.py | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 docker/postgresql/Dockerfile diff --git a/docker/postgresql/Dockerfile b/docker/postgresql/Dockerfile new file mode 100644 index 000000000..8935ec280 --- /dev/null +++ b/docker/postgresql/Dockerfile @@ -0,0 +1,3 @@ +FROM library/postgres:10.5 + +COPY docker/postgresql/init.sh /docker-entrypoint-initdb.d/init.sh diff --git a/docker/start.py b/docker/start.py index 66d2f839e..7f8f1c8e1 100644 --- a/docker/start.py +++ b/docker/start.py @@ -56,7 +56,7 @@ def generate_docker_compose_file(conf, launch_settings): 'postgresql': { 'container_name': 'postgresql', 'labels': ['substra'], - 'image': 'library/postgres:10.5', + 'image': 'substra/postgresql', 'restart': 'unless-stopped', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': [ @@ -65,8 +65,7 @@ def generate_docker_compose_file(conf, launch_settings): f'POSTGRES_PASSWORD={POSTGRES_PASSWORD}', f'POSTGRES_DB={POSTGRES_DB}'], 'volumes': [ - f'{SUBSTRA_FOLDER}/backup/postgres-data:/var/lib/postgresql/data', - f'{dir_path}/postgresql/init.sh:/docker-entrypoint-initdb.d/init.sh'], + f'{SUBSTRA_FOLDER}/backup/postgres-data:/var/lib/postgresql/data'], }, 'celerybeat': { 'container_name': 'celerybeat', From 951d281ebe84cf08d6d13575f0d9e7f42845a4ff Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 26 Jul 2019 11:06:30 +0200 Subject: [PATCH 168/457] Update populate for jenkins test --- populate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/populate.py b/populate.py index 10270a0ca..5dec15c82 100644 --- a/populate.py +++ b/populate.py @@ -9,7 +9,9 @@ from termcolor import colored dir_path = os.path.dirname(os.path.realpath(__file__)) -server_path = '/substra/servermedias' + +SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') +server_path = f'{SUBSTRA_FOLDER}/servermedias' client = substra.Client() @@ -354,3 +356,4 @@ def do_populate(): error_message = json.dumps(error, indent=2) print(colored(str(e), 'red')) print(colored(error_message, 'red')) + exit(1) From 59eed84260050304a56da69678075d6283564232 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 26 Jul 2019 14:41:30 +0200 Subject: [PATCH 169/457] Add downstream job --- Jenkinsfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index d770ac244..8d6697197 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -108,5 +108,12 @@ pipeline { } } } + + stage('Test with substra-network') { + steps { + build job: 'substra-network/dev', parameters: [string(name: 'BACKEND', value: env.BRANCH_NAME)], propagate: true + } + } + } } From ee2eef9d913f6b98c77f21bdef78ef307c63dc7c Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 26 Jul 2019 15:12:04 +0200 Subject: [PATCH 170/457] Change downstream job name --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8d6697197..817d85bb1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -111,7 +111,7 @@ pipeline { stage('Test with substra-network') { steps { - build job: 'substra-network/dev', parameters: [string(name: 'BACKEND', value: env.BRANCH_NAME)], propagate: true + build job: 'substra-network/PR-82', parameters: [string(name: 'BACKEND', value: env.BRANCH_NAME)], propagate: true } } From b22ef3472f052e008025377e709ce9636701d6f3 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 26 Jul 2019 15:33:14 +0200 Subject: [PATCH 171/457] Fix branch name --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 817d85bb1..64140fb10 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -111,7 +111,7 @@ pipeline { stage('Test with substra-network') { steps { - build job: 'substra-network/PR-82', parameters: [string(name: 'BACKEND', value: env.BRANCH_NAME)], propagate: true + build job: 'substra-network/PR-82', parameters: [string(name: 'BACKEND', value: env.CHANGE_BRANCH)], propagate: true } } From 2a8796d0706e0cbd24013995b86038ba20d82244 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 26 Jul 2019 16:54:20 +0200 Subject: [PATCH 172/457] Make E2E test settable --- Jenkinsfile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 64140fb10..084297c23 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,6 +5,10 @@ pipeline { buildDiscarder(logRotator(numToKeepStr: '5')) } + parameters { + booleanParam(name: 'E2E', defaultValue: false, description: 'Launch E2E test') + } + agent none stages { @@ -110,6 +114,10 @@ pipeline { } stage('Test with substra-network') { + when { + expression { return params.E2E } + } + steps { build job: 'substra-network/PR-82', parameters: [string(name: 'BACKEND', value: env.CHANGE_BRANCH)], propagate: true } From 2699f082e6c1206dc4f0938236f1f3419e4c0b15 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 29 Jul 2019 09:37:43 +0200 Subject: [PATCH 173/457] Add params --- Jenkinsfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 084297c23..11162c0eb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,6 +7,9 @@ pipeline { parameters { booleanParam(name: 'E2E', defaultValue: false, description: 'Launch E2E test') + string(name: 'CLI', defaultValue: 'dev', description: 'substra-cli branch') + string(name: 'CHAINCODE', defaultValue: 'dev', description: 'chaincode branch') + } agent none @@ -119,7 +122,9 @@ pipeline { } steps { - build job: 'substra-network/PR-82', parameters: [string(name: 'BACKEND', value: env.CHANGE_BRANCH)], propagate: true + build job: 'substra-network/dev', parameters: [string(name: 'BACKEND', value: env.CHANGE_BRANCH), + string(name: 'CHAINCODE', value: params.CHAINCODE), + string(name: 'CLI', value: params.CLI)], propagate: true } } From e8bbdc813c73f4b43dffcbfbe364759750f8c003 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 29 Jul 2019 11:02:25 +0200 Subject: [PATCH 174/457] populate: sdk calls to load config has been updated --- populate.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/populate.py b/populate.py index 5dec15c82..4fdd51206 100644 --- a/populate.py +++ b/populate.py @@ -18,14 +18,14 @@ def setup_config(): print('Init config in /tmp/.substrabac for owkin and chunantes') - client.create_config('owkin', 'http://owkin.substrabac:8000', '0.0') - client.create_config('chunantes', 'http://chunantes.substrabac:8001', '0.0') - client.create_config('clb', 'http://clb.substrabac:8002', '0.0') + client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0') + client.add_profile('chunantes', 'http://chunantes.substrabac:8001', '0.0') + client.add_profile('clb', 'http://clb.substrabac:8002', '0.0') def get_or_create(data, profile, asset, dryrun=False, local=True): - client.set_config(profile) + client.set_profile(profile) method_kwargs = {} if not local: @@ -60,7 +60,7 @@ def get_or_create(data, profile, asset, dryrun=False, local=True): def update_datamanager(data_manager_key, data, profile): - client.set_config(profile) + client.set_profile(profile) try: r = client.update_dataset(data_manager_key, data) @@ -307,7 +307,7 @@ def do_populate(): #################################################### - client.set_config(org_1) + client.set_profile(org_1) res = client.get_traintuple(traintuple_key) print(colored(json.dumps(res, indent=2), 'green')) @@ -319,14 +319,14 @@ def do_populate(): testtuple_key = get_or_create(data, org_1, 'testtuple') - client.set_config(org_1) + client.set_profile(org_1) res_t = client.get_testtuple(testtuple_key) print(colored(json.dumps(res_t, indent=2), 'yellow')) testtuple_status = None traintuple_status = None - client.set_config(org_1) + client.set_profile(org_1) while traintuple_status not in ('done', 'failed') or testtuple_status not in ('done', 'failed'): res = client.get_traintuple(traintuple_key) From fd8782001345a5949e31074fa4f595800abb954c Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 22 Jul 2019 15:32:12 +0200 Subject: [PATCH 175/457] update substratools to 0.0.1 --- fixtures/chunantes/algos/algo3/algo.tar.gz | Bin 1170 -> 1189 bytes .../datamanagers/datamanager0/opener.py | 4 ++-- .../owkin/datamanagers/datamanager0/opener.py | 4 ++-- .../containers/dryrun_data_sample/Dockerfile | 2 +- .../containers/dryrun_metrics/Dockerfile | 10 ++-------- substrabac/containers/metrics/Dockerfile | 8 +------- 6 files changed, 8 insertions(+), 20 deletions(-) diff --git a/fixtures/chunantes/algos/algo3/algo.tar.gz b/fixtures/chunantes/algos/algo3/algo.tar.gz index 8805ccf0b6c5918f6c66d369556a1f0fa6facc30..fabc8499557a3931203015c89f4c3e0e5a2dd572 100644 GIT binary patch literal 1189 zcmV;W1X}waiwFQD(>7fI1MOE^Pvb@u-e>=cQ})4*lsI-0prXpdcC(<>s!#!|QXynb z;>_&sd%bkXHTgJu_n`4hc|IqSaROy?8F?Hs>;PO!B!1%jLVbL=;5_qY>!u;laN7 zMgu$77!BhA#KZk~e>fZ-M28T?!}xIY4x%@;s>VVpQlTl56gicPXX%hE%U+OU&jPFO zHv-@HFBa2+Ny!8U`bdg0r|`hkEy%l^l8PgR$BI%^3UV=@Gd^#oze&NHF<%tr5{Lv| zdRZlkhC9p|$8S=Il;%(qUz|)n<^)w{j8oOlFk+tQ%fWuXsGmR=5R_Rn|%~KWAh+mIpw6FW8WCq zM;dEth$9~r(tDbZ8_vn6AHSY-(4?8R9zJ001jfox4?9Pm2Z)qrkfJ-1+67i%AZea; z!Hkg-Y7nI=7~ADANm4dbNwV5ai6XfB$7(_2jxLYjp5zM}Dv>j(f)20@m}DH2l+S2j zHoF*#kf)@o$g%@8m(((C$kL8Nd0o4uU8oHTnWBXZIvb>@0x7S1@ePc};3qy1p6Vs| z4yU=0GRYQvrZA5Zf5rLdYE)6RsJJ=O+E2M4=}tdsvX+}{`iwU-CwL%Lk?8tW(~erW zz70YxGRQh>9g^JB?E-jR)x%CzMu)Dg=CEy5SonK?!eGx6qK11ubL^QQ*qk~7#1!O1on$i`yqMqd$((0&&J1z@*owkWX zv~PWYIxtvU^MX7E<~(uxJjrA&iU2D{in;u2A(y|u1 zPRyrI0P3MqZRFE>$qd@T*VAWXZ<)43uh%ysj|3F68k48~! z`~Us@coYwH|9@~WaQ*+kf#dVDpMWmH`3$>0(XV^(-XQvZ6c76Cmi#CRqcHZo^RK5s zO4XZF1&b0N0Q$pfZkix$&3j9jE?A!SsFai|Msnyvkev1MOE^Z`(E$?z4WyS^6Luux0s@c*x*~u5N>(STZCjmLUiP z+M*mT5-EsO5^val-ytd4a_uC;fNWU7??t?v8_$J2BH2=e#p=y#B8sA;@fh@Xa&&0E z(a_E{#>2xA3`XN4{2opYhY$@$!|3P@M6YU9jY=v~qA8N(8I{$ObV!z_&&aW7f%W%) z0^j#9s(H?&WP$^IBzcihcwp)lhR5g#-i*m0ryp&WU7;_kyQv8Kf+uoaA)s8w2}D zV@(ZlfFKFD+)iKM#xY6xf(B-@ zi=ha4Ldue?IzTf?Ez_1P?I@JjwOiVS+Mtjrn#-WGMT#nr^13&;f$0?d*ayNBy#(Lk zG!s(BX~h=`^Cdx}7<}11a-Z*RPshmioln zim7iySE6~sY%4k)4>yOwgBZUuX;SD^aC-cLQ#5_!lx^Bt;I8v^VD`{zNUF4#19PaZ zRfVxKk+STa&JLpv;NKT#rF`vsL-CdK+fFZtx^3BPZUIqH9_WoO_@&>`g_&;KQ480% zL8wIrX=kHDl6$&a057Y0*sIFu(6!YZwyg>apYdADRToyZE@@KXZW^`Jy~Udj$rs9| zW3$}UIpe7a{1d8_zHBs!zwzZ&Y!qQKUai+w>$O!&hfWBrzl8lxxAn9{*il$gc}of! zG;=e%j&8cp8|+i9OPlami5M^5pkafa-pDE8%}N)@Ba?Xc4)pb&RLSm^*RnZfsxCIc zpL5PfW}Rbb{g#NPQmyat2)aD%#9l(W-qzHMEJa!!vvAKNm1-+t zHcMvEj=!Eh8Gg&O8-2aL6?|NHBKBK5-am`P^L|AQJ6Dh8z^4=$MdtFfL7shfnA^I*FAV|7=1q;4Eybt-1E-AoB}CSZ%GwY1wIb+hxOdFKiHJ_ zRxqzvmh`BUlq*Iu?1bi0X1#>o0~9NDEBL7Sn#E>Zu)?Uo?`SQrz)oL0)V~+?o#c7H zoSlE3eL9D}#20oh9zE~fYzASU*uPl_J@3Qm<@v8apM5&LgzJM^#X%PiYLbH+cb_;o kI5;>sI5;>sI5;>sI5;>sI5;>sIDDJ<3qhb%#Q-P(07_X!Q~&?~ diff --git a/fixtures/chunantes/datamanagers/datamanager0/opener.py b/fixtures/chunantes/datamanagers/datamanager0/opener.py index f7dbd14d2..134325b2d 100644 --- a/fixtures/chunantes/datamanagers/datamanager0/opener.py +++ b/fixtures/chunantes/datamanagers/datamanager0/opener.py @@ -78,7 +78,7 @@ def fake_y(self): """Make and return the ISIC like labels as np arrays.""" return np.eye(CLASSES)[np.arange(n_sample) % CLASSES].astype('uint8') - def save_pred(self, y_pred, path): + def save_predictions(self, y_pred, path): """Save prediction in path :param y_pred: predicted target variable vector @@ -91,7 +91,7 @@ def save_pred(self, y_pred, path): writer = csv.writer(f) writer.writerows(y_pred) - def get_pred(self, path): + def get_predictions(self, path): """Get predictions which were saved using the save_pred function :param folder: path to the folder where the previously predicted target variable vector has been saved diff --git a/fixtures/owkin/datamanagers/datamanager0/opener.py b/fixtures/owkin/datamanagers/datamanager0/opener.py index 8d54fcd65..d8c0dc6ba 100644 --- a/fixtures/owkin/datamanagers/datamanager0/opener.py +++ b/fixtures/owkin/datamanagers/datamanager0/opener.py @@ -78,7 +78,7 @@ def fake_y(self): """Make and return the ISIC like labels as np arrays.""" return np.eye(CLASSES)[np.arange(n_sample) % CLASSES].astype('uint8') - def save_pred(self, y_pred, path): + def save_predictions(self, y_pred, path): """Save prediction in path :param y_pred: predicted target variable vector @@ -91,7 +91,7 @@ def save_pred(self, y_pred, path): writer = csv.writer(f) writer.writerows(y_pred) - def get_pred(self, path): + def get_predictions(self, path): """Get predictions which were saved using the save_pred function :param folder: path to the folder where the previously predicted target variable vector has been saved diff --git a/substrabac/containers/dryrun_data_sample/Dockerfile b/substrabac/containers/dryrun_data_sample/Dockerfile index a47637b76..39a3025aa 100644 --- a/substrabac/containers/dryrun_data_sample/Dockerfile +++ b/substrabac/containers/dryrun_data_sample/Dockerfile @@ -1,4 +1,4 @@ -FROM eu.gcr.io/substra-208412/substratools +FROM eu.gcr.io/substra-208412/substratools:0.0.1 RUN apt-get update; apt-get install -y build-essential libssl-dev python3 python3-dev python3-pip RUN pip3 install --upgrade pip diff --git a/substrabac/containers/dryrun_metrics/Dockerfile b/substrabac/containers/dryrun_metrics/Dockerfile index 61a90bf85..88395c62a 100644 --- a/substrabac/containers/dryrun_metrics/Dockerfile +++ b/substrabac/containers/dryrun_metrics/Dockerfile @@ -1,9 +1,3 @@ -FROM eu.gcr.io/substra-208412/substratools - -RUN mkdir -p /sandbox -RUN mkdir -p /sandbox/opener -RUN mkdir -p /sandbox/metrics -WORKDIR /sandbox - +FROM eu.gcr.io/substra-208412/substratools:0.0.1 ENTRYPOINT ["python3"] -CMD ["-c", "import substratools as tools; tools.metrics.execute(dry_run=True)"] +CMD ["-c", "import substratools as tools; tools.metrics.execute(sysargs=['--dry-run'])"] diff --git a/substrabac/containers/metrics/Dockerfile b/substrabac/containers/metrics/Dockerfile index 679578a93..2e1bbc67f 100644 --- a/substrabac/containers/metrics/Dockerfile +++ b/substrabac/containers/metrics/Dockerfile @@ -1,9 +1,3 @@ -FROM eu.gcr.io/substra-208412/substratools - -RUN mkdir -p /sandbox -RUN mkdir -p /sandbox/opener -RUN mkdir -p /sandbox/metrics -WORKDIR /sandbox - +FROM eu.gcr.io/substra-208412/substratools:0.0.1 ENTRYPOINT ["python3"] CMD ["-c", "import substratools as tools; tools.metrics.execute()"] From 4e8797bff56946a2641e07a9d11448dda20499af Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 24 Jul 2019 10:51:20 +0200 Subject: [PATCH 176/457] update tests assets --- .../management/tests/tests_createobjective.py | 2 +- substrabac/substrapp/tests/assets.py | 152 +++++++++--------- .../tests/views/tests_views_datamanager.py | 4 +- 3 files changed, 79 insertions(+), 79 deletions(-) diff --git a/substrabac/substrapp/management/tests/tests_createobjective.py b/substrabac/substrapp/management/tests/tests_createobjective.py index 9f97d9789..f3b3c72a6 100644 --- a/substrabac/substrapp/management/tests/tests_createobjective.py +++ b/substrabac/substrapp/management/tests/tests_createobjective.py @@ -66,7 +66,7 @@ def test_createobjective(self): } objective_pk = 'd5002e1cd50bd5de5341df8a7b7d11b6437154b3b08f531c9b8f93889855c66f' - datamanager_pk = '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7' + datamanager_pk = '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca' pkhash1 = '24fb12ff87485f6b0bc5349e5bf7f36ccca4eb1353395417fdae7d8d787f178c' pkhash2 = '30f6c797e277451b0a08da7119ed86fb2986fa7fab2258bf3edbd9f1752ed553' diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index c4f0a4e60..b8d0897e7 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -11,7 +11,7 @@ "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" }, - "owner": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", + "owner": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", "testDataset": None, "permissions": "all" }, @@ -27,9 +27,9 @@ "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" }, - "owner": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", + "owner": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", "testDataset": { - "dataManagerKey": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", + "dataManagerKey": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "dataSampleKeys": [ "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf", "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a" @@ -45,15 +45,15 @@ "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "description": { "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", - "storageAddress": "http://testserver/data_manager/615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7/description/" + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" }, - "key": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "name": "ISIC 2018", "opener": { - "hash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", - "storageAddress": "http://testserver/data_manager/615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7/opener/" + "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" }, - "owner": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "owner": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "permissions": "all", "type": "Images" }, @@ -61,15 +61,15 @@ "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "description": { "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", - "storageAddress": "http://testserver/data_manager/82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2/description/" + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" }, - "key": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", + "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "name": "Simplified ISIC 2018", "opener": { - "hash": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", - "storageAddress": "http://testserver/data_manager/82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2/opener/" + "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" }, - "owner": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", + "owner": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", "permissions": "all", "type": "Images" } @@ -87,7 +87,7 @@ "hash": "b9463411a01ea00869bdffce6e59a5c100a4e635c0a9386266cad3c77eb28e9e", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/description/" }, - "owner": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "owner": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "permissions": "all" }, { @@ -101,46 +101,46 @@ "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" }, - "owner": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "owner": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "permissions": "all" }, { - "key": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", + "key": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "name": "Logistic regression", "content": { - "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, "description": { "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/description/" + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" }, - "owner": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", + "owner": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", "permissions": "all" } ] traintuple = [ { - "key": "e0db5d9206a9049dd57736943e6c79b7b0b5d369971725284bada0ad10b6d2e4", + "key": "8e8c724a3308b81b01f69ea96da80bac9cd5c2f31d08f54531da17aa1a8cca7e", "algo": { "name": "Neural Network", "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" }, - "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "dataset": { - "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], - "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, "fltask": "", "inModels": None, - "log": "[00-01-0032-5246056]", + "log": "[00-01-0032-8a01ed9]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -155,25 +155,25 @@ "tag": "My super tag" }, { - "key": "e60b3a73927eda5ccd94620693e3dd056dee289bce0a3a0865b03b3359ab0ce4", + "key": "00227da7d49a20c228e0c10a3283891b9c0ded90685959cba55f0ba3f38123bb", "algo": { "name": "Logistic regression", - "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, - "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "dataset": { - "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], - "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, "fltask": "", "inModels": None, - "log": "Train - CPU:89.48 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Train - CPU:268.84 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -182,8 +182,8 @@ } }, "outModel": { - "hash": "72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080", - "storageAddress": "http://testserver/model/72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080/file/" + "hash": "a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717", + "storageAddress": "http://testserver/model/a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717/file/" }, "permissions": "all", "rank": 0, @@ -191,25 +191,25 @@ "tag": "substra" }, { - "key": "689990aac749b241b080fb6ee2c73aa30f442cb9056bd9803e75a7606dcdfb91", + "key": "6ac5dc6f51bf793248b18906171f3133cf24eb04e2fd0bafa3f86ff9b518c886", "algo": { "name": "Random Forest", "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, - "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "dataset": { - "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], - "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, "fltask": "", "inModels": None, - "log": "[00-01-0032-c370fb8]", + "log": "[00-01-0032-4647065]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -227,28 +227,28 @@ testtuple = [ { - "key": "915fdcc3406b6bf149a9d178f6e61d6c87a057a9ed8c10b369422b74ce4d3394", + "key": "8fbcd8f301447c73e7cfd0afac9dca9300d6fc948060af588de02c8ca946ffc0", "algo": { "name": "Logistic regression", - "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, "certified": True, - "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "dataset": { - "worker": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", + "worker": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", "keys": [ "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" ], - "openerHash": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", + "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "perf": 0 }, "log": "Test - CPU:0.00 % - Mem:0.00 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "model": { - "traintupleKey": "e60b3a73927eda5ccd94620693e3dd056dee289bce0a3a0865b03b3359ab0ce4", - "hash": "72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080", - "storageAddress": "http://testserver/model/72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080/file/" + "traintupleKey": "00227da7d49a20c228e0c10a3283891b9c0ded90685959cba55f0ba3f38123bb", + "hash": "a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717", + "storageAddress": "http://testserver/model/a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -266,25 +266,25 @@ model = [ { "traintuple": { - "key": "e0db5d9206a9049dd57736943e6c79b7b0b5d369971725284bada0ad10b6d2e4", + "key": "8e8c724a3308b81b01f69ea96da80bac9cd5c2f31d08f54531da17aa1a8cca7e", "algo": { "name": "Neural Network", "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" }, - "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "dataset": { - "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], - "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, "fltask": "", "inModels": None, - "log": "[00-01-0032-5246056]", + "log": "[00-01-0032-8a01ed9]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -314,25 +314,25 @@ }, { "traintuple": { - "key": "e60b3a73927eda5ccd94620693e3dd056dee289bce0a3a0865b03b3359ab0ce4", + "key": "00227da7d49a20c228e0c10a3283891b9c0ded90685959cba55f0ba3f38123bb", "algo": { "name": "Logistic regression", - "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, - "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "dataset": { - "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], - "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, "fltask": "", "inModels": None, - "log": "Train - CPU:89.48 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Train - CPU:268.84 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -341,8 +341,8 @@ } }, "outModel": { - "hash": "72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080", - "storageAddress": "http://testserver/model/72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080/file/" + "hash": "a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717", + "storageAddress": "http://testserver/model/a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717/file/" }, "permissions": "all", "rank": 0, @@ -350,28 +350,28 @@ "tag": "substra" }, "testtuple": { - "key": "915fdcc3406b6bf149a9d178f6e61d6c87a057a9ed8c10b369422b74ce4d3394", + "key": "8fbcd8f301447c73e7cfd0afac9dca9300d6fc948060af588de02c8ca946ffc0", "algo": { "name": "Logistic regression", - "hash": "4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7", - "storageAddress": "http://testserver/algo/4cc53726e01f7e3864a6cf9da24d9cef04a7cbd7fd2892765ff76931dd4628e7/file/" + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, "certified": True, - "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "dataset": { - "worker": "cc89c43e621de4e2251505ce71f48111cfc2cdc46307eb2d01616d0ccfae3eac", + "worker": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", "keys": [ "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" ], - "openerHash": "82e841c49822b2abcab9e95fe9ae359316d70ab5f627a28b0b67618dd945b2c2", + "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "perf": 0 }, "log": "Test - CPU:0.00 % - Mem:0.00 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "model": { - "traintupleKey": "e60b3a73927eda5ccd94620693e3dd056dee289bce0a3a0865b03b3359ab0ce4", - "hash": "72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080", - "storageAddress": "http://testserver/model/72a0af902268420e04fcd06d50f97ed3015fc106f1b24af533451b55a00e7080/file/" + "traintupleKey": "00227da7d49a20c228e0c10a3283891b9c0ded90685959cba55f0ba3f38123bb", + "hash": "a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717", + "storageAddress": "http://testserver/model/a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -387,25 +387,25 @@ }, { "traintuple": { - "key": "689990aac749b241b080fb6ee2c73aa30f442cb9056bd9803e75a7606dcdfb91", + "key": "6ac5dc6f51bf793248b18906171f3133cf24eb04e2fd0bafa3f86ff9b518c886", "algo": { "name": "Random Forest", "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, - "creator": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "dataset": { - "worker": "2849eac88763d23f65706b81cc63056712a170e5915e210640846c3ab4abea55", + "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], - "openerHash": "615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7", + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, "fltask": "", "inModels": None, - "log": "[00-01-0032-c370fb8]", + "log": "[00-01-0032-4647065]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 87d9545c0..7f03a42f3 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -111,7 +111,7 @@ def test_datamanager_list_filter_model(self): def test_datamanager_retrieve(self): url = reverse('substrapp:data_manager-list') datamanager_response = [d for d in datamanager - if d['key'] == '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7'][0] + if d['key'] == '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca'][0] with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger, \ mock.patch('substrapp.views.datamanager.get_from_node') as mrequestsget: mget_object_from_ledger.return_value = datamanager_response @@ -130,7 +130,7 @@ def test_datamanager_retrieve(self): FakeRequest(status=status.HTTP_200_OK, content=description_content)] - search_params = '615ce631b93c185b492dfc97ed5dea27430d871fa4e50678bab3c79ce2ec6cb7/' + search_params = '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/' response = self.client.get(url + search_params, **self.extra) r = response.json() From e42ed68dd119ff3d6fe8f45027cbd4a88c95b3d3 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 30 Jul 2019 17:14:09 +0200 Subject: [PATCH 177/457] Fix issue with commit in ledger when asset already exists --- populate.py | 10 ++++++++++ substrabac/substrapp/views/algo.py | 4 +++- substrabac/substrapp/views/datamanager.py | 4 +++- substrabac/substrapp/views/datasample.py | 4 +++- substrabac/substrapp/views/objective.py | 4 +++- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/populate.py b/populate.py index 4fdd51206..45359085f 100644 --- a/populate.py +++ b/populate.py @@ -162,6 +162,16 @@ def do_populate(): } data_manager_org0_key = get_or_create(data, org_0, 'dataset') + print(f'create datamanager, test data and objective on {org_1} (should say "already exists")') + data = { + 'name': 'Simplified ISIC 2018', + 'data_opener': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/opener.py'), + 'type': 'Images', + 'description': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/description.md'), + 'permissions': 'all' + } + get_or_create(data, org_1, 'dataset') + #################################################### print('register test data') diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index b2dcd66c0..70dc525c8 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -11,7 +11,7 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer from substrapp.utils import get_hash, get_from_node -from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, get_success_create_code, LedgerException, ValidationException) from substrapp.views.filters_utils import filter_list @@ -54,6 +54,8 @@ def commit(self, serializer, request): except LedgerTimeout as e: data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) + except LedgerConflict as e: + raise ValidationException(e.msg, e.pkhash, e.status) except LedgerError as e: instance.delete() raise LedgerException(str(e.msg), e.status) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 747096ba1..1f6ca0c41 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -16,7 +16,7 @@ from substrapp.serializers.ledger.datamanager.util import updateLedgerDataManager from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync from substrapp.utils import get_hash, get_from_node -from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (ManageFileMixin, ComputeHashMixin, find_primary_key_error, validate_pk, get_success_create_code, ValidationException, LedgerException) from substrapp.views.filters_utils import filter_list @@ -78,6 +78,8 @@ def commit(self, serializer, request): except LedgerTimeout as e: data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) + except LedgerConflict as e: + raise ValidationException(e.msg, e.pkhash, e.status) except LedgerError as e: instance.delete() raise LedgerException(str(e.msg), e.status) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 334f9ecc3..8dd0ef2c7 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -28,7 +28,7 @@ from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import find_primary_key_error, LedgerException, ValidationException, \ get_success_create_code -from substrapp.ledger_utils import query_ledger, LedgerError, LedgerTimeout +from substrapp.ledger_utils import query_ledger, LedgerError, LedgerTimeout, LedgerConflict logger = logging.getLogger('django.request') @@ -74,6 +74,8 @@ def commit(serializer, ledger_data): except LedgerTimeout as e: data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) + except LedgerConflict as e: + raise ValidationException(e.msg, e.pkhash, e.status) except LedgerError as e: for instance in instances: instance.delete() diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 5c804d52f..8494a091e 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -22,7 +22,7 @@ from substrapp.models import Objective from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer -from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout +from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.utils import get_hash, get_computed_hash, get_from_node, create_directory from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ @@ -104,6 +104,8 @@ def commit(self, serializer, request): except LedgerTimeout as e: data = {'pkhash': [x['pkhash'] for x in serializer.data], 'validated': False} raise LedgerException(data, e.status) + except LedgerConflict as e: + raise ValidationException(e.msg, e.pkhash, e.status) except LedgerError as e: instance.delete() raise LedgerException(str(e.msg), e.status) From ad5e84e4a4f5fe83fb52e4abd2a7c60310c51517 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 29 Jul 2019 15:20:16 +0200 Subject: [PATCH 178/457] metrics of objective: use Dockerfile instead of script --- .../objectives/objective0/Dockerfile | 7 +++ .../objectives/objective0/metrics.py | 8 +++- .../owkin/objectives/objective0/Dockerfile | 7 +++ .../owkin/objectives/objective0/metrics.py | 8 +++- .../containers/dryrun_metrics/Dockerfile | 3 -- substrabac/containers/metrics/Dockerfile | 3 -- substrabac/substrapp/tasks/tasks.py | 22 ++++------ substrabac/substrapp/tests/common.py | 3 ++ substrabac/substrapp/tests/tests_tasks.py | 26 ++++++++--- .../tests/views/tests_views_objective.py | 21 +++++++-- substrabac/substrapp/views/objective.py | 43 +++++++++---------- 11 files changed, 94 insertions(+), 57 deletions(-) create mode 100644 fixtures/chunantes/objectives/objective0/Dockerfile create mode 100644 fixtures/owkin/objectives/objective0/Dockerfile delete mode 100644 substrabac/containers/dryrun_metrics/Dockerfile delete mode 100644 substrabac/containers/metrics/Dockerfile diff --git a/fixtures/chunantes/objectives/objective0/Dockerfile b/fixtures/chunantes/objectives/objective0/Dockerfile new file mode 100644 index 000000000..9f4b3498a --- /dev/null +++ b/fixtures/chunantes/objectives/objective0/Dockerfile @@ -0,0 +1,7 @@ +FROM eu.gcr.io/substra-208412/substratools:0.0.1 + +RUN mkdir -p /sandbox/opener +WORKDIR /sandbox +COPY metrics.py . + +ENTRYPOINT ["python3", "metrics.py"] diff --git a/fixtures/chunantes/objectives/objective0/metrics.py b/fixtures/chunantes/objectives/objective0/metrics.py index 95652de06..04ace0354 100644 --- a/fixtures/chunantes/objectives/objective0/metrics.py +++ b/fixtures/chunantes/objectives/objective0/metrics.py @@ -1,8 +1,12 @@ from sklearn.metrics import recall_score -from substratools import Metrics as MetricsABC +import substratools as tools -class Metrics(MetricsABC): +class Metrics(tools.Metrics): def score(self, y_true, y_pred): return recall_score(y_true.argmax(axis=1), y_pred.argmax(axis=1), average='macro') + + +if __name__ == '__main__': + tools.metrics.execute(Metrics()) diff --git a/fixtures/owkin/objectives/objective0/Dockerfile b/fixtures/owkin/objectives/objective0/Dockerfile new file mode 100644 index 000000000..9f4b3498a --- /dev/null +++ b/fixtures/owkin/objectives/objective0/Dockerfile @@ -0,0 +1,7 @@ +FROM eu.gcr.io/substra-208412/substratools:0.0.1 + +RUN mkdir -p /sandbox/opener +WORKDIR /sandbox +COPY metrics.py . + +ENTRYPOINT ["python3", "metrics.py"] diff --git a/fixtures/owkin/objectives/objective0/metrics.py b/fixtures/owkin/objectives/objective0/metrics.py index 95652de06..04ace0354 100644 --- a/fixtures/owkin/objectives/objective0/metrics.py +++ b/fixtures/owkin/objectives/objective0/metrics.py @@ -1,8 +1,12 @@ from sklearn.metrics import recall_score -from substratools import Metrics as MetricsABC +import substratools as tools -class Metrics(MetricsABC): +class Metrics(tools.Metrics): def score(self, y_true, y_pred): return recall_score(y_true.argmax(axis=1), y_pred.argmax(axis=1), average='macro') + + +if __name__ == '__main__': + tools.metrics.execute(Metrics()) diff --git a/substrabac/containers/dryrun_metrics/Dockerfile b/substrabac/containers/dryrun_metrics/Dockerfile deleted file mode 100644 index 88395c62a..000000000 --- a/substrabac/containers/dryrun_metrics/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM eu.gcr.io/substra-208412/substratools:0.0.1 -ENTRYPOINT ["python3"] -CMD ["-c", "import substratools as tools; tools.metrics.execute(sysargs=['--dry-run'])"] diff --git a/substrabac/containers/metrics/Dockerfile b/substrabac/containers/metrics/Dockerfile deleted file mode 100644 index 2e1bbc67f..000000000 --- a/substrabac/containers/metrics/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM eu.gcr.io/substra-208412/substratools:0.0.1 -ENTRYPOINT ["python3"] -CMD ["-c", "import substratools as tools; tools.metrics.execute()"] diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index e2f12a278..5e7deb8ff 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -31,11 +31,10 @@ def get_objective(subtuple): objectiveHash = subtuple['objective']['hash'] - objective = None try: objective = Objective.objects.get(pk=objectiveHash) except ObjectDoesNotExist: - pass + objective = None # get objective from ledger as it is not available in local db and store it in local db if objective is None or not objective.metrics: @@ -45,9 +44,9 @@ def get_objective(subtuple): tmp_file = tempfile.TemporaryFile() tmp_file.write(content) - objective.metrics.save('metrics.py', tmp_file) + objective.metrics.save('metrics.archive', tmp_file) - return objective + return objective.metrics.read() def get_algo(subtuple): @@ -153,10 +152,9 @@ def put_data_sample(subtuple, subtuple_directory): raise Exception('Failed to create sym link for subtuple data sample') -def put_metric(subtuple_directory, objective): - metrics_dst_path = path.join(subtuple_directory, 'metrics/metrics.py') - if not os.path.exists(metrics_dst_path): - os.link(objective.metrics.path, metrics_dst_path) +def put_metric(subtuple_directory, metrics_content): + metrics_dst_path = path.join(subtuple_directory, 'metrics/') + uncompress_content(metrics_content, metrics_dst_path) def put_algo(subtuple_directory, algo_content): @@ -288,7 +286,7 @@ def compute_task(self, tuple_type, subtuple, fltask): def prepare_materials(subtuple, tuple_type): # get subtuple components - objective = get_objective(subtuple) + metrics_content = get_objective(subtuple) algo_content = get_algo(subtuple) if tuple_type == 'testtuple': model_content = get_model(subtuple) @@ -301,7 +299,7 @@ def prepare_materials(subtuple, tuple_type): subtuple_directory = build_subtuple_folders(subtuple) put_opener(subtuple, subtuple_directory) put_data_sample(subtuple, subtuple_directory) - put_metric(subtuple_directory, objective) + put_metric(subtuple_directory, metrics_content) put_algo(subtuple_directory, algo_content) if tuple_type == 'testtuple': put_model(subtuple, subtuple_directory, model_content) @@ -379,10 +377,8 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, fltask, flrank, o pred_path = path.join(subtuple_directory, 'pred') opener_file = path.join(subtuple_directory, 'opener/opener.py') - metrics_file = path.join(subtuple_directory, 'metrics/metrics.py') volumes = {data_path: {'bind': '/sandbox/data', 'mode': 'ro'}, pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, - metrics_file: {'bind': '/sandbox/metrics/__init__.py', 'mode': 'ro'}, opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}} # compute algo task @@ -449,7 +445,7 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, fltask, flrank, o end_model_file = f'{current_site}{reverse("substrapp:model-file", args=[end_model_file_hash])}' # compute metric task - metrics_path = path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/metrics') # comes with substrabac + metrics_path = f'{subtuple_directory}/metrics' metrics_docker = f'metrics_{tuple_type}'.lower() # tag must be lowercase for docker metrics_docker_name = f'{metrics_docker}_{subtuple["key"]}' compute_docker( diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 5b70dc342..190060eff 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -267,6 +267,9 @@ def __init__(self, filepath='path'): def save(self, p, f): return + def read(self, *args, **kwargs): + return b'foo' + class FakeObjective(object): def __init__(self, filepath='path'): diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 2ae77e656..a4d643d52 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -158,16 +158,26 @@ def test_put_algo_zip(self): self.assertTrue(os.path.exists(os.path.join(self.subtuple_path, f'subtuple/{subtuple["key"]}/{filename}'))) def test_put_metric(self): - - filepath = os.path.join(self.subtuple_path, self.script_filename) + filename = 'metrics.py' + filepath = os.path.join(self.subtuple_path, filename) with open(filepath, 'w') as f: - f.write(self.script.read()) + f.write('Hello World') self.assertTrue(os.path.exists(filepath)) - metrics_directory = os.path.join(self.subtuple_path, 'metrics/') + zipname = 'sample.zip' + zippath = os.path.join(self.subtuple_path, zipname) + with zipfile.ZipFile(zippath, mode='w') as zf: + zf.write(filepath, arcname=filename) + self.assertTrue(os.path.exists(zippath)) + + metrics_directory = os.path.join(self.subtuple_path) create_directory(metrics_directory) - put_metric(self.subtuple_path, FakeObjective(filepath)) + with mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash: + with open(zippath, 'rb') as content: + mget_hash.return_value = 'hash_value' + put_metric(metrics_directory, content.read()) + self.assertTrue(os.path.exists(os.path.join(metrics_directory, 'metrics.py'))) def test_put_opener(self): @@ -446,7 +456,8 @@ def test_get_objective(self): objective = get_objective({'objective': {'hash': objective_hash, 'metrics': ''}}) - self.assertTrue(isinstance(objective, FakeObjective)) + self.assertTrue(isinstance(objective, bytes)) + self.assertEqual(objective, b'foo') with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: @@ -457,7 +468,8 @@ def test_get_objective(self): objective = get_objective({'objective': {'hash': objective_hash, 'metrics': ''}}) - self.assertTrue(isinstance(objective, FakeObjective)) + self.assertTrue(isinstance(objective, bytes)) + self.assertEqual(objective, b'foo') def test_compute_docker(self): cpu_set, gpu_set = None, None diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index e5888b3b2..6cf43e1b1 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -1,6 +1,7 @@ import os import shutil import logging +import zipfile import mock @@ -26,6 +27,16 @@ MEDIA_ROOT = "/tmp/unittests_views/" +def zip_folder(path, destination): + zipf = zipfile.ZipFile(destination, 'w', zipfile.ZIP_DEFLATED) + for root, dirs, files in os.walk(path): + for f in files: + abspath = os.path.join(root, f) + archive_path = os.path.relpath(abspath, start=path) + zipf.write(abspath, arcname=archive_path) + zipf.close() + + # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(SITE_HOST='localhost') @@ -253,12 +264,14 @@ def test_objective_compute_dryrun(self): dir_path = os.path.dirname(os.path.realpath(__file__)) - metrics_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/metrics.py') - description_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/description.md') - shutil.copy(metrics_path, os.path.join(MEDIA_ROOT, 'metrics.py')) + objective_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/') + description_path = os.path.join(objective_path, 'description.md') + zip_path = os.path.join(MEDIA_ROOT, 'metrics.zip') opener_path = os.path.join(dir_path, '../../../../fixtures/owkin/datamanagers/datamanager0/opener.py') + zip_folder(objective_path, zip_path) + with open(opener_path, 'rb') as f: opener_content = f.read() @@ -270,4 +283,4 @@ def test_objective_compute_dryrun(self): mock.patch('substrapp.views.objective.get_computed_hash') as mopener: mdatamanager.return_value = {'opener': {'storageAddress': 'test'}} mopener.return_value = (opener_content, pkhash) - objective_compute_dryrun(os.path.join(MEDIA_ROOT, 'metrics.py'), test_data_manager_key, pkhash) + objective_compute_dryrun(zip_path, test_data_manager_key, pkhash) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 8494a091e..55aec4e22 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -2,7 +2,6 @@ import logging import os import re -import shutil import tempfile import uuid @@ -23,7 +22,7 @@ from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.utils import get_hash, get_computed_hash, get_from_node, create_directory +from substrapp.utils import get_hash, get_computed_hash, get_from_node, create_directory, uncompress_path from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ get_success_create_code, ValidationException, LedgerException @@ -50,10 +49,10 @@ def handle_dryrun(self, pkhash, metrics, test_data_manager_key): dryrun_directory = os.path.join(getattr(settings, 'MEDIA_ROOT'), 'dryrun') create_directory(dryrun_directory) - metrics_path = os.path.join(dryrun_directory, f'metrics_{pkhash}.py') + metrics_path = os.path.join(dryrun_directory, f'metrics_{pkhash}.archive') - with open(metrics_path, 'wb') as metrics_file: - metrics_file.write(metrics.open().read()) + with open(metrics_path, 'wb') as fh: + fh.write(metrics.open().read()) task = compute_dryrun.apply_async( (metrics_path, test_data_manager_key, pkhash), queue=f"{settings.LEDGER['name']}.dryrunner" @@ -124,9 +123,12 @@ def _create(self, request, dryrun): test_data_manager_key = request.data.get('test_data_manager_key', '') pkhash = get_hash(description) - serializer = self.get_serializer(data={'pkhash': pkhash, - 'metrics': metrics, - 'description': description}) + + serializer = self.get_serializer(data={ + 'pkhash': pkhash, + 'metrics': metrics, + 'description': description, + }) try: serializer.is_valid(raise_exception=True) @@ -275,38 +277,33 @@ def data(self, request, *args, **kwargs): @app.task(bind=True, ignore_result=False) -def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): +def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): + if not test_data_manager_key: + raise Exception('Cannot do a objective dryrun without a data manager key.') + dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) + metrics_path = f'{subtuple_directory}/metrics' + uncompress_path(archive_path, metrics_path) - metrics_path_dst = os.path.join(subtuple_directory, 'metrics/metrics.py') - if not os.path.exists(metrics_path_dst): - shutil.copy2(metrics_path, os.path.join(subtuple_directory, 'metrics/metrics.py')) - os.remove(metrics_path) - - if not test_data_manager_key: - remove_subtuple_materials(subtuple_directory) - raise Exception('Cannot do a objective dryrun without a data manager key.') + os.remove(archive_path) datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') opener_content, opener_computed_hash = get_computed_hash(datamanager['opener']['storageAddress']) - with open(os.path.join(subtuple_directory, 'opener/opener.py'), 'wb') as file: - file.write(opener_content) + with open(os.path.join(subtuple_directory, 'opener/opener.py'), 'wb') as fh: + fh.write(opener_content) # Launch verification client = docker.from_env() pred_path = os.path.join(subtuple_directory, 'pred') opener_file = os.path.join(subtuple_directory, 'opener/opener.py') - metrics_file = os.path.join(subtuple_directory, 'metrics/metrics.py') - metrics_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/dryrun_metrics') metrics_docker = 'metrics_dry_run' metrics_docker_name = f'{metrics_docker}_{dryrun_uuid}' volumes = { pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, - metrics_file: {'bind': '/sandbox/metrics/__init__.py', 'mode': 'ro'}, opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}} client.images.build(path=metrics_path, @@ -318,7 +315,7 @@ def compute_dryrun(self, metrics_path, test_data_manager_key, pkhash): 'name': metrics_docker_name, 'cpuset_cpus': '0-0', 'mem_limit': '1G', - 'command': None, + 'command': '--dry-run', 'volumes': volumes, 'shm_size': '8G', 'labels': ['dryrun'], From 9a1f8825c3181bcb312a75fecc0fefc4f33b20d2 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 29 Jul 2019 16:07:00 +0200 Subject: [PATCH 179/457] update populate --- populate.py | 65 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/populate.py b/populate.py index 45359085f..89cd0400e 100644 --- a/populate.py +++ b/populate.py @@ -2,7 +2,9 @@ import os import json import shutil +import tempfile import time +import zipfile import substra @@ -23,6 +25,16 @@ def setup_config(): client.add_profile('clb', 'http://clb.substrabac:8002', '0.0') +def zip_folder(path, destination): + zipf = zipfile.ZipFile(destination, 'w', zipfile.ZIP_DEFLATED) + for root, dirs, files in os.walk(path): + for f in files: + abspath = os.path.join(root, f) + archive_path = os.path.relpath(abspath, start=path) + zipf.write(abspath, arcname=archive_path) + zipf.close() + + def get_or_create(data, profile, asset, dryrun=False, local=True): client.set_profile(profile) @@ -213,31 +225,42 @@ def do_populate(): #################################################### - print('register objective') - data = { - 'name': 'Skin Lesion Classification Objective', - 'description': os.path.join(dir_path, './fixtures/chunantes/objectives/objective0/description.md'), - 'metrics_name': 'macro-average recall', - 'metrics': os.path.join(dir_path, './fixtures/chunantes/objectives/objective0/metrics.py'), - 'permissions': 'all', - 'test_data_sample_keys': test_data_sample_keys, - 'test_data_manager_key': data_manager_org0_key - } + with tempfile.TemporaryDirectory() as tmp_dir: + print('register objective') + objective_path = os.path.join( + dir_path, './fixtures/chunantes/objectives/objective0/') - objective_key = get_or_create(data, org_0, 'objective', dryrun=True) + zip_path = os.path.join(tmp_dir, 'metrics.zip') + zip_folder(objective_path, zip_path) + data = { + 'name': 'Skin Lesion Classification Objective', + 'description': os.path.join(dir_path, './fixtures/chunantes/objectives/objective0/description.md'), + 'metrics_name': 'macro-average recall', + 'metrics': zip_path, + 'permissions': 'all', + 'test_data_sample_keys': test_data_sample_keys, + 'test_data_manager_key': data_manager_org0_key + } - #################################################### + objective_key = get_or_create(data, org_0, 'objective', dryrun=True) - print('register objective without data manager and data sample') - data = { - 'name': 'Skin Lesion Classification Objective', - 'description': os.path.join(dir_path, './fixtures/owkin/objectives/objective0/description.md'), - 'metrics_name': 'macro-average recall', - 'metrics': os.path.join(dir_path, './fixtures/owkin/objectives/objective0/metrics.py'), - 'permissions': 'all' - } + #################################################### + + print('register objective without data manager and data sample') + objective_path = os.path.join( + dir_path, './fixtures/chunantes/objectives/objective0/') + + zip_path = os.path.join(tmp_dir, 'metrics2.zip') + zip_folder(objective_path, zip_path) + data = { + 'name': 'Skin Lesion Classification Objective', + 'description': os.path.join(dir_path, './fixtures/owkin/objectives/objective0/description.md'), + 'metrics_name': 'macro-average recall', + 'metrics': zip_path, + 'permissions': 'all' + } - get_or_create(data, org_0, 'objective', dryrun=True) + get_or_create(data, org_0, 'objective', dryrun=True) #################################################### From 33957ee69340112dc41a0924510ef3159b0bee70 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 31 Jul 2019 11:06:01 +0200 Subject: [PATCH 180/457] Fix agressive remove on data sample dryrun --- substrabac/substrapp/views/datasample.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 8dd0ef2c7..d10883529 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -40,8 +40,8 @@ class DataSampleViewSet(mixins.CreateModelMixin, queryset = DataSample.objects.all() serializer_class = DataSampleSerializer - def dryrun_task(self, data, data_manager_keys): - task = compute_dryrun.apply_async((data, data_manager_keys), + def dryrun_task(self, data, data_manager_keys, paths_to_remove): + task = compute_dryrun.apply_async((data, data_manager_keys, paths_to_remove), queue=f"{settings.LEDGER['name']}.dryrunner") current_site = getattr(settings, "DEFAULT_DOMAIN") task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' @@ -170,10 +170,10 @@ def compute_data(self, request, paths_to_remove): return list(data.values()) - def handle_dryrun(self, data, data_manager_keys): + def handle_dryrun(self, data, data_manager_keys, paths_to_remove): try: - task, msg = self.dryrun_task(data, data_manager_keys) + task, msg = self.dryrun_task(data, data_manager_keys, paths_to_remove) except Exception as e: raise Exception(f'Could not launch data creation with dry-run on this instance: {str(e)}') else: @@ -209,7 +209,7 @@ def _create(self, request, data_manager_keys, test_only, dryrun): raise ValidationException(e.args, pkhashes, st) else: if dryrun: - return self.handle_dryrun(computed_data, data_manager_keys) + return self.handle_dryrun(computed_data, data_manager_keys, paths_to_remove) # create on ledger + db ledger_data = {'test_only': test_only, @@ -304,7 +304,7 @@ def path_leaf(path): @app.task(bind=True, ignore_result=False) -def compute_dryrun(self, data_samples, data_manager_keys): +def compute_dryrun(self, data_samples, data_manager_keys, paths_to_remove): from shutil import copy from substrapp.models import DataManager @@ -374,6 +374,6 @@ def compute_dryrun(self, data_samples, data_manager_keys): remove_subtuple_materials(subtuple_directory) # Clean dryrun materials - for data_sample in data_samples: + for path in paths_to_remove: # Remove all possible data (data in servermedias is read-only) - shutil.rmtree(data_sample['path'], ignore_errors=True) + shutil.rmtree(path, ignore_errors=True) From 9b502c9d8a9a2047501a5effa31d95f976440bca Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 31 Jul 2019 17:33:17 +0200 Subject: [PATCH 181/457] Fix archive removal after dry run --- substrabac/substrapp/views/objective.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 55aec4e22..3fce4e6e9 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -279,6 +279,7 @@ def data(self, request, *args, **kwargs): @app.task(bind=True, ignore_result=False) def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): if not test_data_manager_key: + os.remove(archive_path) raise Exception('Cannot do a objective dryrun without a data manager key.') dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' @@ -286,7 +287,6 @@ def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) metrics_path = f'{subtuple_directory}/metrics' uncompress_path(archive_path, metrics_path) - os.remove(archive_path) datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') From c3046884812302d25448dbbb1660f55b98204bda Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 1 Aug 2019 10:04:17 +0200 Subject: [PATCH 182/457] fix broken tests --- substrabac/substrapp/tests/views/tests_views_datasample.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index a4e53653b..045190de5 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -299,7 +299,7 @@ def test_data_sample_compute_dryrun(self): with mock.patch.object(DataManager.objects, 'get') as mdatamanager: mdatamanager.return_value = FakeDataManager(opener_path) - data_sample_compute_dryrun(data_files, data_manager_keys) + data_sample_compute_dryrun(data_files, data_manager_keys, []) def test_datasamples_list(self): url = reverse('substrapp:data_sample-list') From 8020cf3d9ef235430074cbac4ef66711369645bf Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Tue, 16 Jul 2019 15:42:42 +0200 Subject: [PATCH 183/457] Remove custom list format in ledger calls --- .../substrapp/serializers/ledger/datasample/serializer.py | 4 ++-- .../substrapp/serializers/ledger/objective/serializer.py | 5 ++++- .../substrapp/serializers/ledger/testtuple/serializer.py | 2 +- .../substrapp/serializers/ledger/traintuple/serializer.py | 4 ++-- substrabac/substrapp/views/datasample.py | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/datasample/serializer.py b/substrabac/substrapp/serializers/ledger/datasample/serializer.py index e1a4a7b36..891bf984a 100644 --- a/substrabac/substrapp/serializers/ledger/datasample/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datasample/serializer.py @@ -19,8 +19,8 @@ def create(self, validated_data): test_only = validated_data.get('test_only') args = { - 'hashes': ','.join([x.pk for x in instances]), - 'dataManagerKeys': ','.join([x for x in data_manager_keys]), + 'hashes': [x.pk for x in instances], + 'dataManagerKeys': [x for x in data_manager_keys], 'testOnly': json.dumps(test_only), } diff --git a/substrabac/substrapp/serializers/ledger/objective/serializer.py b/substrabac/substrapp/serializers/ledger/objective/serializer.py index bb3fd8f6d..08f616bd4 100644 --- a/substrabac/substrapp/serializers/ledger/objective/serializer.py +++ b/substrabac/substrapp/serializers/ledger/objective/serializer.py @@ -41,7 +41,10 @@ def create(self, validated_data): 'metricsName': metrics_name, 'metricsHash': get_hash(instance.metrics), 'metricsStorageAddress': protocol + host + reverse('substrapp:objective-metrics', args=[instance.pk]), - 'testDataset': f'{test_data_manager_key}:{",".join([x for x in test_data_sample_keys])}', + 'testDataset': { + 'dataManagerKey': test_data_manager_key, + 'dataSampleKeys': test_data_sample_keys, + }, 'permissions': permissions } diff --git a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py index c0722d55f..30a62a85d 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/serializer.py @@ -23,7 +23,7 @@ def get_args(self, validated_data): args = { 'traintupleKey': traintuple_key, 'dataManagerKey': data_manager_key, - 'dataSampleKeys': ','.join(test_data_sample_keys), + 'dataSampleKeys': test_data_sample_keys, 'tag': tag } diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index f48e6a932..0b9022161 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -34,9 +34,9 @@ def get_args(self, validated_data): args = { 'algoKey': algo_key, 'objectiveKey': objective_key, - 'inModels': ','.join([x for x in in_models_keys]), + 'inModels': in_models_keys, 'dataManagerKey': data_manager_key, - 'dataSampleKeys': ','.join([x for x in train_data_sample_keys]), + 'dataSampleKeys': train_data_sample_keys, 'flTask': FLtask_key, 'rank': rank, 'tag': tag diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index d10883529..431199a29 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -275,8 +275,8 @@ def bulk_update(self, request): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: args = { - 'hashes': ','.join(data_sample_keys), - 'dataManagerKeys': ','.join(data_manager_keys), + 'hashes': data_sample_keys, + 'dataManagerKeys': data_manager_keys, } if getattr(settings, 'LEDGER_SYNC_ENABLED'): From a07a6b17ca122dc6887f18a7fe01f6598617946c Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Mon, 22 Jul 2019 17:22:10 +0200 Subject: [PATCH 184/457] Implement Compute plan route and ledger calls --- substrabac/substrapp/ledger_utils.py | 7 +- substrabac/substrapp/serializers/__init__.py | 2 +- .../substrapp/serializers/ledger/__init__.py | 3 +- .../ledger/computeplan/__init__.py | 0 .../ledger/computeplan/serializer.py | 63 ++++++++++++++++ .../serializers/ledger/computeplan/tasks.py | 9 +++ .../serializers/ledger/computeplan/util.py | 8 ++ substrabac/substrapp/urls.py | 4 +- substrabac/substrapp/views/__init__.py | 3 +- substrabac/substrapp/views/computeplan.py | 73 +++++++++++++++++++ 10 files changed, 166 insertions(+), 6 deletions(-) create mode 100644 substrabac/substrapp/serializers/ledger/computeplan/__init__.py create mode 100644 substrabac/substrapp/serializers/ledger/computeplan/serializer.py create mode 100644 substrabac/substrapp/serializers/ledger/computeplan/tasks.py create mode 100644 substrabac/substrapp/serializers/ledger/computeplan/util.py create mode 100644 substrabac/substrapp/views/computeplan.py diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index b798e8b3a..8c83ebb61 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -163,7 +163,7 @@ def query_ledger(fcn, args=None): return call_ledger('query', fcn=fcn, args=args) -def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): +def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False, only_pkhash=True): params = { 'wait_for_event': sync, } @@ -176,7 +176,10 @@ def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False): response = call_ledger('invoke', fcn=fcn, args=args, kwargs=params) - return {'pkhash': response.get('key', response.get('keys'))} + if only_pkhash: + return {'pkhash': response.get('key', response.get('keys'))} + else: + return response def get_object_from_ledger(pk, query): diff --git a/substrabac/substrapp/serializers/__init__.py b/substrabac/substrapp/serializers/__init__.py index e0f4f7577..015186c69 100644 --- a/substrabac/substrapp/serializers/__init__.py +++ b/substrabac/substrapp/serializers/__init__.py @@ -12,4 +12,4 @@ 'LedgerObjectiveSerializer', 'LedgerModelSerializer', 'LedgerDataSampleSerializer', 'LedgerAlgoSerializer', 'LedgerTrainTupleSerializer', 'LedgerTestTupleSerializer', - 'LedgerDataManagerSerializer'] + 'LedgerDataManagerSerializer', 'LedgerComputePlanSerializer'] diff --git a/substrabac/substrapp/serializers/ledger/__init__.py b/substrabac/substrapp/serializers/ledger/__init__.py index 32927cbab..327c989ad 100644 --- a/substrabac/substrapp/serializers/ledger/__init__.py +++ b/substrabac/substrapp/serializers/ledger/__init__.py @@ -7,8 +7,9 @@ from .traintuple.serializer import LedgerTrainTupleSerializer from .testtuple.serializer import LedgerTestTupleSerializer from .datamanager.serializer import LedgerDataManagerSerializer +from .computeplan.serializer import LedgerComputePlanSerializer __all__ = ['LedgerObjectiveSerializer', 'LedgerModelSerializer', 'LedgerDataSampleSerializer', 'LedgerAlgoSerializer', 'LedgerTrainTupleSerializer', 'LedgerTestTupleSerializer', - 'LedgerDataManagerSerializer'] + 'LedgerDataManagerSerializer', 'LedgerComputePlanSerializer'] diff --git a/substrabac/substrapp/serializers/ledger/computeplan/__init__.py b/substrabac/substrapp/serializers/ledger/computeplan/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/substrapp/serializers/ledger/computeplan/serializer.py b/substrabac/substrapp/serializers/ledger/computeplan/serializer.py new file mode 100644 index 000000000..afeae1894 --- /dev/null +++ b/substrabac/substrapp/serializers/ledger/computeplan/serializer.py @@ -0,0 +1,63 @@ +from rest_framework import serializers + +from django.conf import settings + +from .util import createLedgerComputePlan +from .tasks import createLedgerComputePlanAsync + + +class ComputePlanTraintupleSerializer(serializers.Serializer): + data_manager_key = serializers.CharField(min_length=64, max_length=64) + train_data_sample_keys = serializers.ListField( + child=serializers.CharField(min_length=64, max_length=64), + min_length=1) + traintuple_id = serializers.CharField(min_length=1, max_length=64) + in_models_ids = serializers.ListField( + child=serializers.CharField(min_length=1, max_length=64), + min_length=0, + required=False) + tag = serializers.CharField(min_length=0, max_length=64, allow_blank=True, required=False) + + +class LedgerComputePlanSerializer(serializers.Serializer): + algo_key = serializers.CharField(min_length=64, max_length=64) + objective_key = serializers.CharField(min_length=64, max_length=64) + traintuples = ComputePlanTraintupleSerializer(many=True) + + def get_args(self, validated_data): + algo_key = validated_data.get('algo_key') + objective_key = validated_data.get('objective_key') + traintuples = [] + + for traintuple in validated_data.get('traintuples', []): + traintuples.append({ + 'dataManagerKey': traintuple.get('data_manager_key'), + 'dataSampleKeys': traintuple.get('train_data_sample_keys', []), + 'id': traintuple.get('traintuple_id'), + 'inModelIds': traintuple.get('in_models_ids'), + 'tag': traintuple.get('tag'), + }) + + args = { + 'algoKey': algo_key, + 'objectiveKey': objective_key, + 'traintuples': traintuples, + } + + return args + + def create(self, validated_data): + args = self.get_args(validated_data) + + if getattr(settings, 'LEDGER_SYNC_ENABLED'): + data = createLedgerComputePlan(args, sync=True) + else: + # use a celery task, as we are in an http request transaction + createLedgerComputePlanAsync.delay(args) + data = { + 'message': 'The substra network has been notified for adding this ComputePlan. ' + 'Please be aware you won\'t get return values from the ledger. ' + 'You will need to check manually' + } + + return data diff --git a/substrabac/substrapp/serializers/ledger/computeplan/tasks.py b/substrabac/substrapp/serializers/ledger/computeplan/tasks.py new file mode 100644 index 000000000..9146b312f --- /dev/null +++ b/substrabac/substrapp/serializers/ledger/computeplan/tasks.py @@ -0,0 +1,9 @@ +# Create your tasks here +from __future__ import absolute_import, unicode_literals +from celery import shared_task +from .util import createLedgerComputePlan + + +@shared_task +def createLedgerComputePlanAsync(args): + return createLedgerComputePlan(args) diff --git a/substrabac/substrapp/serializers/ledger/computeplan/util.py b/substrabac/substrapp/serializers/ledger/computeplan/util.py new file mode 100644 index 000000000..d8d8ba774 --- /dev/null +++ b/substrabac/substrapp/serializers/ledger/computeplan/util.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import, unicode_literals + + +from substrapp.ledger_utils import invoke_ledger + + +def createLedgerComputePlan(args, sync=False): + return invoke_ledger(fcn='createComputePlan', args=args, sync=sync, only_pkhash=False) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index 312ce188c..4e5d4b704 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -6,7 +6,8 @@ from rest_framework.routers import DefaultRouter from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ - AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet + AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ + ComputePlanViewSet # Create a router and register our viewsets with it. @@ -19,6 +20,7 @@ router.register(r'traintuple', TrainTupleViewSet, base_name='traintuple') router.register(r'testtuple', TestTupleViewSet, base_name='testtuple') router.register(r'task', TaskViewSet, base_name='task') +router.register(r'compute_plan', ComputePlanViewSet, base_name='compute_plan') urlpatterns = [ url(r'^', include(router.urls)), diff --git a/substrabac/substrapp/views/__init__.py b/substrabac/substrapp/views/__init__.py index d3149b744..b44f571af 100644 --- a/substrabac/substrapp/views/__init__.py +++ b/substrabac/substrapp/views/__init__.py @@ -8,7 +8,8 @@ from .traintuple import TrainTupleViewSet from .testtuple import TestTupleViewSet from .task import TaskViewSet +from .computeplan import ComputePlanViewSet __all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'ObjectiveViewSet', 'ModelViewSet', 'AlgoViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', - 'TaskViewSet'] + 'TaskViewSet', 'ComputePlanViewSet'] diff --git a/substrabac/substrapp/views/computeplan.py b/substrabac/substrapp/views/computeplan.py new file mode 100644 index 000000000..116b4a61a --- /dev/null +++ b/substrabac/substrapp/views/computeplan.py @@ -0,0 +1,73 @@ +from rest_framework import mixins +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet + +from substrapp.serializers import LedgerComputePlanSerializer +from substrapp.ledger_utils import query_ledger, LedgerError +from substrapp.views.utils import get_success_create_code, LedgerException + + +class ComputePlanViewSet( + mixins.CreateModelMixin, + mixins.RetrieveModelMixin, + mixins.ListModelMixin, + GenericViewSet): + + serializer_class = LedgerComputePlanSerializer + + def get_queryset(self): + return [] + + def perform_create(self, serializer): + return serializer.save() + + def commit(self, serializer, fltask): + # create on ledger + try: + data = serializer.create(serializer.validated_data) + except LedgerError as e: + raise LedgerException({'message': str(e.msg), 'fltask': fltask}, e.status) + else: + return data + + def _create(self, request): + traintuples = [] + input_data = dict(request.data) + for traintuple in input_data.get('traintuples', []): + traintuples.append({ + 'data_manager_key': traintuple.get('data_manager_key'), + 'train_data_sample_keys': traintuple.get('train_data_sample_keys', []), + 'traintuple_id': traintuple.get('traintuple_id'), + 'in_models_ids': traintuple.get('in_model_ids', []), + 'tag': traintuple.get('tag', ''), + }) + data = { + 'algo_key': input_data.get('algo_key'), + 'objective_key': input_data.get('objective_key'), + 'traintuples': traintuples, + } + + serializer = self.get_serializer(data=data) + serializer.is_valid(raise_exception=True) + + # Get traintuple fltask to handle 408 timeout in invoke_ledger + args = serializer.get_args(serializer.validated_data) + + try: + data = query_ledger(fcn='createComputePlan', args=args) + except LedgerError as e: + raise LedgerException({'message': str(e.msg)}, e.status) + else: + fltask = data.get('fltask') + output_data = self.commit(serializer, fltask) + return output_data + + def create(self, request, *args, **kwargs): + try: + data = self._create(request) + except LedgerException as e: + return Response(e.data, status=e.st) + else: + headers = self.get_success_headers(data) + st = get_success_create_code() + return Response(data, status=st, headers=headers) From 05207c024e112ac3f924c3c305a20193696da8bc Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 31 Jul 2019 11:40:20 +0200 Subject: [PATCH 185/457] handle testtuple and simplify compute plan code small fixes too: - typo in field inModelsIDs --- .../ledger/computeplan/serializer.py | 70 ++++++++++++----- substrabac/substrapp/views/computeplan.py | 76 +++++-------------- 2 files changed, 74 insertions(+), 72 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/computeplan/serializer.py b/substrabac/substrapp/serializers/ledger/computeplan/serializer.py index afeae1894..9d903d868 100644 --- a/substrabac/substrapp/serializers/ledger/computeplan/serializer.py +++ b/substrabac/substrapp/serializers/ledger/computeplan/serializer.py @@ -19,33 +19,69 @@ class ComputePlanTraintupleSerializer(serializers.Serializer): tag = serializers.CharField(min_length=0, max_length=64, allow_blank=True, required=False) +class ComputePlanTesttupleSerializer(serializers.Serializer): + traintuple_id = serializers.CharField(min_length=1, max_length=64) + testtuple_id = serializers.CharField(min_length=1, max_length=64) + data_manager_key = serializers.CharField(min_length=64, max_length=64, required=False) + test_data_sample_keys = serializers.ListField( + child=serializers.CharField(min_length=64, max_length=64), + min_length=0, + required=False) + tag = serializers.CharField(min_length=0, max_length=64, allow_blank=True, required=False) + + class LedgerComputePlanSerializer(serializers.Serializer): algo_key = serializers.CharField(min_length=64, max_length=64) objective_key = serializers.CharField(min_length=64, max_length=64) traintuples = ComputePlanTraintupleSerializer(many=True) + testtuples = ComputePlanTesttupleSerializer(many=True) - def get_args(self, validated_data): - algo_key = validated_data.get('algo_key') - objective_key = validated_data.get('objective_key') + def get_args(self, data): + # convert snake case fields to camel case fields to match chaincode expected inputs traintuples = [] + for data_traintuple in data['traintuples']: + traintuple = { + 'dataManagerKey': data_traintuple['data_manager_key'], + 'dataSampleKeys': data_traintuple['train_data_sample_keys'], + 'id': data_traintuple['traintuple_id'], + } + try: + traintuple['inModelsIDs'] = data_traintuple['in_models_ids'] + except KeyError: + pass + try: + traintuple['tag'] = data_traintuple['tag'] + except KeyError: + pass + traintuples.append(traintuple) - for traintuple in validated_data.get('traintuples', []): - traintuples.append({ - 'dataManagerKey': traintuple.get('data_manager_key'), - 'dataSampleKeys': traintuple.get('train_data_sample_keys', []), - 'id': traintuple.get('traintuple_id'), - 'inModelIds': traintuple.get('in_models_ids'), - 'tag': traintuple.get('tag'), - }) - - args = { - 'algoKey': algo_key, - 'objectiveKey': objective_key, + testtuples = [] + for data_testtuple in data['testtuples']: + testtuple = { + 'testtupleID': data_testtuple['testtuple_id'], + 'traintupleID': data_testtuple['traintuple_id'], + } + try: + testtuple['tag'] = data_testtuple['tag'] + except KeyError: + pass + try: + testtuple['dataManagerKey'] = data_testtuple['data_manager_key'] + except KeyError: + pass + try: + testtuple['dataSampleKeys'] = data_testtuple['test_data_sample_keys'] + except KeyError: + pass + testtuples.append(testtuple) + + return { + 'algoKey': data['algo_key'], + 'objectiveKey': data['objective_key'], 'traintuples': traintuples, + 'testtuples': testtuples, } - return args - def create(self, validated_data): args = self.get_args(validated_data) diff --git a/substrabac/substrapp/views/computeplan.py b/substrabac/substrapp/views/computeplan.py index 116b4a61a..1eb88f14a 100644 --- a/substrabac/substrapp/views/computeplan.py +++ b/substrabac/substrapp/views/computeplan.py @@ -4,70 +4,36 @@ from substrapp.serializers import LedgerComputePlanSerializer from substrapp.ledger_utils import query_ledger, LedgerError -from substrapp.views.utils import get_success_create_code, LedgerException +from substrapp.views.utils import get_success_create_code -class ComputePlanViewSet( - mixins.CreateModelMixin, - mixins.RetrieveModelMixin, - mixins.ListModelMixin, - GenericViewSet): +class ComputePlanViewSet(mixins.CreateModelMixin, + GenericViewSet): serializer_class = LedgerComputePlanSerializer - def get_queryset(self): - return [] - - def perform_create(self, serializer): - return serializer.save() - - def commit(self, serializer, fltask): - # create on ledger - try: - data = serializer.create(serializer.validated_data) - except LedgerError as e: - raise LedgerException({'message': str(e.msg), 'fltask': fltask}, e.status) - else: - return data - - def _create(self, request): - traintuples = [] - input_data = dict(request.data) - for traintuple in input_data.get('traintuples', []): - traintuples.append({ - 'data_manager_key': traintuple.get('data_manager_key'), - 'train_data_sample_keys': traintuple.get('train_data_sample_keys', []), - 'traintuple_id': traintuple.get('traintuple_id'), - 'in_models_ids': traintuple.get('in_model_ids', []), - 'tag': traintuple.get('tag', ''), - }) - data = { - 'algo_key': input_data.get('algo_key'), - 'objective_key': input_data.get('objective_key'), - 'traintuples': traintuples, - } - - serializer = self.get_serializer(data=data) + def create(self, request, *args, **kwargs): + # rely on serializer to parse and validate request data + serializer = self.get_serializer(data=dict(request.data)) serializer.is_valid(raise_exception=True) - # Get traintuple fltask to handle 408 timeout in invoke_ledger + # get fltask to handle 408 timeout in next invoke ledger request args = serializer.get_args(serializer.validated_data) - try: - data = query_ledger(fcn='createComputePlan', args=args) + ledger_response = query_ledger(fcn='createComputePlan', args=args) except LedgerError as e: - raise LedgerException({'message': str(e.msg)}, e.status) - else: - fltask = data.get('fltask') - output_data = self.commit(serializer, fltask) - return output_data + error = {'message': str(e.msg)} + return Response(error, status=e.status) - def create(self, request, *args, **kwargs): + # create compute plan in ledger + fltask = ledger_response.get('fltask') try: - data = self._create(request) - except LedgerException as e: - return Response(e.data, status=e.st) - else: - headers = self.get_success_headers(data) - st = get_success_create_code() - return Response(data, status=st, headers=headers) + data = serializer.create(serializer.validated_data) + except LedgerError as e: + error = {'message': str(e.msg), 'fltask': fltask} + return Response(error, status=e.status) + + # send successful response + headers = self.get_success_headers(data) + status = get_success_create_code() + return Response(data, status=status, headers=headers) From 87236930cf786477f5a1168fe7f43b8292b0ad1a Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 1 Aug 2019 09:40:44 +0200 Subject: [PATCH 186/457] computeplan: get ridof testtuple id --- .../substrapp/serializers/ledger/computeplan/serializer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/computeplan/serializer.py b/substrabac/substrapp/serializers/ledger/computeplan/serializer.py index 9d903d868..19fe83789 100644 --- a/substrabac/substrapp/serializers/ledger/computeplan/serializer.py +++ b/substrabac/substrapp/serializers/ledger/computeplan/serializer.py @@ -21,7 +21,6 @@ class ComputePlanTraintupleSerializer(serializers.Serializer): class ComputePlanTesttupleSerializer(serializers.Serializer): traintuple_id = serializers.CharField(min_length=1, max_length=64) - testtuple_id = serializers.CharField(min_length=1, max_length=64) data_manager_key = serializers.CharField(min_length=64, max_length=64, required=False) test_data_sample_keys = serializers.ListField( child=serializers.CharField(min_length=64, max_length=64), @@ -58,7 +57,6 @@ def get_args(self, data): testtuples = [] for data_testtuple in data['testtuples']: testtuple = { - 'testtupleID': data_testtuple['testtuple_id'], 'traintupleID': data_testtuple['traintuple_id'], } try: From f59de561599492cf74c21f71c23ff7bdd28a87ec Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 1 Aug 2019 10:56:35 +0200 Subject: [PATCH 187/457] computeplan: add test --- .../tests/views/tests_views_computeplan.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 substrabac/substrapp/tests/views/tests_views_computeplan.py diff --git a/substrabac/substrapp/tests/views/tests_views_computeplan.py b/substrabac/substrapp/tests/views/tests_views_computeplan.py new file mode 100644 index 000000000..f023cceb6 --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_computeplan.py @@ -0,0 +1,61 @@ +import os +import shutil + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.serializers import LedgerComputePlanSerializer + +MEDIA_ROOT = "/tmp/unittests_views/" + + +# APITestCase +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +@override_settings(LEDGER_SYNC_ENABLED=True) +class ComputePlanViewTests(APITestCase): + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + def test_create(self): + url = reverse('substrapp:compute_plan-list') + + dummy_key = 'x' * 64 + + data = { + 'algo_key': dummy_key, + 'objective_key': dummy_key, + 'traintuples': [{ + 'data_manager_key': dummy_key, + 'train_data_sample_keys': [dummy_key], + 'traintuple_id': dummy_key, + }], + 'testtuples': [{ + 'traintuple_id': dummy_key, + 'data_manager_key': dummy_key, + }], + } + + with mock.patch.object(LedgerComputePlanSerializer, 'create') as mcreate: + with mock.patch('substrapp.views.computeplan.query_ledger') as mquery: + mcreate.return_value = {} + mquery.return_value = {} + + response = self.client.post(url, data=data, format='json', **self.extra) + + self.assertEqual(response.json(), {}) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) From af52e27baa82a4353837ef3d044d610ce86ef40a Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 12 Aug 2019 16:47:08 +0200 Subject: [PATCH 188/457] prefer LBYL syntax style to check if key in dict --- .../ledger/computeplan/serializer.py | 22 ++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/computeplan/serializer.py b/substrabac/substrapp/serializers/ledger/computeplan/serializer.py index 19fe83789..4f40975fe 100644 --- a/substrabac/substrapp/serializers/ledger/computeplan/serializer.py +++ b/substrabac/substrapp/serializers/ledger/computeplan/serializer.py @@ -44,14 +44,11 @@ def get_args(self, data): 'dataSampleKeys': data_traintuple['train_data_sample_keys'], 'id': data_traintuple['traintuple_id'], } - try: + if 'in_models_ids' in data_traintuple: traintuple['inModelsIDs'] = data_traintuple['in_models_ids'] - except KeyError: - pass - try: + if 'tag' in data_traintuple: traintuple['tag'] = data_traintuple['tag'] - except KeyError: - pass + traintuples.append(traintuple) testtuples = [] @@ -59,18 +56,13 @@ def get_args(self, data): testtuple = { 'traintupleID': data_testtuple['traintuple_id'], } - try: + if 'tag' in data_testtuple: testtuple['tag'] = data_testtuple['tag'] - except KeyError: - pass - try: + if 'data_manager_key' in data_testtuple: testtuple['dataManagerKey'] = data_testtuple['data_manager_key'] - except KeyError: - pass - try: + if 'test_data_sample_keys' in data_testtuple: testtuple['dataSampleKeys'] = data_testtuple['test_data_sample_keys'] - except KeyError: - pass + testtuples.append(testtuple) return { From 235e1f662e5e4ca5c0f7034aaa07fd47fe455b41 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 6 Aug 2019 11:18:39 +0200 Subject: [PATCH 189/457] ledger: add retry on MVCC errors when updating tuple state --- substrabac/substrabac/settings/deps/ledger.py | 1 + substrabac/substrapp/ledger_utils.py | 35 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 723b7f968..f22b8f301 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -20,6 +20,7 @@ LEDGER = json.load(open(LEDGER_CONFIG_FILE, 'r')) LEDGER_SYNC_ENABLED = True +LEDGER_MVCC_RETRY = True PEER_PORT = LEDGER['peer']['port'][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index b798e8b3a..9d36f0cef 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -1,11 +1,15 @@ -import json import contextlib +import functools +import json +import logging +import time from django.conf import settings from rest_framework import status LEDGER = getattr(settings, 'LEDGER', None) +logger = logging.getLogger(__name__) class LedgerError(Exception): @@ -77,6 +81,32 @@ class LedgerStatusError(LedgerError): } +def retry_on_mvcc_error(delay=1, nbtries=5, backoff=2): + def _retry(fn): + @functools.wraps(fn) + def _wrapper(*args, **kwargs): + if not getattr(settings, 'LEDGER_MVCC_RETRY', False): + return fn(*args, **kwargs) + + _delay = delay + _nbtries = nbtries + _backoff = backoff + + while True: + try: + return fn(*args, **kwargs) + except LedgerMVCCError as e: + _nbtries -= 1 + if not nbtries: + raise + _delay *= _backoff + time.sleep(_delay) + logger.warning(f'Function {fn.__name__} failed: {e} retrying in {_delay}s') + + return _wrapper + return _retry + + @contextlib.contextmanager def get_hfc(): loop, client = LEDGER['hfc']() @@ -183,6 +213,7 @@ def get_object_from_ledger(pk, query): return query_ledger(fcn=query, args={'key': pk}) +@retry_on_mvcc_error() def log_fail_tuple(tuple_type, tuple_key, err_msg): err_msg = str(err_msg).replace('"', "'").replace('\\', "").replace('\\n', "")[:200] @@ -197,6 +228,7 @@ def log_fail_tuple(tuple_type, tuple_key, err_msg): sync=True) +@retry_on_mvcc_error() def log_success_tuple(tuple_type, tuple_key, res): if tuple_type == 'traintuple': invoke_fcn = 'logSuccessTrain' @@ -224,6 +256,7 @@ def log_success_tuple(tuple_type, tuple_key, res): return invoke_ledger(fcn=invoke_fcn, args=invoke_args, sync=True) +@retry_on_mvcc_error() def log_start_tuple(tuple_type, tuple_key): start_type = None From 437b8117ca94d687b70ebc526563d37a27330bd1 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 6 Aug 2019 12:02:20 +0200 Subject: [PATCH 190/457] ledger: add retry on MVCC errors when creating tuple --- substrabac/substrapp/serializers/ledger/testtuple/util.py | 3 ++- substrabac/substrapp/serializers/ledger/traintuple/util.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/testtuple/util.py b/substrabac/substrapp/serializers/ledger/testtuple/util.py index 62b9a1eb3..c21f8fec5 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/util.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/util.py @@ -1,8 +1,9 @@ from __future__ import absolute_import, unicode_literals -from substrapp.ledger_utils import invoke_ledger +from substrapp.ledger_utils import invoke_ledger, retry_on_mvcc_error +@retry_on_mvcc_error(nbtries=3) def createLedgerTesttuple(args, sync=False): return invoke_ledger(fcn='createTesttuple', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/traintuple/util.py b/substrabac/substrapp/serializers/ledger/traintuple/util.py index a910516e6..505d7530a 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/util.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/util.py @@ -1,8 +1,9 @@ from __future__ import absolute_import, unicode_literals -from substrapp.ledger_utils import invoke_ledger +from substrapp.ledger_utils import invoke_ledger, retry_on_mvcc_error +@retry_on_mvcc_error(nbtries=3) def createLedgerTraintuple(args, sync=False): return invoke_ledger(fcn='createTraintuple', args=args, sync=sync) From 3e5f5e21603b61b892194f4a8d886acf1a375535 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 19 Aug 2019 16:38:46 +0200 Subject: [PATCH 191/457] rename fltask to computePlanId --- substrabac/substrapp/tasks/tasks.py | 38 +++++++++++------------ substrabac/substrapp/tests/assets.py | 12 +++---- substrabac/substrapp/tests/tests_tasks.py | 4 +-- substrabac/substrapp/views/computeplan.py | 6 ++-- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 5e7deb8ff..c90a1f8a5 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -218,14 +218,14 @@ def prepare_task(tuple_type): def prepare_tuple(subtuple, tuple_type): from django_celery_results.models import TaskResult - fltask = None + compute_plan_id = None worker_queue = f"{settings.LEDGER['name']}.worker" - if 'fltask' in subtuple and subtuple['fltask']: - fltask = subtuple['fltask'] + if 'computePlanID' in subtuple and subtuple['computePlanID']: + compute_plan_id = subtuple['computePlanID'] flresults = TaskResult.objects.filter( task_name='substrapp.tasks.tasks.compute_task', - result__icontains=f'"fltask": "{fltask}"') + result__icontains=f'"computePlanID": "{compute_plan_id}"') if flresults and flresults.count() > 0: worker_queue = json.loads(flresults.first().as_dict()['result'])['worker'] @@ -241,7 +241,7 @@ def prepare_tuple(subtuple, tuple_type): try: compute_task.apply_async( - (tuple_type, subtuple, fltask), + (tuple_type, subtuple, compute_plan_id), queue=worker_queue) except Exception as e: error_code = compute_error_code(e) @@ -250,7 +250,7 @@ def prepare_tuple(subtuple, tuple_type): @app.task(bind=True, ignore_result=False) -def compute_task(self, tuple_type, subtuple, fltask): +def compute_task(self, tuple_type, subtuple, compute_plan_id): try: worker = self.request.hostname.split('@')[1] @@ -259,7 +259,7 @@ def compute_task(self, tuple_type, subtuple, fltask): worker = f"{settings.LEDGER['name']}.worker" queue = f"{settings.LEDGER['name']}" - result = {'worker': worker, 'queue': queue, 'fltask': fltask} + result = {'worker': worker, 'queue': queue, 'computePlanID': compute_plan_id} try: prepare_materials(subtuple, tuple_type) @@ -314,11 +314,11 @@ def do_task(subtuple, tuple_type): org_name = getattr(settings, 'ORG_NAME') # Federated learning variables - fltask = None + compute_plan_id = None flrank = None - if 'fltask' in subtuple and subtuple['fltask']: - fltask = subtuple['fltask'] + if 'computePlanID' in subtuple and subtuple['computePlanID']: + compute_plan_id = subtuple['computePlanID'] flrank = int(subtuple['rank']) client = docker.from_env() @@ -329,13 +329,13 @@ def do_task(subtuple, tuple_type): subtuple_directory, tuple_type, subtuple, - fltask, + compute_plan_id, flrank, org_name ) except Exception as e: # If an exception is thrown set flrank == -1 (we stop the fl training) - if fltask is not None: + if compute_plan_id is not None: flrank = -1 raise e finally: @@ -344,7 +344,7 @@ def do_task(subtuple, tuple_type): # Rank == -1 -> Last fl subtuple or fl throws an exception if flrank == -1: - flvolume = f'local-{fltask}-{org_name}' + flvolume = f'local-{compute_plan_id}-{org_name}' local_volume = client.volumes.get(volume_id=flvolume) try: local_volume.remove(force=True) @@ -354,7 +354,7 @@ def do_task(subtuple, tuple_type): return result -def _do_task(client, subtuple_directory, tuple_type, subtuple, fltask, flrank, org_name): +def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, flrank, org_name): # Job log job_task_log = '' @@ -387,7 +387,7 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, fltask, flrank, o algo_docker_name = f'{algo_docker}_{subtuple["key"]}' model_volume = {model_path: {'bind': '/sandbox/model', 'mode': 'rw'}} - if fltask is not None and flrank != -1: + if compute_plan_id is not None and flrank != -1: remove_image = False else: remove_image = True @@ -401,7 +401,7 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, fltask, flrank, o inmodels = [subtuple_model["traintupleKey"] for subtuple_model in subtuple['inModels']] algo_command = f"{algo_command} {' '.join(inmodels)}" - # add fltask rank for training + # add compute_plan_id rank for training if flrank is not None: algo_command = f"{algo_command} --rank {flrank}" @@ -411,9 +411,9 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, fltask, flrank, o inmodels = subtuple['model']["traintupleKey"] algo_command = f'{algo_command} {inmodels}' - # local volume for fltask - if fltask is not None and tuple_type == 'traintuple': - flvolume = f'local-{fltask}-{org_name}' + # local volume for compute_plan_id + if compute_plan_id is not None and tuple_type == 'traintuple': + flvolume = f'local-{compute_plan_id}-{org_name}' if flrank == 0: client.volumes.create(name=flvolume) else: diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index b8d0897e7..d322a2d63 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -138,7 +138,7 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, - "fltask": "", + "compute_plan_id": "", "inModels": None, "log": "[00-01-0032-8a01ed9]", "objective": { @@ -171,7 +171,7 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "fltask": "", + "compute_plan_id": "", "inModels": None, "log": "Train - CPU:268.84 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { @@ -207,7 +207,7 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, - "fltask": "", + "compute_plan_id": "", "inModels": None, "log": "[00-01-0032-4647065]", "objective": { @@ -282,7 +282,7 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, - "fltask": "", + "compute_plan_id": "", "inModels": None, "log": "[00-01-0032-8a01ed9]", "objective": { @@ -330,7 +330,7 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "fltask": "", + "compute_plan_id": "", "inModels": None, "log": "Train - CPU:268.84 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { @@ -403,7 +403,7 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, - "fltask": "", + "compute_plan_id": "", "inModels": None, "log": "[00-01-0032-4647065]", "objective": { diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index a4d643d52..18bed0f9a 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -524,7 +524,7 @@ def __init__(self): self.MEDIA_ROOT = MEDIA_ROOT - subtuple = [{'key': 'subtuple_test', 'fltask': 'flkey'}] + subtuple = [{'key': 'subtuple_test', 'computePlanID': 'flkey'}] with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ mock.patch.object(TaskResult.objects, 'filter') as mtaskresult, \ @@ -669,7 +669,7 @@ def __init__(self): self.MEDIA_ROOT = MEDIA_ROOT - subtuple = [{'key': 'subtuple_test', 'fltask': 'flkey'}] + subtuple = [{'key': 'subtuple_test', 'computePlanID': 'flkey'}] with mock.patch('substrapp.tasks.tasks.settings') as msettings, \ mock.patch('substrapp.tasks.tasks.get_hash') as mget_hash, \ diff --git a/substrabac/substrapp/views/computeplan.py b/substrabac/substrapp/views/computeplan.py index 1eb88f14a..f01790373 100644 --- a/substrabac/substrapp/views/computeplan.py +++ b/substrabac/substrapp/views/computeplan.py @@ -17,7 +17,7 @@ def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=dict(request.data)) serializer.is_valid(raise_exception=True) - # get fltask to handle 408 timeout in next invoke ledger request + # get compute_plan_id to handle 408 timeout in next invoke ledger request args = serializer.get_args(serializer.validated_data) try: ledger_response = query_ledger(fcn='createComputePlan', args=args) @@ -26,11 +26,11 @@ def create(self, request, *args, **kwargs): return Response(error, status=e.status) # create compute plan in ledger - fltask = ledger_response.get('fltask') + compute_plan_id = ledger_response.get('computePlanID') try: data = serializer.create(serializer.validated_data) except LedgerError as e: - error = {'message': str(e.msg), 'fltask': fltask} + error = {'message': str(e.msg), 'computePlanID': compute_plan_id} return Response(error, status=e.status) # send successful response From 4f2cae6fa01b909b2f229c291321a21313c2171d Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 22 Aug 2019 10:59:02 +0200 Subject: [PATCH 192/457] update populate: use add_data_samples to add many data samples --- populate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/populate.py b/populate.py index 89cd0400e..8a740193b 100644 --- a/populate.py +++ b/populate.py @@ -149,7 +149,7 @@ def do_populate(): 'data_manager_keys': [data_manager_org1_key], 'test_only': False, } - train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True, local=False) + train_data_sample_keys = get_or_create(data, org_1, 'data_samples', dryrun=True, local=False) else: print(f'register train data on datamanager {org_1} (will take datamanager creator as worker)') data = { @@ -160,7 +160,7 @@ def do_populate(): 'data_manager_keys': [data_manager_org1_key], 'test_only': False, } - train_data_sample_keys = get_or_create(data, org_1, 'data_sample', dryrun=True) + train_data_sample_keys = get_or_create(data, org_1, 'data_samples', dryrun=True) #################################################### @@ -195,7 +195,7 @@ def do_populate(): 'data_manager_keys': [data_manager_org0_key], 'test_only': True, } - test_data_sample_keys = get_or_create(data, org_0, 'data_sample') + test_data_sample_keys = get_or_create(data, org_0, 'data_samples') #################################################### @@ -208,7 +208,7 @@ def do_populate(): 'data_manager_keys': [data_manager_org0_key], 'test_only': True, } - get_or_create(data, org_0, 'data_sample') + get_or_create(data, org_0, 'data_samples') #################################################### @@ -221,7 +221,7 @@ def do_populate(): 'data_manager_keys': [data_manager_org0_key], 'test_only': True, } - get_or_create(data, org_0, 'data_sample') + get_or_create(data, org_0, 'data_samples') #################################################### From f19d251f19256b531d08b577cf869a9404bf6bde Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 22 Aug 2019 15:05:18 +0200 Subject: [PATCH 193/457] fix get owner method --- substrabac/events/apps.py | 4 ++-- substrabac/requirements.txt | 1 + substrabac/substrapp/tasks/tasks.py | 4 ++-- substrabac/substrapp/utils.py | 19 ++++++++++++++++++- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index eb4dd28fa..6ddb188fc 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -17,7 +17,7 @@ from hfc.protos.peer.transaction_pb2 import TxValidationCode from substrapp.tasks.tasks import prepare_tuple -from substrapp.utils import get_hash +from substrapp.utils import get_owner from celery.result import AsyncResult @@ -70,7 +70,7 @@ def on_tuples(block): def launch_tuple(_tuple, tuple_type): worker_queue = f"{LEDGER['name']}.worker" - data_owner = get_hash(LEDGER['signcert']) + data_owner = get_owner() if data_owner == _tuple['dataset']['worker'] and tuple_type is not None: tkey = _tuple['key'] diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index db437e65e..f0fc33fd4 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -19,6 +19,7 @@ mock==2.0.0 psycopg2-binary==2.7.4 protobuf == 3.6.0 pycryptodomex >= 3.4.2 +pyOpenSSL == 19.0.0 pysha3 == 1.0b1 raven == 6.9.0 requests == 2.20.0 diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 5e7deb8ff..19f1329b9 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -13,7 +13,7 @@ from celery.exceptions import Ignore from substrabac.celery import app -from substrapp.utils import get_hash, create_directory, get_remote_file, uncompress_content +from substrapp.utils import get_hash, get_owner, create_directory, get_remote_file, uncompress_content from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, query_tuples, LedgerError, LedgerStatusError) from substrapp.tasks.utils import ResourcesManager, compute_docker @@ -197,7 +197,7 @@ def prepare_testing_task(): def prepare_task(tuple_type): - data_owner = get_hash(settings.LEDGER['signcert']) + data_owner = get_owner() worker_queue = f"{settings.LEDGER['name']}.worker" tuples = query_tuples(tuple_type, data_owner) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index c26eb9412..297ad5303 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -1,6 +1,6 @@ - import io import hashlib +import OpenSSL import logging import os import tempfile @@ -83,6 +83,23 @@ def get_hash(file, key=None): return compute_hash(data, key) +def get_owner(): + ledger_settings = getattr(settings, 'LEDGER') + return get_hash_public_key(ledger_settings['signcert']) + + +def get_hash_public_key(file): + + with open(file, 'rb') as f: + cert = f.read() + + loaded_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) + pub_asn1 = OpenSSL.crypto.dump_publickey(OpenSSL.crypto.FILETYPE_ASN1, + loaded_cert.get_pubkey()) + + return compute_hash(pub_asn1) + + def compute_hash(bytes, key=None): sha256_hash = hashlib.sha256() From 1f86020de39495c64adcbd35824ff90fe11d5667 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 22 Aug 2019 15:14:18 +0200 Subject: [PATCH 194/457] fix tests --- substrabac/substrapp/tests/tests_tasks.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index a4d643d52..9ef6cdd2e 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -540,7 +540,8 @@ def __init__(self): mock.patch('substrapp.tasks.tasks.put_algo') as mput_algo, \ mock.patch('substrapp.tasks.tasks.json.loads') as mjson_loads, \ mock.patch('substrapp.tasks.tasks.AsyncResult') as masyncres, \ - mock.patch('substrapp.tasks.tasks.put_model') as mput_model: + mock.patch('substrapp.tasks.tasks.put_model') as mput_model, \ + mock.patch('substrapp.tasks.tasks.get_owner') as get_owner: msettings.return_value = FakeSettings() mget_hash.return_value = 'owkinhash' @@ -554,6 +555,7 @@ def __init__(self): mput_metric.return_value = 'metric' mput_algo.return_value = 'algo' mput_model.return_value = 'model' + get_owner.return_value = 'foo' masyncres.return_value.state = 'PENDING' From a19d7b4dc7b0627c260a9cb9e864f7e66ec61261 Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 30 Aug 2019 09:58:37 +0200 Subject: [PATCH 195/457] missing renaming of fltask --- .../substrapp/serializers/ledger/traintuple/serializer.py | 6 +++--- substrabac/substrapp/tests/query/tests_query_tuples.py | 4 ++-- substrabac/substrapp/views/traintuple.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py index 0b9022161..9efa6ded9 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/serializer.py @@ -12,7 +12,7 @@ class LedgerTrainTupleSerializer(serializers.Serializer): objective_key = serializers.CharField(min_length=64, max_length=64) rank = serializers.IntegerField(allow_null=True, required=False) rank = serializers.IntegerField(allow_null=True, required=False, default=0) - FLtask_key = serializers.CharField(min_length=64, max_length=64, allow_blank=True, required=False) + compute_plan_id = serializers.CharField(min_length=64, max_length=64, allow_blank=True, required=False) in_models_keys = serializers.ListField(child=serializers.CharField(min_length=64, max_length=64), min_length=0, required=False) @@ -26,7 +26,7 @@ def get_args(self, validated_data): objective_key = validated_data.get('objective_key') rank = validated_data.get('rank', '') rank = '' if rank is None else str(rank) - FLtask_key = validated_data.get('FLtask_key', '') + compute_plan_id = validated_data.get('compute_plan_id', '') train_data_sample_keys = validated_data.get('train_data_sample_keys', []) in_models_keys = validated_data.get('in_models_keys', []) tag = validated_data.get('tag', '') @@ -37,7 +37,7 @@ def get_args(self, validated_data): 'inModels': in_models_keys, 'dataManagerKey': data_manager_key, 'dataSampleKeys': train_data_sample_keys, - 'flTask': FLtask_key, + 'computePlanID': compute_plan_id, 'rank': rank, 'tag': tag } diff --git a/substrabac/substrapp/tests/query/tests_query_tuples.py b/substrabac/substrapp/tests/query/tests_query_tuples.py index 77148e582..51e11fe26 100644 --- a/substrabac/substrapp/tests/query/tests_query_tuples.py +++ b/substrabac/substrapp/tests/query/tests_query_tuples.py @@ -50,7 +50,7 @@ def test_add_traintuple_sync_ok(self): 'data_manager_key': self.fake_key, 'objective_key': self.fake_key, 'rank': -1, - 'FLtask_key': self.fake_key, + 'compute_plan_id': self.fake_key, 'in_models_keys': [self.fake_key]} extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', @@ -88,7 +88,7 @@ def test_add_traintuple_no_sync_ok(self): 'data_manager_key': self.fake_key, 'objective_key': self.fake_key, 'rank': -1, - 'FLtask_key': self.fake_key, + 'compute_plan_id': self.fake_key, 'in_models_keys': [self.fake_key]} extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 05ab08bc2..93ed768dd 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -35,7 +35,7 @@ def _create(self, request): 'data_manager_key': request.data.get('data_manager_key'), 'objective_key': request.data.get('objective_key'), 'rank': request.data.get('rank'), - 'FLtask_key': request.data.get('FLtask_key', ''), + 'compute_plan_id': request.data.get('compute_plan_id', ''), 'in_models_keys': request.data.getlist('in_models_keys'), # list of train data keys (which are stored in the train worker node) 'train_data_sample_keys': request.data.getlist('train_data_sample_keys'), From 9e17844a2fb17a6425ef9c69c7f41cf2cba8cf7c Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 29 Aug 2019 17:58:59 +0200 Subject: [PATCH 196/457] use MSP ID as node_id --- substrabac/substrapp/utils.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 297ad5303..85737110c 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -1,6 +1,5 @@ import io import hashlib -import OpenSSL import logging import os import tempfile @@ -85,19 +84,7 @@ def get_hash(file, key=None): def get_owner(): ledger_settings = getattr(settings, 'LEDGER') - return get_hash_public_key(ledger_settings['signcert']) - - -def get_hash_public_key(file): - - with open(file, 'rb') as f: - cert = f.read() - - loaded_cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) - pub_asn1 = OpenSSL.crypto.dump_publickey(OpenSSL.crypto.FILETYPE_ASN1, - loaded_cert.get_pubkey()) - - return compute_hash(pub_asn1) + return ledger_settings['client']['msp_id'] def compute_hash(bytes, key=None): From ec6a5683bddf72620225cfa54c4d86acc1487716 Mon Sep 17 00:00:00 2001 From: Samuel Date: Mon, 2 Sep 2019 15:28:00 +0200 Subject: [PATCH 197/457] events: update logs As far as I know we don't use debug logs to help debugging in a dev environment, it will be good to start to use logs instead of print. - add a debug log when a tuple is skipped due to a mismatching owner - remove call to print() in events - merge functions on_tuples and launch_tuple to improve readability (and limit nesting) - add settings in dev to setup a console handler for the events logger --- substrabac/events/apps.py | 44 +++++++++++++++------------ substrabac/substrabac/settings/dev.py | 12 +++++++- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 6ddb188fc..602bdeb1a 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -1,5 +1,6 @@ import asyncio import json +import logging import multiprocessing import os import contextlib @@ -21,8 +22,7 @@ from celery.result import AsyncResult -import logging - +logger = logging.getLogger(__name__) LEDGER = getattr(settings, 'LEDGER', None) @@ -53,35 +53,41 @@ def on_tuples(block): tx_validation_code = None payload = get_block_payload(block) + owner = get_owner() + worker_queue = f"{LEDGER['name']}.worker" for tuple_type, _tuples in payload.items(): - if _tuples: - for _tuple in _tuples: - tuple_key = _tuple['key'] - tuple_status = _tuple['status'] + if not _tuples: + continue - logging.info(f'[ChaincodeEvent] Received {tuple_type} "{tuple_status}" ' - f'(key: "{tuple_key}") with tx status: {tx_validation_code}') + for _tuple in _tuples: + key = _tuple['key'] + status = _tuple['status'] - if tuple_status == 'todo': - launch_tuple(_tuple, tuple_type) + logger.info(f'Processing task {key}: type={tuple_type} status={status}' + f' with tx status: {tx_validation_code}') + if status != 'todo': + continue -def launch_tuple(_tuple, tuple_type): + if tuple_type is None: + continue - worker_queue = f"{LEDGER['name']}.worker" - data_owner = get_owner() + tuple_owner = _tuple['dataset']['worker'] + if tuple_owner != owner: + logger.debug(f'Skipping task {key}: owner does not match' + f' ({tuple_owner} vs {owner})') + continue + + if AsyncResult(key).state != 'PENDING': + logger.info(f'Skipping task {key}: already exists') + continue - if data_owner == _tuple['dataset']['worker'] and tuple_type is not None: - tkey = _tuple['key'] - if AsyncResult(tkey).state == 'PENDING': prepare_tuple.apply_async( (_tuple, tuple_type), - task_id=tkey, + task_id=key, queue=worker_queue ) - else: - print(f'[ChaincodeEvent] Tuple task ({tkey}) already exists') def wait(): diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 125fca43a..9db133d2b 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -39,7 +39,7 @@ 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' }, 'simple': { - 'format': '%(levelname)s %(message)s' + 'format': '%(levelname)s - %(asctime)s - %(name)s - %(message)s' }, }, 'filters': { @@ -53,6 +53,11 @@ 'filters': ['require_debug_false'], 'class': 'django.utils.log.AdminEmailHandler' }, + 'console': { + 'level': 'DEBUG', + 'class': 'logging.StreamHandler', + 'formatter': 'simple' + }, 'error_file': { 'level': 'INFO', 'filename': os.path.join(PROJECT_ROOT, 'substrabac.log'), @@ -68,5 +73,10 @@ 'level': 'INFO', 'propagate': False, }, + 'events': { + 'handlers': ['console'], + 'level': 'DEBUG', + 'propagate': True, + }, } } From 5b156e63c41773bbbf2a76aa05e691b42ea178f7 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 3 Sep 2019 09:13:48 +0200 Subject: [PATCH 198/457] Add archive check in post view for objective and algo. --- .../objectives/objective0/metrics.zip | Bin 0 -> 610 bytes substrabac/substrapp/tests/common.py | 15 ++++++++++++--- .../tests/query/tests_query_objective.py | 4 ++++ .../tests/views/tests_views_objective.py | 18 ++++++++++++++---- substrabac/substrapp/utils.py | 16 ++++++++++++++++ substrabac/substrapp/views/algo.py | 6 +++++- substrabac/substrapp/views/objective.py | 5 ++++- 7 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 fixtures/chunantes/objectives/objective0/metrics.zip diff --git a/fixtures/chunantes/objectives/objective0/metrics.zip b/fixtures/chunantes/objectives/objective0/metrics.zip new file mode 100644 index 0000000000000000000000000000000000000000..f30d5acc37dda5e35ab7ffb9a1dfa65694fb814d GIT binary patch literal 610 zcmWIWW@Zs#-~htTp#OdhNPvq$fFU=vq$o4FSg)WmG=hggnKv)i(cdxlE29WQYJex# zVFR8$zeRT)Z4-L2b%OdAUZ>J030cQoi@bjQPP3hI&h?Ukl&+%}TdkU!}F(N#-TSc7f|CHMF*;rf2}U|vpj$h))z$McM4`m5(0VzrA% zePp_?<+t+|ryYJq|9ZCX-k~aKbavXa6?d=B-CJ+6H!|bFx|2_qn&jQoXLFFzG*&8+ zHR+i7sN=?);_t2f>|1O$&)2&BS?2i}@c?gj4&n1Z%r*dhsL9B{5P;X;F8RsXsYPj- zIjJCj+aUS7nETWBP!HX!-u`-*PM^81uji|!r|EUY)M$f&p-EGr_ovUrU2A#10O8IZ zO-_GBiZ%xub&Hg6i+t%8{v0&vllGU-+(Dm%x_2D<+q@^%ruo66m~;OaCvxpvsp>lO z Date: Tue, 3 Sep 2019 19:32:09 +0200 Subject: [PATCH 199/457] add logs when failing to build docker image --- substrabac/substrapp/tasks/utils.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index 0de2044be..86a420b2f 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -11,6 +11,8 @@ DOCKER_LABEL = 'substra_task' +logger = logging.getLogger(__name__) + def get_cpu_sets(cpu_count, concurrency): cpu_step = max(1, cpu_count // concurrency) @@ -188,9 +190,17 @@ def compute_docker(client, resources_manager, dockerfile_path, image_name, conta raise Exception(f'Dockerfile does not exist : {dockerfile_fullpath}') # Build metrics - client.images.build(path=dockerfile_path, - tag=image_name, - rm=remove_image) + try: + client.images.build(path=dockerfile_path, + tag=image_name, + rm=remove_image) + except docker.errors.BuildError as e: + # catch build errors and print them for easier debugging of failed build + lines = [line['stream'].strip() for line in e.build_log if 'stream' in line] + lines = [l for l in lines if l] + error = '\n'.join(lines) + logger.error(f'BuildError: {error}') + raise # Limit ressources memory_limit_mb = f'{resources_manager.memory_limit_mb()}M' @@ -303,7 +313,7 @@ def get_cpu_gpu_sets(cls): containers = [container.attrs for container in cls.__docker.containers.list(filters=filters)] except docker.errors.APIError as e: - logging.error(e, exc_info=True) + logger.error(e, exc_info=True) continue # CPU From 12ae77c840f832deac8bcc73931330182d2f4aea Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 3 Sep 2019 19:57:48 +0200 Subject: [PATCH 200/457] fix Zipfile extractall method As described in https://bugs.python.org/issue15795, the extractall method was not preserving the file permissions. Implement a workaround to ensure file permissions are kept. This is required as some scripts must be executable in order to build a docker image. --- substrabac/substrapp/utils.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 297ad5303..5fafedb38 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -137,9 +137,32 @@ def create_directory(directory): os.makedirs(directory) +class ZipFile(zipfile.ZipFile): + """Override Zipfile to ensure unix file permissions are preserved. + + This is due to a python bug: + https://bugs.python.org/issue15795 + + Workaround from: + https://stackoverflow.com/questions/39296101/python-zipfile-removes-execute-permissions-from-binaries + """ + + def extract(self, member, path=None, pwd=None): + if not isinstance(member, zipfile.ZipInfo): + member = self.getinfo(member) + + if path is None: + path = os.getcwd() + + ret_val = self._extract_member(member, path, pwd) + attr = member.external_attr >> 16 + os.chmod(ret_val, attr) + return ret_val + + def uncompress_path(archive_path, to_directory): if zipfile.is_zipfile(archive_path): - zip_ref = zipfile.ZipFile(archive_path, 'r') + zip_ref = ZipFile(archive_path, 'r') zip_ref.extractall(to_directory) zip_ref.close() elif tarfile.is_tarfile(archive_path): @@ -152,7 +175,7 @@ def uncompress_path(archive_path, to_directory): def uncompress_content(archive_content, to_directory): if zipfile.is_zipfile(io.BytesIO(archive_content)): - zip_ref = zipfile.ZipFile(io.BytesIO(archive_content)) + zip_ref = ZipFile(io.BytesIO(archive_content)) zip_ref.extractall(to_directory) zip_ref.close() else: From 1aa220984737023bff861079354d5127e0f504e8 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 3 Sep 2019 20:09:50 +0200 Subject: [PATCH 201/457] small refactoring In uncompress_path and uncompress_content methods use a context manager to open an archive. Unfortunately we cannot easily do a better refactoring as zipfile and tarfile have different interfaces. --- substrabac/substrapp/utils.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 5fafedb38..74e2276c6 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -162,27 +162,23 @@ def extract(self, member, path=None, pwd=None): def uncompress_path(archive_path, to_directory): if zipfile.is_zipfile(archive_path): - zip_ref = ZipFile(archive_path, 'r') - zip_ref.extractall(to_directory) - zip_ref.close() + with ZipFile(archive_path, 'r') as zf: + zf.extractall(to_directory) elif tarfile.is_tarfile(archive_path): - tar = tarfile.open(archive_path, 'r:*') - tar.extractall(to_directory) - tar.close() + with tarfile.open(archive_path, 'r:*') as tf: + tf.extractall(to_directory) else: raise Exception('Archive must be zip or tar.gz') def uncompress_content(archive_content, to_directory): if zipfile.is_zipfile(io.BytesIO(archive_content)): - zip_ref = ZipFile(io.BytesIO(archive_content)) - zip_ref.extractall(to_directory) - zip_ref.close() + with ZipFile(io.BytesIO(archive_content)) as zf: + zf.extractall(to_directory) else: try: - tar = tarfile.open(fileobj=io.BytesIO(archive_content)) - tar.extractall(to_directory) - tar.close() + with tarfile.open(fileobj=io.BytesIO(archive_content)) as tf: + tf.extractall(to_directory) except tarfile.TarError: raise Exception('Archive must be zip or tar.*') From bfae9f0862058f0d71c4e6445c0ac548a7dbd64b Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 2 Sep 2019 10:11:13 +0200 Subject: [PATCH 202/457] Update django number of fields in post --- substrabac/substrabac/settings/common.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 0044fcd0c..5a12f6321 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -150,3 +150,5 @@ CELERY_TASK_TRACK_STARTED = True # since 4.0 CELERY_WORKER_CONCURRENCY = 1 CELERY_BROKER_URL = os.environ.get('CELERY_BROKER_URL', 'amqp://localhost:5672//'), + +DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 From e9810079c7272d6646b321582dffa100f1077439 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 30 Aug 2019 09:18:36 +0200 Subject: [PATCH 203/457] (WIP) Add new url --- populate.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/populate.py b/populate.py index 8a740193b..66bb0a3f2 100644 --- a/populate.py +++ b/populate.py @@ -20,8 +20,10 @@ def setup_config(): print('Init config in /tmp/.substrabac for owkin and chunantes') - client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0') - client.add_profile('chunantes', 'http://chunantes.substrabac:8001', '0.0') + client.add_profile('owkin', 'http://substra-backend.peer-1', '0.0') + # client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0') + client.add_profile('chunantes', 'http://substra-backend.peer-2', '0.0') + # client.add_profile('chunantes', 'http://chunantes.substrabac:8001', '0.0') client.add_profile('clb', 'http://clb.substrabac:8002', '0.0') From bc1f8bcad199fb7c2208f233a7ab23803d327f76 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 2 Sep 2019 10:14:38 +0200 Subject: [PATCH 204/457] Add check in event app. --- substrabac/events/apps.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 602bdeb1a..0481318e0 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -19,6 +19,7 @@ from substrapp.tasks.tasks import prepare_tuple from substrapp.utils import get_owner +from substrapp.ledger_utils import get_hfc from celery.result import AsyncResult @@ -145,6 +146,10 @@ class EventsConfig(AppConfig): name = 'events' def ready(self): - # always wait + # always + + with get_hfc() as (loop, client): + print('Start the event application.') + p1 = multiprocessing.Process(target=wait) p1.start() From b43e79a2106d6a3f0b17ae685fa9e1bfa523e149 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 2 Sep 2019 10:17:43 +0200 Subject: [PATCH 205/457] Cleaning --- populate.py | 8 +++----- substrabac/events/apps.py | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/populate.py b/populate.py index 66bb0a3f2..3c496814f 100644 --- a/populate.py +++ b/populate.py @@ -20,11 +20,9 @@ def setup_config(): print('Init config in /tmp/.substrabac for owkin and chunantes') - client.add_profile('owkin', 'http://substra-backend.peer-1', '0.0') - # client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0') - client.add_profile('chunantes', 'http://substra-backend.peer-2', '0.0') - # client.add_profile('chunantes', 'http://chunantes.substrabac:8001', '0.0') - client.add_profile('clb', 'http://clb.substrabac:8002', '0.0') + client.add_profile('owkin', 'http://substrabac.peer-1', '0.0') + client.add_profile('chunantes', 'http://substrabac.peer-2', '0.0') + client.add_profile('clb', 'http://substrabac.peer-3', '0.0') def zip_folder(path, destination): diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 0481318e0..285b9a5eb 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -146,7 +146,6 @@ class EventsConfig(AppConfig): name = 'events' def ready(self): - # always with get_hfc() as (loop, client): print('Start the event application.') From ad5b5b8ebac4079bb9439bd282454c532d72473b Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 2 Sep 2019 18:01:47 +0200 Subject: [PATCH 206/457] Update populate. --- populate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/populate.py b/populate.py index 3c496814f..ab3113c1d 100644 --- a/populate.py +++ b/populate.py @@ -20,9 +20,9 @@ def setup_config(): print('Init config in /tmp/.substrabac for owkin and chunantes') - client.add_profile('owkin', 'http://substrabac.peer-1', '0.0') - client.add_profile('chunantes', 'http://substrabac.peer-2', '0.0') - client.add_profile('clb', 'http://substrabac.peer-3', '0.0') + client.add_profile('owkin', 'http://substrabac.node-1', '0.0') + client.add_profile('chunantes', 'http://substrabac.node-2', '0.0') + client.add_profile('clb', 'http://substrabac.node-3', '0.0') def zip_folder(path, destination): From 6ce24dff00819314d34cf50a503da7c15d2dcc31 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 3 Sep 2019 09:24:53 +0200 Subject: [PATCH 207/457] Add skaffold option in populate. --- populate.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/populate.py b/populate.py index ab3113c1d..4c9279fe9 100644 --- a/populate.py +++ b/populate.py @@ -18,11 +18,16 @@ client = substra.Client() -def setup_config(): +def setup_config(network='docker'): print('Init config in /tmp/.substrabac for owkin and chunantes') - client.add_profile('owkin', 'http://substrabac.node-1', '0.0') - client.add_profile('chunantes', 'http://substrabac.node-2', '0.0') - client.add_profile('clb', 'http://substrabac.node-3', '0.0') + if network == 'docker': + client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0') + client.add_profile('chunantes', 'http://chunantes.substrabac:8001', '0.0') + client.add_profile('clb', 'http://clb.substrabac:8002', '0.0') + if network == 'skaffold': + client.add_profile('owkin', 'http://substrabac.node-1', '0.0') + client.add_profile('chunantes', 'http://substrabac.node-2', '0.0') + client.add_profile('clb', 'http://substrabac.node-3', '0.0') def zip_folder(path, destination): @@ -92,7 +97,6 @@ def update_datamanager(data_manager_key, data, profile): def do_populate(): - setup_config() parser = argparse.ArgumentParser() group = parser.add_mutually_exclusive_group() @@ -104,9 +108,16 @@ def do_populate(): help='Launch populate with three orgs') parser.add_argument('-a', '--archive', action='store_true', help='Launch populate with archive data samples only') + parser.add_argument('-s', '--skaffold', action='store_true', + help='Launch populate with skaffold (K8S) network') parser.set_defaults(nb_org=2) args = vars(parser.parse_args()) + if args['skaffold']: + setup_config('skaffold') + else: + setup_config('docker') + if args['nb_org'] == 1: org_0 = org_1 = org_2 = 'owkin' elif args['nb_org'] == 2: From 92118cc9ef8c14f5bd3e4e0ab559a0613b3b6bb2 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 4 Sep 2019 14:15:33 +0200 Subject: [PATCH 208/457] Update along review. --- populate.py | 6 ++---- substrabac/events/apps.py | 4 +++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/populate.py b/populate.py index 4c9279fe9..999d27874 100644 --- a/populate.py +++ b/populate.py @@ -113,10 +113,8 @@ def do_populate(): parser.set_defaults(nb_org=2) args = vars(parser.parse_args()) - if args['skaffold']: - setup_config('skaffold') - else: - setup_config('docker') + network_type = 'skaffold' if args['skaffold'] else 'docker' + setup_config(network_type) if args['nb_org'] == 1: org_0 = org_1 = org_2 = 'owkin' diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 285b9a5eb..ef45ce6c6 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -147,8 +147,10 @@ class EventsConfig(AppConfig): def ready(self): + # We try to connect a client first, if it fails the backend will not start + # It avoid potential issue when we launch the channel event hub in a subprocess with get_hfc() as (loop, client): - print('Start the event application.') + logger.info('Start the event application.') p1 = multiprocessing.Process(target=wait) p1.start() From 8ca7caa87b094c2bef7493c9ba8431a2dc726dd1 Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Wed, 4 Sep 2019 17:39:20 +0200 Subject: [PATCH 209/457] Retrieve key directly from response --- substrabac/substrapp/ledger_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 960e4cd28..2b4886e75 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -43,8 +43,8 @@ def __repr__(self): @classmethod def from_response(cls, response): - pkhash = response['error'].replace('(', '').replace(')', '').split('tkey: ')[-1].strip() - if 'tkey: ' not in response['error'] or len(pkhash) != 64: + pkhash = response.get('key') + if not pkhash: return LedgerBadResponse(response['error']) return LedgerConflict(response['error'], pkhash=pkhash) From 4451a9f82e391266919535c7a803dd19c290a3d5 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Thu, 5 Sep 2019 11:43:50 +0200 Subject: [PATCH 210/457] Include chart --- charts/substrabac/.gitignore | 1 + charts/substrabac/.helmignore | 1 + charts/substrabac/Chart.yaml | 10 + charts/substrabac/Jenkinsfile | 40 ++++ charts/substrabac/README.md | 22 ++ charts/substrabac/requirements.lock | 9 + charts/substrabac/requirements.yaml | 9 + charts/substrabac/templates/_helpers.tpl | 16 ++ .../templates/configmap-backend.yaml | 48 +++++ .../templates/deployment-backend.yaml | 203 ++++++++++++++++++ .../templates/deployment-celerybeat.yaml | 154 +++++++++++++ .../templates/deployment-dryrunner.yaml | 173 +++++++++++++++ .../templates/deployment-flower.yaml | 57 +++++ .../templates/deployment-scheduler.yaml | 158 ++++++++++++++ .../templates/deployment-worker.yaml | 171 +++++++++++++++ .../substrabac/templates/ingress-backend.yaml | 38 ++++ .../substrabac/templates/service-backend.yaml | 50 +++++ .../substrabac/templates/service-flower.yaml | 50 +++++ charts/substrabac/templates/storage.yaml | 27 +++ charts/substrabac/values.yaml | 201 +++++++++++++++++ 20 files changed, 1438 insertions(+) create mode 100644 charts/substrabac/.gitignore create mode 100644 charts/substrabac/.helmignore create mode 100644 charts/substrabac/Chart.yaml create mode 100644 charts/substrabac/Jenkinsfile create mode 100644 charts/substrabac/README.md create mode 100644 charts/substrabac/requirements.lock create mode 100644 charts/substrabac/requirements.yaml create mode 100644 charts/substrabac/templates/_helpers.tpl create mode 100644 charts/substrabac/templates/configmap-backend.yaml create mode 100644 charts/substrabac/templates/deployment-backend.yaml create mode 100644 charts/substrabac/templates/deployment-celerybeat.yaml create mode 100644 charts/substrabac/templates/deployment-dryrunner.yaml create mode 100644 charts/substrabac/templates/deployment-flower.yaml create mode 100644 charts/substrabac/templates/deployment-scheduler.yaml create mode 100644 charts/substrabac/templates/deployment-worker.yaml create mode 100644 charts/substrabac/templates/ingress-backend.yaml create mode 100644 charts/substrabac/templates/service-backend.yaml create mode 100644 charts/substrabac/templates/service-flower.yaml create mode 100644 charts/substrabac/templates/storage.yaml create mode 100644 charts/substrabac/values.yaml diff --git a/charts/substrabac/.gitignore b/charts/substrabac/.gitignore new file mode 100644 index 000000000..ee3892e87 --- /dev/null +++ b/charts/substrabac/.gitignore @@ -0,0 +1 @@ +charts/ diff --git a/charts/substrabac/.helmignore b/charts/substrabac/.helmignore new file mode 100644 index 000000000..6b8710a71 --- /dev/null +++ b/charts/substrabac/.helmignore @@ -0,0 +1 @@ +.git diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml new file mode 100644 index 000000000..70ae60f1e --- /dev/null +++ b/charts/substrabac/Chart.yaml @@ -0,0 +1,10 @@ +name: substrabac +home: https://substra.org/ +version: 1.0.0-alpha.1 +description: Main package for Substra +icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 +sources: + - https://github.com/SubstraFoudation/substrabac +maintainers: + - name: ClementGautier + email: clement@gautier.im diff --git a/charts/substrabac/Jenkinsfile b/charts/substrabac/Jenkinsfile new file mode 100644 index 000000000..f2c81d795 --- /dev/null +++ b/charts/substrabac/Jenkinsfile @@ -0,0 +1,40 @@ +pipeline { + options { + timestamps () + timeout(time: 1, unit: 'HOURS') + buildDiscarder(logRotator(numToKeepStr: '5')) + skipDefaultCheckout true + } + + agent { + kubernetes { + label 'chart-substra' + defaultContainer 'build' + yamlFile '.cicd/agent-build.yaml' + } + } + + stages { + stage('Test') { + steps { + dir("substra") { + checkout scm + sh "helm lint" + } + } + } + + stage('Publish') { + when { buildingTag() } + steps { + dir("substra") { + checkout scm + sh "helm init --client-only" + sh "helm plugin install https://github.com/chartmuseum/helm-push" + sh "helm repo add substra https://substra-charts.owkin.com --username owlways --password Cokear4nnRK9ooC" + sh "helm push . substra" + } + } + } + } +} diff --git a/charts/substrabac/README.md b/charts/substrabac/README.md new file mode 100644 index 000000000..e0d45f768 --- /dev/null +++ b/charts/substrabac/README.md @@ -0,0 +1,22 @@ +# Main deployment package of Substra + +## Requirements + +Having a Kubernetes cluster working with Helm initialized. You can do thant locally by installing Minikube and grabbing Helm binary from github. +Then simply launch your cluster using `minikube start` and configure helm with `helm init`. + +You will also need the Hyperledger Fabric network setup on the cluster. +Look at the corresponding chart for that (chart-substra-network-tools) + +You will also need a postgresql instance on the cluster, it should already be the case if you install the network first. + +## Install the package +``` +helm install --name substra-network-tools owkin/substra-network-tools +helm install --name substra owkin/substra +``` + +### Cleanup +``` +helm delete --purge substra-network-tools substra +``` diff --git a/charts/substrabac/requirements.lock b/charts/substrabac/requirements.lock new file mode 100644 index 000000000..17d707909 --- /dev/null +++ b/charts/substrabac/requirements.lock @@ -0,0 +1,9 @@ +dependencies: +- name: rabbitmq + repository: https://kubernetes-charts.storage.googleapis.com/ + version: 6.2.6 +- name: postgresql + repository: https://kubernetes-charts.storage.googleapis.com/ + version: 6.2.1 +digest: sha256:f2534148823dfb50af552d37e81afac8e298073730c21bd14d3f471356b2aa09 +generated: "2019-09-05T11:09:00.717234726+02:00" diff --git a/charts/substrabac/requirements.yaml b/charts/substrabac/requirements.yaml new file mode 100644 index 000000000..b613c0a93 --- /dev/null +++ b/charts/substrabac/requirements.yaml @@ -0,0 +1,9 @@ +dependencies: + - name: rabbitmq + repository: https://kubernetes-charts.storage.googleapis.com/ + condition: rabbitmq.enabled + version: ~6.2.5 + - name: postgresql + repository: https://kubernetes-charts.storage.googleapis.com/ + version: ~6.2.0 + condition: postgresql.enabled diff --git a/charts/substrabac/templates/_helpers.tpl b/charts/substrabac/templates/_helpers.tpl new file mode 100644 index 000000000..3868c7f06 --- /dev/null +++ b/charts/substrabac/templates/_helpers.tpl @@ -0,0 +1,16 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "substra.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "substra.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/charts/substrabac/templates/configmap-backend.yaml b/charts/substrabac/templates/configmap-backend.yaml new file mode 100644 index 000000000..1fe400cf6 --- /dev/null +++ b/charts/substrabac/templates/configmap-backend.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "substra.fullname" . }}-backend +data: + conf.json: | + { + "name": "{{ .Values.organization.name }}", + "signcert": "/var/hyperledger/msp/signcerts/cert.pem", + "core_peer_mspconfigpath": "/var/hyperledger/msp", + "channel_name": "{{ .Values.channel }}", + "chaincode_name": "{{ .Values.chaincode.name }}", + "chaincode_version": "{{ .Values.chaincode.version }}", + "client": { + "name": "{{ .Values.user.name }}", + "org": "{{ .Values.organization.name }}", + "state_store": "/tmp/hfc-cvs", + "key_path": "/var/hyperledger/msp/keystore/*", + "cert_path": "/var/hyperledger/msp/signcerts/cert.pem", + "msp_id": "{{ .Values.peer.mspID }}" + }, + "peer": { + "name": "peer", + "host": "{{ .Values.peer.host }}", + "port": { + "internal": {{ .Values.peer.port }}, + "external": {{ .Values.peer.port }} + }, + "docker_core_dir": "/var/hyperledger/fabric_cfg", + "tlsCACerts": "/var/hyperledger/admin_msp/cacerts/cacert.pem", + "clientKey": "/var/hyperledger/tls/client/pair/tls.key", + "clientCert": "/var/hyperledger/tls/client/pair/tls.crt", + "grpcOptions": { + "grpc-max-send-message-length": 15, + "grpc.ssl_target_name_override": "{{ .Values.peer.host }}" + } + }, + "orderer": { + "name": "{{ .Values.orderer.name }}", + "host": "{{ .Values.orderer.host }}", + "port": {{ .Values.orderer.port }}, + "ca": "/var/hyperledger/tls/ord/cert/cacert.pem", + "grpcOptions": { + "grpc-max-send-message-length": 15, + "grpc.ssl_target_name_override": "{{ .Values.orderer.host }}" + } + } + } diff --git a/charts/substrabac/templates/deployment-backend.yaml b/charts/substrabac/templates/deployment-backend.yaml new file mode 100644 index 000000000..44a88b5c6 --- /dev/null +++ b/charts/substrabac/templates/deployment-backend.yaml @@ -0,0 +1,203 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "substra.fullname" . }}-backend + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" . }}-backend + app.kubernetes.io/part-of: {{ template "substra.name" . }} +spec: + replicas: {{ .Values.backend.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "substra.name" . }}-backend + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "substra.name" . }}-backend + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + {{- with .Values.backend.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - name: {{ template "substra.name" . }} + image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}" + {{- if .Values.backend.image.pullPolicy }} + imagePullPolicy: "{{ .Values.backend.image.pullPolicy }}" + {{- end }} + command: ["/bin/bash"] + args: ["-c", "sed -i '7d' substrabac/settings/prod.py; python manage.py migrate; touch /ready; DJANGO_SETTINGS_MODULE={{ .Values.backend.djangoSettingsModuleEvent }} python3 manage.py runserver --noreload 0.0.0.0:8000"] + env: + - name: ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_{{ .Values.organization.name | upper }}_DB_NAME + value: {{ .Values.postgresql.postgresqlDatabase }} + - name: SUBSTRABAC_DB_USER + value: {{ .Values.postgresql.postgresqlUsername }} + - name: SUBSTRABAC_DB_PWD + value: {{ .Values.postgresql.postgresqlPassword }} + - name: DATABASE_HOST + value: {{ .Release.Name }}-postgresql + - name: DJANGO_SETTINGS_MODULE + value: {{ .Values.backend.djangoSettingsModule }} + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric_cfg + - name: CORE_PEER_ADDRESS_ENV + value: "{{ .Values.peer.host }}:{{ .Values.peer.port }}" + - name: FABRIC_LOGGING_SPEC + value: debug + - name: DEFAULT_DOMAIN + value: "{{ .Values.backend.defaultDomain }}" + - name: CELERY_BROKER_URL + value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" + {{- with .Values.backend.auth }} + - name: BACK_AUTH_USER + value: {{ .user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ .password | quote }} + {{- else }} + - name: BACK_AUTH_USER + value: "" + - name: BACK_AUTH_PASSWORD + value: "" + {{- end }} + - name: SUBSTRABAC_DEFAULT_PORT + value: {{ .Values.backend.service.port | quote}} + - name: SUBSTRABAC_PEER_PORT + value: "internal" + - name: LEDGER_CONFIG_FILE + value: /conf/{{ .Values.organization.name }}/substrabac/conf.json + - name: PYTHONUNBUFFERED + value: "1" + - name: MEDIA_ROOT + value: {{ .Values.persistence.hostPath }}/medias/ + ports: + - name: http + containerPort: {{ .Values.backend.service.port }} + protocol: TCP + volumeMounts: + - mountPath: {{ .Values.persistence.hostPath }} + name: data + - mountPath: /conf/{{ .Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/fabric_cfg + name: fabric + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + livenessProbe: + httpGet: + path: / + port: http + httpHeaders: + - name: Accept + value: "text/html;version=0.0, */*;version=0.0" + {{- with .Values.backend.auth }} + - name: Authorization + value: {{ .header | quote }} + {{- end }} + initialDelaySeconds: 60 + timeoutSeconds: 5 + failureThreshold: 6 + readinessProbe: + httpGet: + path: / + port: http + httpHeaders: + - name: Accept + value: "text/html;version=0.0, */*;version=0.0" + {{- with .Values.backend.auth }} + - name: Authorization + value: {{ .header | quote }} + {{- end }} + initialDelaySeconds: 10 + timeoutSeconds: 2 + periodSeconds: 5 + resources: + {{- toYaml .Values.backend.resources | nindent 12 }} + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" . }} + - name: config + configMap: + name: {{ include "substra.fullname" . }}-backend + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ $.Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ $.Values.secrets.key }} + - name: cacert + secret: + secretName: {{ $.Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ $.Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ $.Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ $.Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ $.Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ $.Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + {{- with .Values.backend.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.backend.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.backend.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/substrabac/templates/deployment-celerybeat.yaml b/charts/substrabac/templates/deployment-celerybeat.yaml new file mode 100644 index 000000000..02e64f256 --- /dev/null +++ b/charts/substrabac/templates/deployment-celerybeat.yaml @@ -0,0 +1,154 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "substra.fullname" . }}-celerybeat + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" . }}-celerybeat + app.kubernetes.io/part-of: {{ template "substra.name" . }} +spec: + replicas: {{ .Values.celerybeat.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "substra.name" . }}-celerybeat + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "substra.name" . }}-celerybeat + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + {{- with .Values.celerybeat.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - name: celerybeat + image: "{{ .Values.celerybeat.image.repository }}:{{ .Values.celerybeat.image.tag }}" + {{- if .Values.celerybeat.image.pullPolicy }} + imagePullPolicy: "{{ .Values.celerybeat.image.pullPolicy }}" + {{- end }} + command: ["celery"] + args: ["-A", "substrabac", "beat", "-l", "debug"] + env: + - name: ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ .Values.organization.name }} + {{- with .Values.backend.auth }} + - name: BACK_AUTH_USER + value: {{ .user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ .password | quote }} + {{- else }} + - name: BACK_AUTH_USER + value: "" + - name: BACK_AUTH_PASSWORD + value: "" + {{- end }} + - name: CELERY_BROKER_URL + value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" + - name: DJANGO_SETTINGS_MODULE + value: substrabac.settings.common + - name: PYTHONUNBUFFERED + value: "1" + - name: SUBSTRABAC_{{ .Values.organization.name | upper }}_DB_NAME + value: {{ .Values.postgresql.postgresqlDatabase }} + - name: SUBSTRABAC_DB_USER + value: {{ .Values.postgresql.postgresqlUsername }} + - name: SUBSTRABAC_DB_PWD + value: {{ .Values.postgresql.postgresqlPassword }} + - name: DATABASE_HOST + value: {{ .Release.Name }}-postgresql + - name: DJANGO_SETTINGS_MODULE + value: {{ .Values.backend.djangoSettingsModule }} + - name: LEDGER_CONFIG_FILE + value: /conf/{{ .Values.organization.name }}/substrabac/conf.json + volumeMounts: + - mountPath: /conf/{{ .Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + resources: + {{- toYaml .Values.celerybeat.resources | nindent 12 }} + volumes: + - name: config + configMap: + name: {{ include "substra.fullname" . }}-backend + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" . }} + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ $.Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ $.Values.secrets.key }} + - name: cacert + secret: + secretName: {{ $.Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ $.Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ $.Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ $.Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ $.Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ $.Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + {{- with .Values.celerybeat.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.celerybeat.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.celerybeat.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/substrabac/templates/deployment-dryrunner.yaml b/charts/substrabac/templates/deployment-dryrunner.yaml new file mode 100644 index 000000000..8c95f0d36 --- /dev/null +++ b/charts/substrabac/templates/deployment-dryrunner.yaml @@ -0,0 +1,173 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "substra.fullname" . }}-dryrunner + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" . }}-dryrunner + app.kubernetes.io/part-of: {{ template "substra.name" . }} +spec: + replicas: {{ .Values.celeryworker.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "substra.name" . }}-dryrunner + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "substra.name" . }}-dryrunner + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + {{- with .Values.celeryworker.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - name: dryrunner + image: "{{ .Values.celeryworker.image.repository }}:{{ .Values.celeryworker.image.tag }}" + {{- if .Values.celeryworker.image.pullPolicy }} + imagePullPolicy: "{{ .Values.celeryworker.image.pullPolicy }}" + {{- end }} + command: ["celery"] + args: ["-A", "substrabac", "worker", "-E", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},{{ .Values.organization.name }}.dryrunner,celery", "--hostname", "{{ .Values.organization.name }}.dryrunner"] + env: + - name: ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_DEFAULT_PORT + value: "8000" + - name: CELERY_BROKER_URL + value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" + - name: DJANGO_SETTINGS_MODULE + value: {{ .Values.backend.djangoSettingsModule }} + - name: PYTHONUNBUFFERED + value: "1" + {{- with .Values.backend.auth }} + - name: BACK_AUTH_USER + value: {{ .user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ .password | quote }} + {{- else }} + - name: BACK_AUTH_USER + value: "" + - name: BACK_AUTH_PASSWORD + value: "" + {{- end }} + - name: DATABASE_HOST + value: {{ .Release.Name }}-postgresql + - name: FABRIC_CFG_PATH_ENV + value: /var/hyperledger/fabric_cfg + - name: CORE_PEER_ADDRESS_ENV + value: "{{ .Values.peer.host }}:{{ .Values.peer.port }}" + - name: FABRIC_LOGGING_SPEC + value: debug + - name: DEFAULT_DOMAIN + value: "{{ .Values.backend.defaultDomain }}" + - name: SUBSTRABAC_{{ .Values.organization.name | upper }}_DB_NAME + value: {{ .Values.postgresql.postgresqlDatabase }} + - name: SUBSTRABAC_DB_USER + value: {{ .Values.postgresql.postgresqlUsername }} + - name: SUBSTRABAC_DB_PWD + value: {{ .Values.postgresql.postgresqlPassword }} + - name: DATABASE_HOST + value: {{ .Release.Name }}-postgresql + - name: MEDIA_ROOT + value: {{ .Values.persistence.hostPath }}/medias/ + - name: LEDGER_CONFIG_FILE + value: /conf/{{ .Values.organization.name }}/substrabac/conf.json + volumeMounts: + - mountPath: /host/var/run/docker.sock + name: dockersocket + - mountPath: {{ .Values.persistence.hostPath }} + name: data + - mountPath: /conf/{{ .Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + resources: + {{- toYaml .Values.celeryworker.resources | nindent 12 }} + volumes: + - name: dockersocket + hostPath: + path: /var/run/docker.sock + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" . }} + - name: config + configMap: + name: {{ include "substra.fullname" . }}-backend + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ $.Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ $.Values.secrets.key }} + - name: cacert + secret: + secretName: {{ $.Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ $.Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ $.Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ $.Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ $.Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ $.Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + {{- with .Values.celeryworker.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.celeryworker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.celeryworker.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/substrabac/templates/deployment-flower.yaml b/charts/substrabac/templates/deployment-flower.yaml new file mode 100644 index 000000000..325f5da8f --- /dev/null +++ b/charts/substrabac/templates/deployment-flower.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "substra.fullname" . }}-flower + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" . }}-flower + app.kubernetes.io/part-of: {{ template "substra.name" . }} +spec: + replicas: {{ .Values.flower.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "substra.name" . }}-flower + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "substra.name" . }}-flower + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + {{- with .Values.flower.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - name: flower + image: "{{ .Values.flower.image.repository }}:{{ .Values.flower.image.tag }}" + {{- if .Values.flower.image.pullPolicy }} + imagePullPolicy: "{{ .Values.flower.image.pullPolicy }}" + {{- end }} + command: ["celery"] + args: ["flower", "-A", "substrabac"] + env: + - name: CELERY_BROKER_URL + value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" + - name: DJANGO_SETTINGS_MODULE + value: substrabac.settings.common + - name: PYTHONUNBUFFERED + value: "1" + resources: + {{- toYaml .Values.flower.resources | nindent 12 }} + {{- with .Values.flower.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.flower.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.flower.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/substrabac/templates/deployment-scheduler.yaml b/charts/substrabac/templates/deployment-scheduler.yaml new file mode 100644 index 000000000..87c2b31e6 --- /dev/null +++ b/charts/substrabac/templates/deployment-scheduler.yaml @@ -0,0 +1,158 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "substra.fullname" . }}-scheduler + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" . }}-scheduler + app.kubernetes.io/part-of: {{ template "substra.name" . }} +spec: + replicas: {{ .Values.celeryworker.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "substra.name" . }}-scheduler + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "substra.name" . }}-scheduler + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + {{- with .Values.celeryworker.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - name: scheduler + image: "{{ .Values.celeryworker.image.repository }}:{{ .Values.celeryworker.image.tag }}" + {{- if .Values.celeryworker.image.pullPolicy }} + imagePullPolicy: "{{ .Values.celeryworker.image.pullPolicy }}" + {{- end }} + command: ["celery"] + args: ["-A", "substrabac", "worker", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},scheduler,celery", "--hostname", "{{ .Values.organization.name }}.scheduler"] + env: + - name: ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_DEFAULT_PORT + value: "8000" + - name: CELERY_BROKER_URL + value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" + - name: DJANGO_SETTINGS_MODULE + value: {{ .Values.backend.djangoSettingsModule }} + - name: PYTHONUNBUFFERED + value: "1" + {{- with .Values.backend.auth }} + - name: BACK_AUTH_USER + value: {{ .user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ .password | quote }} + {{- else }} + - name: BACK_AUTH_USER + value: "" + - name: BACK_AUTH_PASSWORD + value: "" + {{- end }} + - name: DATABASE_HOST + value: {{ .Release.Name }}-postgresql + - name: FABRIC_CFG_PATH_ENV + value: /var/hyperledger/fabric_cfg + - name: CORE_PEER_ADDRESS_ENV + value: "{{ .Values.peer.host }}:{{ .Values.peer.port }}" + - name: FABRIC_LOGGING_SPEC + value: debug + - name: MEDIA_ROOT + value: {{ .Values.persistence.hostPath }}/medias/ + - name: LEDGER_CONFIG_FILE + value: /conf/{{ .Values.organization.name }}/substrabac/conf.json + volumeMounts: + - mountPath: {{ .Values.persistence.hostPath }} + name: data + - mountPath: /conf/{{ .Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + resources: + {{- toYaml .Values.celeryworker.resources | nindent 12 }} + volumes: + - name: config + configMap: + name: {{ include "substra.fullname" . }}-backend + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" . }} + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ $.Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ $.Values.secrets.key }} + - name: cacert + secret: + secretName: {{ $.Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ $.Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ $.Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ $.Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ $.Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ $.Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + {{- with .Values.celeryworker.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.celeryworker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.celeryworker.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/substrabac/templates/deployment-worker.yaml b/charts/substrabac/templates/deployment-worker.yaml new file mode 100644 index 000000000..6872f8054 --- /dev/null +++ b/charts/substrabac/templates/deployment-worker.yaml @@ -0,0 +1,171 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "substra.fullname" . }}-worker + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" . }}-worker + app.kubernetes.io/part-of: {{ template "substra.name" . }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ template "substra.name" . }}-worker + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "substra.name" . }}-worker + app.kubernetes.io/instance: {{ .Release.Name }} + spec: + {{- with .Values.celeryworker.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - name: worker + image: "{{ .Values.celeryworker.image.repository }}:{{ .Values.celeryworker.image.tag }}" + {{- if .Values.celeryworker.image.pullPolicy }} + imagePullPolicy: "{{ .Values.celeryworker.image.pullPolicy }}" + {{- end }} + command: ["celery"] + args: ["-A", "substrabac", "worker", "-E", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},{{ .Values.organization.name }}.worker,celery", "--hostname", "{{ .Values.organization.name }}.worker"] + env: + - name: ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ .Values.organization.name }} + - name: SUBSTRABAC_DEFAULT_PORT + value: "8000" + - name: CELERY_BROKER_URL + value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" + - name: DJANGO_SETTINGS_MODULE + value: {{ .Values.backend.djangoSettingsModule }} + - name: PYTHONUNBUFFERED + value: "1" + {{- with .Values.backend.auth }} + - name: BACK_AUTH_USER + value: {{ .user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ .password | quote }} + {{- else }} + - name: BACK_AUTH_USER + value: "" + - name: BACK_AUTH_PASSWORD + value: "" + {{- end }} + - name: DEFAULT_DOMAIN + value: "{{ .Values.backend.defaultDomain }}" + - name: SUBSTRABAC_{{ .Values.organization.name | upper }}_DB_NAME + value: {{ .Values.postgresql.postgresqlDatabase }} + - name: SUBSTRABAC_DB_USER + value: {{ .Values.postgresql.postgresqlUsername }} + - name: SUBSTRABAC_DB_PWD + value: {{ .Values.postgresql.postgresqlPassword }} + - name: DATABASE_HOST + value: {{ .Release.Name }}-postgresql + - name: FABRIC_CFG_PATH_ENV + value: /var/hyperledger/fabric_cfg + - name: CORE_PEER_ADDRESS_ENV + value: "{{ .Values.peer.host }}:{{ .Values.peer.port }}" + - name: FABRIC_LOGGING_SPEC + value: debug + - name: MEDIA_ROOT + value: {{ .Values.persistence.hostPath }}/medias/ + - name: LEDGER_CONFIG_FILE + value: /conf/{{ .Values.organization.name }}/substrabac/conf.json + volumeMounts: + - mountPath: /var/run/docker.sock + name: dockersocket + - mountPath: {{ .Values.persistence.hostPath }} + name: data + - mountPath: /conf/{{ .Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + resources: + {{- toYaml .Values.celeryworker.resources | nindent 12 }} + volumes: + - name: dockersocket + hostPath: + path: /var/run/docker.sock + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" . }} + - name: config + configMap: + name: {{ include "substra.fullname" . }}-backend + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ .Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ .Values.secrets.key }} + - name: cacert + secret: + secretName: {{ .Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ .Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ .Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ .Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ .Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ .Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ .Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ .Values.secrets.tlsRootCert }} + {{- with .Values.celeryworker.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.celeryworker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.celeryworker.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/substrabac/templates/ingress-backend.yaml b/charts/substrabac/templates/ingress-backend.yaml new file mode 100644 index 000000000..e20669183 --- /dev/null +++ b/charts/substrabac/templates/ingress-backend.yaml @@ -0,0 +1,38 @@ +{{- if .Values.backend.ingress.enabled -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ template "substra.fullname" . }}-backend + labels: + app.kubernetes.io/name: {{ template "substra.fullname" . }}-backend + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- with .Values.backend.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.backend.ingress.tls }} + tls: + {{- range .Values.backend.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.backend.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ template "substra.fullname" $ }}-backend + servicePort: http + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/substrabac/templates/service-backend.yaml b/charts/substrabac/templates/service-backend.yaml new file mode 100644 index 000000000..1445ea544 --- /dev/null +++ b/charts/substrabac/templates/service-backend.yaml @@ -0,0 +1,50 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "substra.fullname" . }}-backend + labels: + app.kubernetes.io/name: {{ template "substra.name" . }}-backend + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ template "substra.name" . }} + {{- if .Values.backend.service.labels }} + {{- toYaml .Values.backend.service.labels | nindent 4 }} + {{- end }} + {{- if .Values.backend.service.annotations }} + annotations: + {{- toYaml .Values.backend.service.annotations | nindent 4 }} + {{- end }} +spec: +{{- if (or (eq .Values.backend.service.type "ClusterIP") (empty .Values.backend.service.type)) }} + type: ClusterIP + {{- if .Values.backend.service.clusterIP }} + clusterIP: {{ .Values.backend.service.clusterIP }} + {{end}} +{{- else if eq .Values.backend.service.type "LoadBalancer" }} + type: {{ .Values.backend.service.type }} + {{- if .Values.backend.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.backend.service.loadBalancerIP }} + {{- end }} + {{- if .Values.backend.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml .Values.backend.service.loadBalancerSourceRanges | indent 4 }} + {{- end -}} +{{- else }} + type: {{ .Values.backend.service.type }} +{{- end }} +{{- if .Values.backend.service.externalIPs }} + externalIPs: +{{ toYaml .Values.backend.service.externalIPs | indent 4 }} +{{- end }} + ports: + - name: http + port: {{ .Values.backend.service.port }} + protocol: TCP + targetPort: 8000 +{{ if (and (eq .Values.backend.service.type "NodePort") (not (empty .Values.backend.service.nodePort))) }} + nodePort: {{.Values.backend.service.nodePort}} +{{ end }} + selector: + app.kubernetes.io/name: {{ template "substra.name" . }}-backend + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/charts/substrabac/templates/service-flower.yaml b/charts/substrabac/templates/service-flower.yaml new file mode 100644 index 000000000..66f68133c --- /dev/null +++ b/charts/substrabac/templates/service-flower.yaml @@ -0,0 +1,50 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "substra.fullname" . }}-flower + labels: + app.kubernetes.io/name: {{ template "substra.name" . }}-flower + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/part-of: {{ template "substra.name" . }} + {{- if .Values.flower.service.labels }} + {{- toYaml .Values.flower.service.labels | nindent 4 }} + {{- end }} + {{- if .Values.flower.service.annotations }} + annotations: + {{- toYaml .Values.flower.service.annotations | nindent 4 }} + {{- end }} +spec: +{{- if (or (eq .Values.flower.service.type "ClusterIP") (empty .Values.flower.service.type)) }} + type: ClusterIP + {{- if .Values.flower.service.clusterIP }} + clusterIP: {{ .Values.flower.service.clusterIP }} + {{end}} +{{- else if eq .Values.flower.service.type "LoadBalancer" }} + type: {{ .Values.flower.service.type }} + {{- if .Values.flower.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.flower.service.loadBalancerIP }} + {{- end }} + {{- if .Values.flower.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml .Values.flower.service.loadBalancerSourceRanges | indent 4 }} + {{- end -}} +{{- else }} + type: {{ .Values.flower.service.type }} +{{- end }} +{{- if .Values.flower.service.externalIPs }} + externalIPs: +{{ toYaml .Values.flower.service.externalIPs | indent 4 }} +{{- end }} + ports: + - name: http + port: {{ .Values.flower.service.port }} + protocol: TCP + targetPort: 5555 +{{ if (and (eq .Values.flower.service.type "NodePort") (not (empty .Values.flower.service.nodePort))) }} + nodePort: {{.Values.flower.service.nodePort}} +{{ end }} + selector: + app.kubernetes.io/name: {{ template "substra.name" . }}-flower + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/charts/substrabac/templates/storage.yaml b/charts/substrabac/templates/storage.yaml new file mode 100644 index 000000000..213671680 --- /dev/null +++ b/charts/substrabac/templates/storage.yaml @@ -0,0 +1,27 @@ +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "substra.fullname" . }} +spec: + storageClassName: "" + accessModes: + - ReadWriteMany + resources: + requests: + storage: {{ .Values.persistence.size | quote }} +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{ template "substra.fullname" . }} +spec: + storageClassName: "" + persistentVolumeReclaimPolicy: Recycle + capacity: + storage: {{ .Values.persistence.size | quote }} + accessModes: + - ReadWriteMany + hostPath: + path: {{ .Values.persistence.hostPath | quote }} + type: DirectoryOrCreate diff --git a/charts/substrabac/values.yaml b/charts/substrabac/values.yaml new file mode 100644 index 000000000..1de09d18c --- /dev/null +++ b/charts/substrabac/values.yaml @@ -0,0 +1,201 @@ +backend: + replicaCount: 1 + djangoSettingsModuleEvent: substrabac.settings.events.prod + djangoSettingsModule: substrabac.settings.prod + siteHost: localhost + defaultDomain: localhost + + image: + repository: eu.gcr.io/substra-208412/substrabac + tag: latest + pullPolicy: IfNotPresent + pullSecrets: [] + + service: + type: NodePort + port: 8000 + annotations: {} + labels: {} + clusterIP: "" + externalIPs: [] + loadBalancerIP: "" + loadBalancerSourceRanges: [] + # nodePort: 30000 + + auth: {} + # user: owkward + # password: H9YJh7znjhoje3 + # header: "Basic b3drd2FyZDpIOVlKaDd6bmpob2plMw==" + + ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +persistence: + hostPath: "/substra" + size: "10Gi" + +# Secrets names +secrets: + # Certificate, saved under key 'cert.pem' + cert: hlf-idcert + # Key, saved under 'key.pem' + key: hlf-idkey + # CA Cert, saved under 'cacert.pem' + caCert: hlf-cacert + # TLS secret, saved under keys 'tls.crt' and 'tls.key' (to conform with K8S nomenclature) + tls: hlf-tls + # TLS root CA certificate saved under key 'cert.pem' + tlsRootCert: hlf-tlsrootcert + # TLS client root CA certificates saved under any names (as there may be multiple) + tlsClient: hlf-tls + # TLS client root CA certificates saved under any names (as there may be multiple) + tlsClientRootCerts: hlf-client-tlsrootcert + # This should contain the Certificate of the Peer Organisation admin + # This is necessary to successfully run the peer + adminCert: hlf-admincert + # This should contain the Private Key of the Peer Organisation admin + # This is necessary to successfully join a channel + adminKey: hlf-adminkey + # This should include the Orderer TLS 'cacert.pem' + ordTlsRootCert: hlf-client-tlsrootcert + # This will include the organization config json file (peer only) + orgConfig: org-config + # This will include the organization config json file (peer only) + fabricConfigmap: network-substra-network-tools-fabric + +organization: + name: substra + +user: + name: user + +orderer: + host: orderer-hlf-ord + port: 7050 + +peer: + host: healthchain-peer.owkin.com + port: 443 + mspID: OwkinPeerMSP + +channel: mychannel + +chaincode: + name: mycc + version: "1.0" + +postgresql: + enabled: true + postgresqlDatabase: substra + postgresqlUsername: postgres + postgresqlPassword: postgres + persistence: + enabled: false + +rabbitmq: + enabled: true + rabbitmq: + username: rabbitmq + password: rabbitmq + host: rabbitmq + port: 5672 + persistence: + enabled: false + +flower: + enabled: true + host: flower + port: 5555 + persistence: + enabled: false + + image: + repository: eu.gcr.io/substra-208412/flower + tag: latest + pullPolicy: IfNotPresent + pullSecrets: [] + + service: + type: NodePort + port: 5555 + annotations: {} + labels: {} + clusterIP: "" + externalIPs: [] + loadBalancerIP: "" + loadBalancerSourceRanges: [] + +celerybeat: + replicaCount: 1 + image: + repository: eu.gcr.io/substra-208412/celerybeat + tag: latest + pullPolicy: IfNotPresent + pullSecrets: [] + + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + nodeSelector: {} + + tolerations: [] + + affinity: {} + +celeryworker: + replicaCount: 1 + image: + repository: eu.gcr.io/substra-208412/celeryworker + tag: latest + pullPolicy: IfNotPresent + pullSecrets: [] + + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + nodeSelector: {} + + tolerations: [] + + affinity: {} From 81c721d526aa2dc697666ce0936f08a053fca4c0 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Thu, 5 Sep 2019 15:06:20 +0200 Subject: [PATCH 211/457] Fix jenkinsfile --- .cicd/agent-helm.yaml | 23 ++++++++++++++++++++ Jenkinsfile | 33 +++++++++++++++++++++++++++++ charts/substrabac/Jenkinsfile | 40 ----------------------------------- 3 files changed, 56 insertions(+), 40 deletions(-) create mode 100644 .cicd/agent-helm.yaml delete mode 100644 charts/substrabac/Jenkinsfile diff --git a/.cicd/agent-helm.yaml b/.cicd/agent-helm.yaml new file mode 100644 index 000000000..e077bb352 --- /dev/null +++ b/.cicd/agent-helm.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Pod +spec: + containers: + - name: helm + image: dtzar/helm-kubectl + command: [cat] + tty: true + volumeMounts: + - { name: chartmuseum-secret, mountPath: /secret } + env: + - { + name: GOOGLE_APPLICATION_CREDENTIALS, + value: /secret/chartmuseum-secret.json, + } + resources: + limits: + memory: "128Mi" + cpu: "500m" + volumes: + - name: chartmuseum-secret + secret: + secretName: chartmuseum-secret diff --git a/Jenkinsfile b/Jenkinsfile index 11162c0eb..f6330dfd6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -24,6 +24,20 @@ pipeline { stage('Test & Build') { parallel { + stage('Test Helm') { + agent { + kubernetes { + label 'substrabac-helm' + defaultContainer 'helm' + yamlFile '.cicd/agent-helm.yaml' + } + } + + steps { + sh "helm lint charts/substrabac" + } + } + stage('Test') { agent { kubernetes { @@ -113,6 +127,25 @@ pipeline { } } } + + stage('Publish Helm') { + agent { + kubernetes { + label 'substrabac-helm' + defaultContainer 'helm' + yamlFile '.cicd/agent-helm.yaml' + } + } + + when { buildingTag() } + + steps { + sh "helm init --client-only" + sh "helm plugin install https://github.com/chartmuseum/helm-push" + sh "helm repo add substra https://substra-charts.owkin.com --username owlways --password Cokear4nnRK9ooC" + sh "helm push charts/substrabac substra || true" + } + } } } diff --git a/charts/substrabac/Jenkinsfile b/charts/substrabac/Jenkinsfile deleted file mode 100644 index f2c81d795..000000000 --- a/charts/substrabac/Jenkinsfile +++ /dev/null @@ -1,40 +0,0 @@ -pipeline { - options { - timestamps () - timeout(time: 1, unit: 'HOURS') - buildDiscarder(logRotator(numToKeepStr: '5')) - skipDefaultCheckout true - } - - agent { - kubernetes { - label 'chart-substra' - defaultContainer 'build' - yamlFile '.cicd/agent-build.yaml' - } - } - - stages { - stage('Test') { - steps { - dir("substra") { - checkout scm - sh "helm lint" - } - } - } - - stage('Publish') { - when { buildingTag() } - steps { - dir("substra") { - checkout scm - sh "helm init --client-only" - sh "helm plugin install https://github.com/chartmuseum/helm-push" - sh "helm repo add substra https://substra-charts.owkin.com --username owlways --password Cokear4nnRK9ooC" - sh "helm push . substra" - } - } - } - } -} From 0039e36f5355bcb92b139fc365664e599b2584a9 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Thu, 5 Sep 2019 15:08:30 +0200 Subject: [PATCH 212/457] fixup --- .cicd/agent-helm.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.cicd/agent-helm.yaml b/.cicd/agent-helm.yaml index e077bb352..5ba0de8c8 100644 --- a/.cicd/agent-helm.yaml +++ b/.cicd/agent-helm.yaml @@ -7,12 +7,11 @@ spec: command: [cat] tty: true volumeMounts: - - { name: chartmuseum-secret, mountPath: /secret } + - name: chartmuseum-secret + mountPath: /secret env: - - { - name: GOOGLE_APPLICATION_CREDENTIALS, - value: /secret/chartmuseum-secret.json, - } + - name: GOOGLE_APPLICATION_CREDENTIALS + value: /secret/chartmuseum-secret.json resources: limits: memory: "128Mi" From e8300792cfb0d9379cc564d55519bfc9965bb474 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 5 Sep 2019 15:40:35 +0200 Subject: [PATCH 213/457] Update and clean charts --- .../templates/deployment-backend.yaml | 9 +- .../templates/deployment-celerybeat.yaml | 97 ------------------- .../templates/deployment-dryrunner.yaml | 2 +- .../templates/deployment-scheduler.yaml | 9 +- .../templates/deployment-worker.yaml | 2 +- charts/substrabac/values.yaml | 3 +- 6 files changed, 11 insertions(+), 111 deletions(-) diff --git a/charts/substrabac/templates/deployment-backend.yaml b/charts/substrabac/templates/deployment-backend.yaml index 44a88b5c6..8e0bba1bb 100644 --- a/charts/substrabac/templates/deployment-backend.yaml +++ b/charts/substrabac/templates/deployment-backend.yaml @@ -33,7 +33,12 @@ spec: imagePullPolicy: "{{ .Values.backend.image.pullPolicy }}" {{- end }} command: ["/bin/bash"] - args: ["-c", "sed -i '7d' substrabac/settings/prod.py; python manage.py migrate; touch /ready; DJANGO_SETTINGS_MODULE={{ .Values.backend.djangoSettingsModuleEvent }} python3 manage.py runserver --noreload 0.0.0.0:8000"] + + {{- if eq .Values.backend.settings "prod" }} + args: ["-c", "sed -i '7d' substrabac/settings/prod.py; python manage.py migrate; touch /ready; python3 manage.py collectstatic --noinput; DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} uwsgi --http :8000 --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes 2 --threads 2"] + {{- else }} + args: ["-c", "python manage.py migrate; touch /ready; DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] + {{- end }} env: - name: ORG value: {{ .Values.organization.name }} @@ -48,7 +53,7 @@ spec: - name: DATABASE_HOST value: {{ .Release.Name }}-postgresql - name: DJANGO_SETTINGS_MODULE - value: {{ .Values.backend.djangoSettingsModule }} + value: substrabac.settings.{{ .Values.backend.settings }} - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric_cfg - name: CORE_PEER_ADDRESS_ENV diff --git a/charts/substrabac/templates/deployment-celerybeat.yaml b/charts/substrabac/templates/deployment-celerybeat.yaml index 02e64f256..583ba6df3 100644 --- a/charts/substrabac/templates/deployment-celerybeat.yaml +++ b/charts/substrabac/templates/deployment-celerybeat.yaml @@ -35,111 +35,14 @@ spec: command: ["celery"] args: ["-A", "substrabac", "beat", "-l", "debug"] env: - - name: ORG - value: {{ .Values.organization.name }} - - name: SUBSTRABAC_ORG - value: {{ .Values.organization.name }} - {{- with .Values.backend.auth }} - - name: BACK_AUTH_USER - value: {{ .user | quote }} - - name: BACK_AUTH_PASSWORD - value: {{ .password | quote }} - {{- else }} - - name: BACK_AUTH_USER - value: "" - - name: BACK_AUTH_PASSWORD - value: "" - {{- end }} - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE value: substrabac.settings.common - name: PYTHONUNBUFFERED value: "1" - - name: SUBSTRABAC_{{ .Values.organization.name | upper }}_DB_NAME - value: {{ .Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABAC_DB_USER - value: {{ .Values.postgresql.postgresqlUsername }} - - name: SUBSTRABAC_DB_PWD - value: {{ .Values.postgresql.postgresqlPassword }} - - name: DATABASE_HOST - value: {{ .Release.Name }}-postgresql - - name: DJANGO_SETTINGS_MODULE - value: {{ .Values.backend.djangoSettingsModule }} - - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/substrabac/conf.json - volumeMounts: - - mountPath: /conf/{{ .Values.organization.name }}/substrabac - name: config - readOnly: true - - mountPath: /var/hyperledger/msp/signcerts - name: id-cert - - mountPath: /var/hyperledger/msp/keystore - name: id-key - - mountPath: /var/hyperledger/msp/cacerts - name: cacert - - mountPath: /var/hyperledger/msp/admincerts - name: admin-cert - - mountPath: /var/hyperledger/tls/server/pair - name: tls - - mountPath: /var/hyperledger/tls/server/cert - name: tls-rootcert - - mountPath: /var/hyperledger/tls/client/pair - name: tls-client - - mountPath: /var/hyperledger/tls/client/cert - name: tls-clientrootcert - - mountPath: /var/hyperledger/tls/ord/cert - name: ord-tls-rootcert - - mountPath: /var/hyperledger/admin_msp/signcerts - name: admin-cert - - mountPath: /var/hyperledger/admin_msp/keystore - name: admin-key - - mountPath: /var/hyperledger/admin_msp/cacerts - name: cacert - - mountPath: /var/hyperledger/admin_msp/admincerts - name: admin-cert resources: {{- toYaml .Values.celerybeat.resources | nindent 12 }} - volumes: - - name: config - configMap: - name: {{ include "substra.fullname" . }}-backend - - name: data - persistentVolumeClaim: - claimName: {{ include "substra.fullname" . }} - - name: fabric - configMap: - name: {{ $.Values.secrets.fabricConfigmap }} - - name: id-cert - secret: - secretName: {{ $.Values.secrets.cert }} - - name: id-key - secret: - secretName: {{ $.Values.secrets.key }} - - name: cacert - secret: - secretName: {{ $.Values.secrets.caCert }} - - name: tls - secret: - secretName: {{ $.Values.secrets.tls }} - - name: tls-rootcert - secret: - secretName: {{ $.Values.secrets.tlsRootCert }} - - name: tls-client - secret: - secretName: {{ $.Values.secrets.tlsClient }} - - name: tls-clientrootcert - secret: - secretName: {{ $.Values.secrets.tlsClientRootCerts }} - - name: admin-cert - secret: - secretName: {{ $.Values.secrets.adminCert }} - - name: admin-key - secret: - secretName: {{ $.Values.secrets.adminKey }} - - name: ord-tls-rootcert - secret: - secretName: {{ $.Values.secrets.tlsRootCert }} {{- with .Values.celerybeat.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} diff --git a/charts/substrabac/templates/deployment-dryrunner.yaml b/charts/substrabac/templates/deployment-dryrunner.yaml index 8c95f0d36..d5bd4f2c6 100644 --- a/charts/substrabac/templates/deployment-dryrunner.yaml +++ b/charts/substrabac/templates/deployment-dryrunner.yaml @@ -44,7 +44,7 @@ spec: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: {{ .Values.backend.djangoSettingsModule }} + value: substrabac.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" {{- with .Values.backend.auth }} diff --git a/charts/substrabac/templates/deployment-scheduler.yaml b/charts/substrabac/templates/deployment-scheduler.yaml index 87c2b31e6..ee008e1d8 100644 --- a/charts/substrabac/templates/deployment-scheduler.yaml +++ b/charts/substrabac/templates/deployment-scheduler.yaml @@ -44,7 +44,7 @@ spec: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: {{ .Values.backend.djangoSettingsModule }} + value: substrabac.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" {{- with .Values.backend.auth }} @@ -66,13 +66,9 @@ spec: value: "{{ .Values.peer.host }}:{{ .Values.peer.port }}" - name: FABRIC_LOGGING_SPEC value: debug - - name: MEDIA_ROOT - value: {{ .Values.persistence.hostPath }}/medias/ - name: LEDGER_CONFIG_FILE value: /conf/{{ .Values.organization.name }}/substrabac/conf.json volumeMounts: - - mountPath: {{ .Values.persistence.hostPath }} - name: data - mountPath: /conf/{{ .Values.organization.name }}/substrabac name: config readOnly: true @@ -108,9 +104,6 @@ spec: - name: config configMap: name: {{ include "substra.fullname" . }}-backend - - name: data - persistentVolumeClaim: - claimName: {{ include "substra.fullname" . }} - name: fabric configMap: name: {{ $.Values.secrets.fabricConfigmap }} diff --git a/charts/substrabac/templates/deployment-worker.yaml b/charts/substrabac/templates/deployment-worker.yaml index 6872f8054..2863d7613 100644 --- a/charts/substrabac/templates/deployment-worker.yaml +++ b/charts/substrabac/templates/deployment-worker.yaml @@ -44,7 +44,7 @@ spec: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: {{ .Values.backend.djangoSettingsModule }} + value: substrabac.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" {{- with .Values.backend.auth }} diff --git a/charts/substrabac/values.yaml b/charts/substrabac/values.yaml index 1de09d18c..a378b576d 100644 --- a/charts/substrabac/values.yaml +++ b/charts/substrabac/values.yaml @@ -1,7 +1,6 @@ backend: replicaCount: 1 - djangoSettingsModuleEvent: substrabac.settings.events.prod - djangoSettingsModule: substrabac.settings.prod + settings: prod siteHost: localhost defaultDomain: localhost From 541b8ce5ca24371927fba9eda982111697cde40e Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 5 Sep 2019 15:45:21 +0200 Subject: [PATCH 214/457] Fix settings prods. --- substrabac/substrabac/settings/prod.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 8d70b2d12..76a44de7e 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -38,8 +38,7 @@ } } -MEDIA_ROOT = f'/substra/medias/{ORG_NAME}' - +MEDIA_ROOT = os.environ.get('MEDIA_ROOT', f'/substra/medias/{ORG_NAME}') SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substrabac') SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) From 2865e3ef6804a3ff7f56efdefe652f5beb71f1aa Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 21 Aug 2019 16:58:18 +0200 Subject: [PATCH 215/457] make basic authentication required in dev and prod it is not done for the tests as it requires too much changes. --- substrabac/libs/BasicAuthMiddleware.py | 49 ++++++++++++------------ substrabac/substrabac/settings/common.py | 4 ++ substrabac/substrabac/settings/prod.py | 6 --- substrabac/substrabac/settings/test.py | 2 + 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/substrabac/libs/BasicAuthMiddleware.py b/substrabac/libs/BasicAuthMiddleware.py index 198e2665b..556909d6a 100644 --- a/substrabac/libs/BasicAuthMiddleware.py +++ b/substrabac/libs/BasicAuthMiddleware.py @@ -1,4 +1,3 @@ -from django.core.exceptions import MiddlewareNotUsed from django.http import HttpResponse from django.conf import settings @@ -16,35 +15,37 @@ class BasicAuthMiddleware: - def unauthed(self): + + def __init__(self, get_response): + self.get_response = get_response + + def not_authenticated(self): response = HttpResponse(html_template, content_type="text/html") response['WWW-Authenticate'] = 'Basic realm="Administrator area"' response.status_code = 401 return response - def __init__(self, get_response): - if settings.DEBUG: - raise MiddlewareNotUsed + def __call__(self, request): + server_username = settings.BASICAUTH_USERNAME + server_password = settings.BASICAUTH_PASSWORD - self.get_response = get_response - # One-time configuration and initialization. + if not server_username or not server_password: + return self.not_authenticated() - def __call__(self, request): - username = getattr(settings, 'BASICAUTH_USERNAME', None) - password = getattr(settings, 'BASICAUTH_PASSWORD', None) - - if username not in (None, '') and password not in (None, ''): - if request.method != 'OPTIONS': - if 'HTTP_AUTHORIZATION' not in request.META: - return self.unauthed() - else: - authentication = request.META['HTTP_AUTHORIZATION'] - (authmeth, auth) = authentication.split(' ', 1) - if 'basic' != authmeth.lower(): - return self.unauthed() - auth = base64.b64decode(auth.strip()).decode('utf-8') - username, password = auth.split(':', 1) - if username != settings.BASICAUTH_USERNAME or password != settings.BASICAUTH_PASSWORD: - return self.unauthed() + if request.method != 'OPTIONS': + return self.not_authenticated() + + if 'HTTP_AUTHORIZATION' not in request.META: + return self.not_authenticated() + + header = request.META['HTTP_AUTHORIZATION'] + (method, auth) = header.split(' ', 1) + if 'basic' != method.lower(): + return self.not_authenticated() + + auth = base64.b64decode(auth.strip()).decode('utf-8') + username, password = auth.split(':', 1) + if username != server_username or password != server_password: + return self.not_authenticated() return self.get_response(request) diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 5a12f6321..01eb75e75 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -61,6 +61,9 @@ 'substrapp', ] +BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') +BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD') + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -70,6 +73,7 @@ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'libs.SQLPrintingMiddleware.SQLPrintingMiddleware', + 'libs.BasicAuthMiddleware.BasicAuthMiddleware', ] ROOT_URLCONF = 'substrabac.urls' diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 76a44de7e..226a90391 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -19,11 +19,6 @@ STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'statics') -# deactivate when public -BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER', None) -BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', None) -MIDDLEWARE += ['libs.BasicAuthMiddleware.BasicAuthMiddleware'] - # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases @@ -39,7 +34,6 @@ } MEDIA_ROOT = os.environ.get('MEDIA_ROOT', f'/substra/medias/{ORG_NAME}') - SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substrabac') SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') diff --git a/substrabac/substrabac/settings/test.py b/substrabac/substrabac/settings/test.py index 7df04facc..191fc5d3a 100644 --- a/substrabac/substrabac/settings/test.py +++ b/substrabac/substrabac/settings/test.py @@ -5,3 +5,5 @@ import logging logging.disable(logging.CRITICAL) + +MIDDLEWARE.remove('libs.BasicAuthMiddleware.BasicAuthMiddleware') From 0e48db2ff15c828ac82a33ff182e683b62951f82 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 21 Aug 2019 17:08:36 +0200 Subject: [PATCH 216/457] replace internal BasicAuthMiddleware with authentication backend --- substrabac/libs/BasicAuthMiddleware.py | 51 ------------------- substrabac/libs/authentication.py | 22 ++++++++ substrabac/substrabac/settings/common.py | 6 ++- .../substrabac/settings/deps/restframework.py | 8 ++- substrabac/substrabac/settings/test.py | 2 +- 5 files changed, 34 insertions(+), 55 deletions(-) delete mode 100644 substrabac/libs/BasicAuthMiddleware.py create mode 100644 substrabac/libs/authentication.py diff --git a/substrabac/libs/BasicAuthMiddleware.py b/substrabac/libs/BasicAuthMiddleware.py deleted file mode 100644 index 556909d6a..000000000 --- a/substrabac/libs/BasicAuthMiddleware.py +++ /dev/null @@ -1,51 +0,0 @@ -from django.http import HttpResponse -from django.conf import settings - -import base64 - - -html_template = """ - - Auth required - -

    Authorization Required

    - - -""" - - -class BasicAuthMiddleware: - - def __init__(self, get_response): - self.get_response = get_response - - def not_authenticated(self): - response = HttpResponse(html_template, content_type="text/html") - response['WWW-Authenticate'] = 'Basic realm="Administrator area"' - response.status_code = 401 - return response - - def __call__(self, request): - server_username = settings.BASICAUTH_USERNAME - server_password = settings.BASICAUTH_PASSWORD - - if not server_username or not server_password: - return self.not_authenticated() - - if request.method != 'OPTIONS': - return self.not_authenticated() - - if 'HTTP_AUTHORIZATION' not in request.META: - return self.not_authenticated() - - header = request.META['HTTP_AUTHORIZATION'] - (method, auth) = header.split(' ', 1) - if 'basic' != method.lower(): - return self.not_authenticated() - - auth = base64.b64decode(auth.strip()).decode('utf-8') - username, password = auth.split(':', 1) - if username != server_username or password != server_password: - return self.not_authenticated() - - return self.get_response(request) diff --git a/substrabac/libs/authentication.py b/substrabac/libs/authentication.py new file mode 100644 index 000000000..eef326a81 --- /dev/null +++ b/substrabac/libs/authentication.py @@ -0,0 +1,22 @@ +from django.conf import settings +from django.contrib.auth.models import User + + +class SettingsBackend: + """Authenticate against user and password defined in settings.""" + + def authenticate(self, request, username=None, password=None): + """Check the username/password and return a user.""" + if not username or not password: + return None + + server_username = settings.BASICAUTH_USERNAME + server_password = settings.BASICAUTH_PASSWORD + if username == server_username and password == server_password: + return User(username) + + return None + + def get_user(self, user_id): + # required for session + return None diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 01eb75e75..5c8ea71a4 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -64,6 +64,11 @@ BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD') +AUTHENTICATION_BACKENDS = [ + 'django.contrib.auth.backends.ModelBackend', + 'libs.authentication.SettingsBackend', +] + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -73,7 +78,6 @@ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'libs.SQLPrintingMiddleware.SQLPrintingMiddleware', - 'libs.BasicAuthMiddleware.BasicAuthMiddleware', ] ROOT_URLCONF = 'substrabac.urls' diff --git a/substrabac/substrabac/settings/deps/restframework.py b/substrabac/substrabac/settings/deps/restframework.py index e79ae083b..189e836c8 100644 --- a/substrabac/substrabac/settings/deps/restframework.py +++ b/substrabac/substrabac/settings/deps/restframework.py @@ -5,9 +5,13 @@ # 'rest_framework.renderers.AdminRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ), - 'DEFAULT_AUTHENTICATION_CLASSES': ( + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', - ), + ], + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', + ], 'UNICODE_JSON': False, 'DEFAULT_VERSIONING_CLASS': 'libs.versioning.AcceptHeaderVersioningRequired', 'ALLOWED_VERSIONS': ('0.0',), diff --git a/substrabac/substrabac/settings/test.py b/substrabac/substrabac/settings/test.py index 191fc5d3a..1c87ea32e 100644 --- a/substrabac/substrabac/settings/test.py +++ b/substrabac/substrabac/settings/test.py @@ -6,4 +6,4 @@ import logging logging.disable(logging.CRITICAL) -MIDDLEWARE.remove('libs.BasicAuthMiddleware.BasicAuthMiddleware') +REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'] = [] From 141f23f8109d9a9dbb1868a386e7c3b768c85fda Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Thu, 22 Aug 2019 13:24:16 +0200 Subject: [PATCH 217/457] add node model to handle incoming/outgoing nodes --- substrabac/node/__init__.py | 0 substrabac/node/apps.py | 5 ++++ substrabac/node/migrations/0001_initial.py | 34 ++++++++++++++++++++++ substrabac/node/migrations/__init__.py | 0 substrabac/node/models.py | 18 ++++++++++++ substrabac/substrabac/settings/common.py | 1 + 6 files changed, 58 insertions(+) create mode 100644 substrabac/node/__init__.py create mode 100644 substrabac/node/apps.py create mode 100644 substrabac/node/migrations/0001_initial.py create mode 100644 substrabac/node/migrations/__init__.py create mode 100644 substrabac/node/models.py diff --git a/substrabac/node/__init__.py b/substrabac/node/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/node/apps.py b/substrabac/node/apps.py new file mode 100644 index 000000000..ffb6c1d7d --- /dev/null +++ b/substrabac/node/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class NodeConfig(AppConfig): + name = 'node' diff --git a/substrabac/node/migrations/0001_initial.py b/substrabac/node/migrations/0001_initial.py new file mode 100644 index 000000000..f29b03031 --- /dev/null +++ b/substrabac/node/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 2.1.2 on 2019-08-22 11:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='IncomingNode', + fields=[ + ('node_id', models.CharField(max_length=64, primary_key=True, serialize=False)), + ('secret', models.CharField(max_length=128)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='OutgoingNode', + fields=[ + ('node_id', models.CharField(max_length=64, primary_key=True, serialize=False)), + ('secret', models.CharField(max_length=128)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/substrabac/node/migrations/__init__.py b/substrabac/node/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/node/models.py b/substrabac/node/models.py new file mode 100644 index 000000000..b3c423a84 --- /dev/null +++ b/substrabac/node/models.py @@ -0,0 +1,18 @@ +from django.db import models +from django.contrib.auth.models import AbstractUser + + +class Node(models.Model): + node_id = models.CharField(primary_key=True, max_length=64, blank=False) + secret = models.CharField(max_length=128, blank=False) + + class Meta: + abstract = True + + +class OutgoingNode(Node): + pass + + +class IncomingNode(Node): + pass diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 5c8ea71a4..0aace4447 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -59,6 +59,7 @@ 'rest_framework_swagger', 'rest_framework', 'substrapp', + 'node', ] BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') From fca3d8fc3aece5c6fc2ccea13689625015ca7b7c Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Thu, 22 Aug 2019 16:29:06 +0200 Subject: [PATCH 218/457] add create/get for incoming and outgoing nodes --- .../commands/create_incoming_node.py | 19 ++++++++++++++ .../commands/create_outgoing_node.py | 19 ++++++++++++++ .../management/commands/get_incoming_node.py | 25 +++++++++++++++++++ .../management/commands/get_outgoing_node.py | 25 +++++++++++++++++++ substrabac/node/models.py | 5 ++++ 5 files changed, 93 insertions(+) create mode 100644 substrabac/node/management/commands/create_incoming_node.py create mode 100644 substrabac/node/management/commands/create_outgoing_node.py create mode 100644 substrabac/node/management/commands/get_incoming_node.py create mode 100644 substrabac/node/management/commands/get_outgoing_node.py diff --git a/substrabac/node/management/commands/create_incoming_node.py b/substrabac/node/management/commands/create_incoming_node.py new file mode 100644 index 000000000..a21f627d4 --- /dev/null +++ b/substrabac/node/management/commands/create_incoming_node.py @@ -0,0 +1,19 @@ +from django.core.management.base import BaseCommand, CommandError +from node.models import Node, IncomingNode + + +class Command(BaseCommand): + help = 'Create a new incoming node' + + def add_arguments(self, parser): + parser.add_argument('node_id') + + def handle(self, *args, **options): + incoming_node, created = IncomingNode.objects.get_or_create(node_id=options['node_id'], secret=Node.generate_secret()) + + if not created: + self.stdout.write(self.style.NOTICE(f'node with id {incoming_node.node_id} already exists')) + else: + self.stdout.write(self.style.SUCCESS('node successfully created')) + self.stdout.write(f'node_id={incoming_node.node_id}') + self.stdout.write(f'secret={incoming_node.secret}') diff --git a/substrabac/node/management/commands/create_outgoing_node.py b/substrabac/node/management/commands/create_outgoing_node.py new file mode 100644 index 000000000..9bc733b14 --- /dev/null +++ b/substrabac/node/management/commands/create_outgoing_node.py @@ -0,0 +1,19 @@ +from django.core.management.base import BaseCommand, CommandError +from node.models import Node, OutgoingNode + + +class Command(BaseCommand): + help = 'Create a new outgoing node' + + def add_arguments(self, parser): + parser.add_argument('node_id') + + def handle(self, *args, **options): + outgoing_node, created = OutgoingNode.objects.get_or_create(node_id=options['node_id'], secret=Node.generate_secret()) + + if not created: + self.stdout.write(self.style.NOTICE(f'node with id {outgoing_node.node_id} already exists')) + else: + self.stdout.write(self.style.SUCCESS('node successfully created')) + self.stdout.write(f'node_id={outgoing_node.node_id}') + self.stdout.write(f'secret={outgoing_node.secret}') diff --git a/substrabac/node/management/commands/get_incoming_node.py b/substrabac/node/management/commands/get_incoming_node.py new file mode 100644 index 000000000..56839890f --- /dev/null +++ b/substrabac/node/management/commands/get_incoming_node.py @@ -0,0 +1,25 @@ +from django.core.management.base import BaseCommand, CommandError +from node.models import IncomingNode + + +def pretty(s1, s2): + return f'{s1.ljust(64)} | {s2.ljust(128)}' + + +class Command(BaseCommand): + help = 'Get incoming nodes' + + def add_arguments(self, parser): + parser.add_argument('node_id', nargs='?') + + def handle(self, *args, **options): + self.stdout.write(pretty("node_id", "secret")) + self.stdout.write(pretty("_" * 64, "_" * 128)) + + if options['node_id']: + outgoing_node = IncomingNode.objects.get(node_id=options['node_id']) + self.stdout.write(self.style.SUCCESS(pretty(outgoing_node.node_id, outgoing_node.secret))) + else: + outgoing_nodes = IncomingNode.objects.all() + for node in outgoing_nodes: + self.stdout.write(self.style.SUCCESS(pretty(node.node_id, node.secret))) diff --git a/substrabac/node/management/commands/get_outgoing_node.py b/substrabac/node/management/commands/get_outgoing_node.py new file mode 100644 index 000000000..28ffc109c --- /dev/null +++ b/substrabac/node/management/commands/get_outgoing_node.py @@ -0,0 +1,25 @@ +from django.core.management.base import BaseCommand, CommandError +from node.models import OutgoingNode + + +def pretty(s1, s2): + return f'{s1.ljust(64)} | {s2.ljust(128)}' + + +class Command(BaseCommand): + help = 'Get outgoing nodes' + + def add_arguments(self, parser): + parser.add_argument('node_id', nargs='?') + + def handle(self, *args, **options): + self.stdout.write(pretty("node_id", "secret")) + self.stdout.write(pretty("_" * 64, "_" * 128)) + + if options['node_id']: + outgoing_node = OutgoingNode.objects.get(node_id=options['node_id']) + self.stdout.write(self.style.SUCCESS(pretty(outgoing_node.node_id, outgoing_node.secret))) + else: + outgoing_nodes = OutgoingNode.objects.all() + for node in outgoing_nodes: + self.stdout.write(self.style.SUCCESS(pretty(node.node_id, node.secret))) diff --git a/substrabac/node/models.py b/substrabac/node/models.py index b3c423a84..643db0692 100644 --- a/substrabac/node/models.py +++ b/substrabac/node/models.py @@ -1,11 +1,16 @@ from django.db import models from django.contrib.auth.models import AbstractUser +import secrets class Node(models.Model): node_id = models.CharField(primary_key=True, max_length=64, blank=False) secret = models.CharField(max_length=128, blank=False) + @staticmethod + def generate_secret(): + return secrets.token_hex(64) + class Meta: abstract = True From b143c74376d5dff91f85e6cb453f1432948419bc Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 23 Aug 2019 10:58:59 +0200 Subject: [PATCH 219/457] add node backend authentication --- substrabac/node/__init__.py | 1 + substrabac/node/authentication.py | 27 +++++++++++++++++++ .../management/commands/get_incoming_node.py | 8 +++--- substrabac/substrabac/settings/common.py | 1 + 4 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 substrabac/node/authentication.py diff --git a/substrabac/node/__init__.py b/substrabac/node/__init__.py index e69de29bb..00990e886 100644 --- a/substrabac/node/__init__.py +++ b/substrabac/node/__init__.py @@ -0,0 +1 @@ +default_app_config = 'node.apps.NodeConfig' diff --git a/substrabac/node/authentication.py b/substrabac/node/authentication.py new file mode 100644 index 000000000..ada23f037 --- /dev/null +++ b/substrabac/node/authentication.py @@ -0,0 +1,27 @@ +from django.contrib.auth.models import User +from .models import IncomingNode + + +class NodeBackend: + """Authenticate node """ + + def authenticate(self, request, username=None, password=None): + """Check the username/password and return a user.""" + node_id = username + secret = password + + if not node_id or not secret: + return None + + incoming_node = IncomingNode.objects.get(node_id=node_id) + if not incoming_node: + return None + + if node_id == incoming_node.node_id and secret == incoming_node.secret: + return User(node_id) + + return None + + def get_user(self, user_id): + # required for session + return None diff --git a/substrabac/node/management/commands/get_incoming_node.py b/substrabac/node/management/commands/get_incoming_node.py index 56839890f..83a9a527a 100644 --- a/substrabac/node/management/commands/get_incoming_node.py +++ b/substrabac/node/management/commands/get_incoming_node.py @@ -17,9 +17,9 @@ def handle(self, *args, **options): self.stdout.write(pretty("_" * 64, "_" * 128)) if options['node_id']: - outgoing_node = IncomingNode.objects.get(node_id=options['node_id']) - self.stdout.write(self.style.SUCCESS(pretty(outgoing_node.node_id, outgoing_node.secret))) + incoming_node = IncomingNode.objects.get(node_id=options['node_id']) + self.stdout.write(self.style.SUCCESS(pretty(incoming_node.node_id, incoming_node.secret))) else: - outgoing_nodes = IncomingNode.objects.all() - for node in outgoing_nodes: + incoming_nodes = IncomingNode.objects.all() + for node in incoming_nodes: self.stdout.write(self.style.SUCCESS(pretty(node.node_id, node.secret))) diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 0aace4447..c928c3a67 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -68,6 +68,7 @@ AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'libs.authentication.SettingsBackend', + 'node.authentication.NodeBackend', ] MIDDLEWARE = [ From 3b55ad3b1a989f0242ea6d08a8635d1b4c4d753a Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 23 Aug 2019 11:40:53 +0200 Subject: [PATCH 220/457] fix node backend authentication --- substrabac/node/authentication.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/substrabac/node/authentication.py b/substrabac/node/authentication.py index ada23f037..c4a7f8610 100644 --- a/substrabac/node/authentication.py +++ b/substrabac/node/authentication.py @@ -13,11 +13,8 @@ def authenticate(self, request, username=None, password=None): if not node_id or not secret: return None - incoming_node = IncomingNode.objects.get(node_id=node_id) - if not incoming_node: - return None - - if node_id == incoming_node.node_id and secret == incoming_node.secret: + incoming_node_exists = IncomingNode.objects.filter(node_id=node_id, secret=secret).exists() + if incoming_node_exists: return User(node_id) return None From 1a62c98098b75588a8b9a6c11605c400462729c2 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 23 Aug 2019 15:00:34 +0200 Subject: [PATCH 221/457] fix tests --- substrabac/substrabac/settings/common.py | 1 + substrabac/substrabac/settings/dev.py | 2 - substrabac/substrabac/settings/prod.py | 2 - substrabac/substrabac/settings/test.py | 5 +- substrabac/substrapp/tests/common.py | 22 +++++++ .../substrapp/tests/query/tests_query_algo.py | 3 +- .../tests/query/tests_query_datamanager.py | 3 +- .../tests/query/tests_query_datasample.py | 3 +- .../tests/query/tests_query_objective.py | 3 +- .../tests/query/tests_query_tuples.py | 4 +- .../tests/views/test_views_authentication.py | 61 +++++++++++++++++++ .../substrapp/tests/views/tests_views.py | 8 ++- .../substrapp/tests/views/tests_views_algo.py | 3 +- .../tests/views/tests_views_computeplan.py | 2 + .../tests/views/tests_views_datamanager.py | 4 +- .../tests/views/tests_views_datasample.py | 4 +- .../tests/views/tests_views_model.py | 4 +- .../tests/views/tests_views_objective.py | 5 +- .../substrapp/tests/views/tests_views_task.py | 3 +- .../tests/views/tests_views_tuples.py | 3 + 20 files changed, 119 insertions(+), 26 deletions(-) create mode 100644 substrabac/substrapp/tests/views/test_views_authentication.py diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index c928c3a67..38be95575 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -13,6 +13,7 @@ import os import sys from libs.gen_secret_key import write_secret_key +from .deps.restframework import * # noqa # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 9db133d2b..b39beebd0 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -1,8 +1,6 @@ import os from .common import * - -from .deps.restframework import * from .deps.cors import * from .deps.org import * from .deps.ledger import * diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 226a90391..376ae6f76 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -1,8 +1,6 @@ import os from .common import * - -from .deps.restframework import * from .deps.cors import * from .deps.raven import * from .deps.org import * diff --git a/substrabac/substrabac/settings/test.py b/substrabac/substrabac/settings/test.py index 1c87ea32e..17b5c92fc 100644 --- a/substrabac/substrabac/settings/test.py +++ b/substrabac/substrabac/settings/test.py @@ -1,9 +1,8 @@ from .common import * # noqa - -from .deps.restframework import * # noqa from .deps.cors import * # noqa import logging logging.disable(logging.CRITICAL) -REST_FRAMEWORK['DEFAULT_PERMISSION_CLASSES'] = [] +BASICAUTH_USERNAME = "admin" +BASICAUTH_PASSWORD = "admin" diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 717323318..9e9ab3282 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -1,7 +1,29 @@ from io import StringIO, BytesIO import os +import base64 +from django.conf import settings from django.core.files.uploadedfile import InMemoryUploadedFile +from rest_framework.test import APIClient + + +# This function helper generate a basic authenticaiton header with given credentials +# Given username and password it returns "Basic GENERATED_TOKEN" +def generate_basic_auth_header(username, password): + return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() + + +class AuthenticatedClient(APIClient): + + def request(self, **kwargs): + basic_auth_header = generate_basic_auth_header( + settings.BASICAUTH_USERNAME, + settings.BASICAUTH_PASSWORD + ) + + self.credentials(HTTP_AUTHORIZATION=basic_auth_header) + + return super().request(**kwargs) class gpu(): diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substrabac/substrapp/tests/query/tests_query_algo.py index a38cb7355..56b44a0b0 100644 --- a/substrabac/substrapp/tests/query/tests_query_algo.py +++ b/substrabac/substrapp/tests/query/tests_query_algo.py @@ -16,7 +16,7 @@ from substrapp.ledger_utils import LedgerError from ..common import get_sample_objective, get_sample_datamanager, \ - get_sample_algo, get_sample_algo_zip + get_sample_algo, get_sample_algo_zip, AuthenticatedClient MEDIA_ROOT = tempfile.mkdtemp() @@ -25,6 +25,7 @@ @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class AlgoQueryTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/query/tests_query_datamanager.py b/substrabac/substrapp/tests/query/tests_query_datamanager.py index 487a0cd3c..4a5c883de 100644 --- a/substrabac/substrapp/tests/query/tests_query_datamanager.py +++ b/substrabac/substrapp/tests/query/tests_query_datamanager.py @@ -13,7 +13,7 @@ from substrapp.utils import get_hash -from ..common import get_sample_datamanager +from ..common import get_sample_datamanager, AuthenticatedClient MEDIA_ROOT = tempfile.mkdtemp() @@ -22,6 +22,7 @@ @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class DataManagerQueryTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substrabac/substrapp/tests/query/tests_query_datasample.py index 201f93114..bbe8618f5 100644 --- a/substrabac/substrapp/tests/query/tests_query_datasample.py +++ b/substrabac/substrapp/tests/query/tests_query_datasample.py @@ -22,7 +22,7 @@ from substrapp.views import DataSampleViewSet from ..common import get_sample_datamanager, get_sample_zip_data_sample, get_sample_script, \ - get_sample_datamanager2, get_sample_tar_data_sample, get_sample_zip_data_sample_2 + get_sample_datamanager2, get_sample_tar_data_sample, get_sample_zip_data_sample_2, AuthenticatedClient MEDIA_ROOT = tempfile.mkdtemp() @@ -31,6 +31,7 @@ @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class DataSampleQueryTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/query/tests_query_objective.py b/substrabac/substrapp/tests/query/tests_query_objective.py index 710393bd1..f97d99aba 100644 --- a/substrabac/substrapp/tests/query/tests_query_objective.py +++ b/substrabac/substrapp/tests/query/tests_query_objective.py @@ -15,7 +15,7 @@ from substrapp.utils import get_hash, compute_hash from ..common import get_sample_objective, get_sample_datamanager, \ - get_temporary_text_file + get_temporary_text_file, AuthenticatedClient MEDIA_ROOT = tempfile.mkdtemp() @@ -24,6 +24,7 @@ @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class ObjectiveQueryTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/query/tests_query_tuples.py b/substrabac/substrapp/tests/query/tests_query_tuples.py index 51e11fe26..d46298992 100644 --- a/substrabac/substrapp/tests/query/tests_query_tuples.py +++ b/substrabac/substrapp/tests/query/tests_query_tuples.py @@ -13,7 +13,7 @@ from substrapp.models import Objective from substrapp.utils import get_hash -from ..common import get_sample_objective +from ..common import get_sample_objective, AuthenticatedClient MEDIA_ROOT = tempfile.mkdtemp() @@ -22,6 +22,7 @@ @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class TraintupleQueryTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): @@ -173,6 +174,7 @@ def test_add_traintuple_wrong_version(self): @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(LEDGER_SYNC_ENABLED=True) class TesttupleQueryTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/views/test_views_authentication.py b/substrabac/substrapp/tests/views/test_views_authentication.py new file mode 100644 index 000000000..601aaeff4 --- /dev/null +++ b/substrabac/substrapp/tests/views/test_views_authentication.py @@ -0,0 +1,61 @@ +import base64 + +from rest_framework import status +from rest_framework.test import APITestCase +from node.models import IncomingNode + +from ..common import generate_basic_auth_header +from django.conf import settings + + +class AuthenticationTests(APITestCase): + def setUp(self): + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + @classmethod + def setUpTestData(cls): + cls.incoming_node = IncomingNode.objects.create(node_id="external_node_id", secret="s3cr37") + + def test_authentication_fail(self): + response = self.client.get('/', **self.extra) + + self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) + + def test_authentication_with_settings_success(self): + authorization_header = generate_basic_auth_header(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) + + self.client.credentials(HTTP_AUTHORIZATION=authorization_header) + response = self.client.get('/', **self.extra) + + self.assertEqual(status.HTTP_200_OK, response.status_code) + + def test_authentication_with_bad_settings_credentials_fail(self): + authorization_header = generate_basic_auth_header('unauthorized_username', 'unauthorized_password') + + self.client.credentials(HTTP_AUTHORIZATION=authorization_header) + response = self.client.get('/', **self.extra) + + self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) + + def test_authentication_with_node(self): + authorization_header = generate_basic_auth_header('external_node_id', 's3cr37') + + self.client.credentials(HTTP_AUTHORIZATION=authorization_header) + response = self.client.get('/', **self.extra) + + self.assertEqual(status.HTTP_200_OK, response.status_code) + + def test_authentication_with_node_fail(self): + bad_authorization_headers = [ + generate_basic_auth_header('external_node_id', 'bad_s3cr37'), + generate_basic_auth_header('bad_external_node_id', 's3cr37'), + generate_basic_auth_header('bad_external_node_id', 'bad_s3cr37'), + ] + + for header in bad_authorization_headers: + self.client.credentials(HTTP_AUTHORIZATION=header) + response = self.client.get('/', **self.extra) + + self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) diff --git a/substrabac/substrapp/tests/views/tests_views.py b/substrabac/substrapp/tests/views/tests_views.py index 5560252b6..af6697edd 100644 --- a/substrabac/substrapp/tests/views/tests_views.py +++ b/substrabac/substrapp/tests/views/tests_views.py @@ -1,6 +1,6 @@ import mock - +from rest_framework import status from rest_framework.test import APITestCase from substrapp.views.utils import ComputeHashMixin @@ -8,13 +8,15 @@ from substrapp.utils import compute_hash from substrapp.ledger_utils import get_object_from_ledger + from ..assets import objective +from ..common import AuthenticatedClient MEDIA_ROOT = "/tmp/unittests_views/" - -# APITestCase class ViewTests(APITestCase): + client_class = AuthenticatedClient + def test_data_sample_path_view(self): self.assertEqual('tutu', path_leaf('/toto/tata/tutu')) self.assertEqual('toto', path_leaf('/toto/')) diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index e3d33d149..a7d4cf7e7 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -17,7 +17,7 @@ from substrapp.utils import get_hash -from ..common import get_sample_algo +from ..common import get_sample_algo, AuthenticatedClient from ..common import FakeRequest from ..assets import objective, datamanager, algo, traintuple, model @@ -30,6 +30,7 @@ @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class AlgoViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/views/tests_views_computeplan.py b/substrabac/substrapp/tests/views/tests_views_computeplan.py index f023cceb6..352351683 100644 --- a/substrabac/substrapp/tests/views/tests_views_computeplan.py +++ b/substrabac/substrapp/tests/views/tests_views_computeplan.py @@ -10,6 +10,7 @@ from rest_framework.test import APITestCase from substrapp.serializers import LedgerComputePlanSerializer +from ..common import AuthenticatedClient MEDIA_ROOT = "/tmp/unittests_views/" @@ -19,6 +20,7 @@ @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class ComputePlanViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 7f03a42f3..5179dd063 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -14,8 +14,7 @@ from substrapp.utils import get_hash -from ..common import get_sample_datamanager -from ..common import FakeRequest +from ..common import get_sample_datamanager, FakeRequest, AuthenticatedClient from ..assets import objective, datamanager, traintuple, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -26,6 +25,7 @@ @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class DataManagerViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 045190de5..1839769a7 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -21,8 +21,7 @@ from django.core.files.uploadedfile import InMemoryUploadedFile -from ..common import get_sample_datamanager -from ..common import FakeFilterDataManager, FakeDataManager +from ..common import get_sample_datamanager, FakeFilterDataManager, FakeDataManager, AuthenticatedClient MEDIA_ROOT = "/tmp/unittests_views/" @@ -34,6 +33,7 @@ @override_settings(DEFAULT_DOMAIN='https://localhost') @override_settings(LEDGER_SYNC_ENABLED=True) class DataSampleViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substrabac/substrapp/tests/views/tests_views_model.py index e5dbf2f5e..8537492d5 100644 --- a/substrabac/substrapp/tests/views/tests_views_model.py +++ b/substrabac/substrapp/tests/views/tests_views_model.py @@ -14,8 +14,7 @@ from substrapp.utils import get_hash -from ..common import get_sample_model -from ..common import FakeRequest +from ..common import get_sample_model, FakeRequest, AuthenticatedClient from ..assets import objective, datamanager, algo, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -25,6 +24,7 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) class ModelViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index ed5a4c01d..837e16a0f 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -19,9 +19,7 @@ from substrapp.views.objective import compute_dryrun as objective_compute_dryrun from substrapp.utils import compute_hash, get_hash - -from ..common import get_sample_objective -from ..common import FakeRequest, FakeTask +from ..common import get_sample_objective, FakeRequest, FakeTask, AuthenticatedClient from ..assets import objective, datamanager, traintuple, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -44,6 +42,7 @@ def zip_folder(path, destination): @override_settings(DEFAULT_DOMAIN='https://localhost') @override_settings(LEDGER_SYNC_ENABLED=True) class ObjectiveViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/views/tests_views_task.py b/substrabac/substrapp/tests/views/tests_views_task.py index d53a97ff5..ecb447ba0 100644 --- a/substrabac/substrapp/tests/views/tests_views_task.py +++ b/substrabac/substrapp/tests/views/tests_views_task.py @@ -10,7 +10,7 @@ from rest_framework import status from rest_framework.test import APITestCase -from ..common import FakeAsyncResult +from ..common import FakeAsyncResult, AuthenticatedClient MEDIA_ROOT = "/tmp/unittests_views/" @@ -19,6 +19,7 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) class TaskViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): diff --git a/substrabac/substrapp/tests/views/tests_views_tuples.py b/substrabac/substrapp/tests/views/tests_views_tuples.py index 7f2854967..e03c77fba 100644 --- a/substrabac/substrapp/tests/views/tests_views_tuples.py +++ b/substrabac/substrapp/tests/views/tests_views_tuples.py @@ -17,6 +17,7 @@ from substrapp.ledger_utils import LedgerError from ..assets import traintuple, testtuple +from ..common import AuthenticatedClient MEDIA_ROOT = "/tmp/unittests_views/" @@ -25,6 +26,7 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) class TraintupleViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): @@ -96,6 +98,7 @@ def test_traintuple_retrieve_fail(self): @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) class TesttupleViewTests(APITestCase): + client_class = AuthenticatedClient def setUp(self): if not os.path.exists(MEDIA_ROOT): From 252bbe737a77a9a493b61de0896ca03e1a530d6c Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 23 Aug 2019 16:23:09 +0200 Subject: [PATCH 222/457] fix docker config --- docker/celerybeat/Dockerfile | 1 + docker/celeryworker/Dockerfile | 1 + docker/flower/Dockerfile | 1 + docker/substrabac/Dockerfile | 1 + 4 files changed, 4 insertions(+) diff --git a/docker/celerybeat/Dockerfile b/docker/celerybeat/Dockerfile index 144cdad4f..43c5f85ea 100644 --- a/docker/celerybeat/Dockerfile +++ b/docker/celerybeat/Dockerfile @@ -14,3 +14,4 @@ RUN pip3 install -r requirements.txt COPY ./substrabac/libs /usr/src/app/libs COPY ./substrabac/substrapp /usr/src/app/substrapp COPY ./substrabac/substrabac /usr/src/app/substrabac +COPY ./substrabac/node /usr/src/app/node diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index 678ac6e68..c362c71a4 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -15,3 +15,4 @@ COPY ./substrabac/libs /usr/src/app/libs COPY ./substrabac/containers /usr/src/app/containers COPY ./substrabac/substrapp /usr/src/app/substrapp COPY ./substrabac/substrabac /usr/src/app/substrabac +COPY ./substrabac/node /usr/src/app/node diff --git a/docker/flower/Dockerfile b/docker/flower/Dockerfile index 5bf9a390b..f5eb80fa7 100644 --- a/docker/flower/Dockerfile +++ b/docker/flower/Dockerfile @@ -15,3 +15,4 @@ RUN pip3 install flower COPY ./substrabac/libs /usr/src/app/libs COPY ./substrabac/substrapp /usr/src/app/substrapp COPY ./substrabac/substrabac /usr/src/app/substrabac +COPY ./substrabac/node /usr/src/app/node diff --git a/docker/substrabac/Dockerfile b/docker/substrabac/Dockerfile index 4e62bed49..e2d82f0d7 100644 --- a/docker/substrabac/Dockerfile +++ b/docker/substrabac/Dockerfile @@ -16,3 +16,4 @@ COPY ./substrabac/libs /usr/src/app/libs COPY ./substrabac/substrapp /usr/src/app/substrapp COPY ./substrabac/events /usr/src/app/events COPY ./substrabac/substrabac /usr/src/app/substrabac +COPY ./substrabac/node /usr/src/app/node From 368e618291efb2f7d01d8a281d6575b4e646ce14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Fri, 23 Aug 2019 16:45:09 +0200 Subject: [PATCH 223/457] linting --- .../node/management/commands/create_incoming_node.py | 7 +++++-- .../node/management/commands/create_outgoing_node.py | 7 +++++-- substrabac/node/management/commands/get_incoming_node.py | 2 +- substrabac/node/management/commands/get_outgoing_node.py | 2 +- substrabac/node/models.py | 1 - .../substrapp/tests/views/test_views_authentication.py | 2 -- substrabac/substrapp/tests/views/tests_views.py | 2 +- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/substrabac/node/management/commands/create_incoming_node.py b/substrabac/node/management/commands/create_incoming_node.py index a21f627d4..2dc305666 100644 --- a/substrabac/node/management/commands/create_incoming_node.py +++ b/substrabac/node/management/commands/create_incoming_node.py @@ -1,4 +1,4 @@ -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from node.models import Node, IncomingNode @@ -9,7 +9,10 @@ def add_arguments(self, parser): parser.add_argument('node_id') def handle(self, *args, **options): - incoming_node, created = IncomingNode.objects.get_or_create(node_id=options['node_id'], secret=Node.generate_secret()) + incoming_node, created = IncomingNode.objects.get_or_create( + node_id=options['node_id'], + secret=Node.generate_secret() + ) if not created: self.stdout.write(self.style.NOTICE(f'node with id {incoming_node.node_id} already exists')) diff --git a/substrabac/node/management/commands/create_outgoing_node.py b/substrabac/node/management/commands/create_outgoing_node.py index 9bc733b14..91b4fa85e 100644 --- a/substrabac/node/management/commands/create_outgoing_node.py +++ b/substrabac/node/management/commands/create_outgoing_node.py @@ -1,4 +1,4 @@ -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from node.models import Node, OutgoingNode @@ -9,7 +9,10 @@ def add_arguments(self, parser): parser.add_argument('node_id') def handle(self, *args, **options): - outgoing_node, created = OutgoingNode.objects.get_or_create(node_id=options['node_id'], secret=Node.generate_secret()) + outgoing_node, created = OutgoingNode.objects.get_or_create( + node_id=options['node_id'], + secret=Node.generate_secret() + ) if not created: self.stdout.write(self.style.NOTICE(f'node with id {outgoing_node.node_id} already exists')) diff --git a/substrabac/node/management/commands/get_incoming_node.py b/substrabac/node/management/commands/get_incoming_node.py index 83a9a527a..020e222e5 100644 --- a/substrabac/node/management/commands/get_incoming_node.py +++ b/substrabac/node/management/commands/get_incoming_node.py @@ -1,4 +1,4 @@ -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from node.models import IncomingNode diff --git a/substrabac/node/management/commands/get_outgoing_node.py b/substrabac/node/management/commands/get_outgoing_node.py index 28ffc109c..f6fed292d 100644 --- a/substrabac/node/management/commands/get_outgoing_node.py +++ b/substrabac/node/management/commands/get_outgoing_node.py @@ -1,4 +1,4 @@ -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from node.models import OutgoingNode diff --git a/substrabac/node/models.py b/substrabac/node/models.py index 643db0692..908da1513 100644 --- a/substrabac/node/models.py +++ b/substrabac/node/models.py @@ -1,5 +1,4 @@ from django.db import models -from django.contrib.auth.models import AbstractUser import secrets diff --git a/substrabac/substrapp/tests/views/test_views_authentication.py b/substrabac/substrapp/tests/views/test_views_authentication.py index 601aaeff4..c9b137463 100644 --- a/substrabac/substrapp/tests/views/test_views_authentication.py +++ b/substrabac/substrapp/tests/views/test_views_authentication.py @@ -1,5 +1,3 @@ -import base64 - from rest_framework import status from rest_framework.test import APITestCase from node.models import IncomingNode diff --git a/substrabac/substrapp/tests/views/tests_views.py b/substrabac/substrapp/tests/views/tests_views.py index af6697edd..a864885e1 100644 --- a/substrabac/substrapp/tests/views/tests_views.py +++ b/substrabac/substrapp/tests/views/tests_views.py @@ -1,6 +1,5 @@ import mock -from rest_framework import status from rest_framework.test import APITestCase from substrapp.views.utils import ComputeHashMixin @@ -14,6 +13,7 @@ MEDIA_ROOT = "/tmp/unittests_views/" + class ViewTests(APITestCase): client_class = AuthenticatedClient From b58be78ae4d5f3ea6d8eee7f6dd71207c6d422a3 Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 23 Aug 2019 16:40:22 +0200 Subject: [PATCH 224/457] update populate and docker/start.py --- docker/start.py | 6 ++++-- populate.py | 19 +++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/docker/start.py b/docker/start.py index 7f8f1c8e1..006a1b4a3 100644 --- a/docker/start.py +++ b/docker/start.py @@ -20,6 +20,8 @@ 'clb': 8002 } +BACKEND_AUTH = ('foo', 'bar') + SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') @@ -145,8 +147,8 @@ def generate_docker_compose_file(conf, launch_settings): f'DJANGO_SETTINGS_MODULE=substrabac.settings.{launch_settings}', # Basic auth - f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', '')}", - f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', '')}", + f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', BACKEND_AUTH[0])}", + f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', BACKEND_AUTH[1])}", f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", ] diff --git a/populate.py b/populate.py index 999d27874..4ed46c93e 100644 --- a/populate.py +++ b/populate.py @@ -12,6 +12,7 @@ dir_path = os.path.dirname(os.path.realpath(__file__)) +USER, PASSWORD = ('foo', 'bar') SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') server_path = f'{SUBSTRA_FOLDER}/servermedias' @@ -21,13 +22,19 @@ def setup_config(network='docker'): print('Init config in /tmp/.substrabac for owkin and chunantes') if network == 'docker': - client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0') - client.add_profile('chunantes', 'http://chunantes.substrabac:8001', '0.0') - client.add_profile('clb', 'http://clb.substrabac:8002', '0.0') + client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0', + user=USER, password=PASSWORD) + client.add_profile('chunantes', 'http://chunantes.substrabac:8001', '0.0', + user=USER, password=PASSWORD) + client.add_profile('clb', 'http://clb.substrabac:8002', '0.0', + user=USER, password=PASSWORD) if network == 'skaffold': - client.add_profile('owkin', 'http://substrabac.node-1', '0.0') - client.add_profile('chunantes', 'http://substrabac.node-2', '0.0') - client.add_profile('clb', 'http://substrabac.node-3', '0.0') + client.add_profile('owkin', 'http://substrabac.node-1', '0.0', + user=USER, password=PASSWORD) + client.add_profile('chunantes', 'http://substrabac.node-2', '0.0', + user=USER, password=PASSWORD) + client.add_profile('clb', 'http://substrabac.node-3', '0.0', + user=USER, password=PASSWORD) def zip_folder(path, destination): From 3b53b5a0fc41c8bf112a626d2adf0ded90179754 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Wed, 28 Aug 2019 16:35:30 +0200 Subject: [PATCH 225/457] update commands to accept secrets --- .../management/commands/create_incoming_node.py | 15 ++++++++------- .../management/commands/create_outgoing_node.py | 5 +++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/substrabac/node/management/commands/create_incoming_node.py b/substrabac/node/management/commands/create_incoming_node.py index 2dc305666..6053820e2 100644 --- a/substrabac/node/management/commands/create_incoming_node.py +++ b/substrabac/node/management/commands/create_incoming_node.py @@ -7,16 +7,17 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument('node_id') + parser.add_argument('secret', nargs='?', default=Node.generate_secret()) def handle(self, *args, **options): - incoming_node, created = IncomingNode.objects.get_or_create( - node_id=options['node_id'], - secret=Node.generate_secret() - ) - - if not created: - self.stdout.write(self.style.NOTICE(f'node with id {incoming_node.node_id} already exists')) + if IncomingNode.objects.filter(node_id=options['node_id']).exists(): + self.stdout.write(self.style.NOTICE(f'node with id {options["node_id"]} already exists')) else: + incoming_node = IncomingNode.objects.create( + node_id=options['node_id'], + secret=options['secret'], + ) + self.stdout.write(self.style.SUCCESS('node successfully created')) self.stdout.write(f'node_id={incoming_node.node_id}') self.stdout.write(f'secret={incoming_node.secret}') diff --git a/substrabac/node/management/commands/create_outgoing_node.py b/substrabac/node/management/commands/create_outgoing_node.py index 91b4fa85e..41cd19276 100644 --- a/substrabac/node/management/commands/create_outgoing_node.py +++ b/substrabac/node/management/commands/create_outgoing_node.py @@ -7,6 +7,7 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument('node_id') + parser.add_argument('secret', nargs='?', default=Node.generate_secret()) def handle(self, *args, **options): outgoing_node, created = OutgoingNode.objects.get_or_create( @@ -17,6 +18,10 @@ def handle(self, *args, **options): if not created: self.stdout.write(self.style.NOTICE(f'node with id {outgoing_node.node_id} already exists')) else: + outgoing_node, created = OutgoingNode.objects.get_or_create( + node_id=options['node_id'], + secret=options['secret'], + ) self.stdout.write(self.style.SUCCESS('node successfully created')) self.stdout.write(f'node_id={outgoing_node.node_id}') self.stdout.write(f'secret={outgoing_node.secret}') From f0cf2952eed089a502cfec64557c4137c1bd84e5 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 30 Aug 2019 14:26:15 +0200 Subject: [PATCH 226/457] fix outgoing node command --- .../management/commands/create_outgoing_node.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/substrabac/node/management/commands/create_outgoing_node.py b/substrabac/node/management/commands/create_outgoing_node.py index 41cd19276..c87bcefcc 100644 --- a/substrabac/node/management/commands/create_outgoing_node.py +++ b/substrabac/node/management/commands/create_outgoing_node.py @@ -10,18 +10,14 @@ def add_arguments(self, parser): parser.add_argument('secret', nargs='?', default=Node.generate_secret()) def handle(self, *args, **options): - outgoing_node, created = OutgoingNode.objects.get_or_create( - node_id=options['node_id'], - secret=Node.generate_secret() - ) - - if not created: - self.stdout.write(self.style.NOTICE(f'node with id {outgoing_node.node_id} already exists')) + if OutgoingNode.objects.filter(node_id=options['node_id']).exists(): + self.stdout.write(self.style.NOTICE(f'node with id {options["node_id"]} already exists')) else: - outgoing_node, created = OutgoingNode.objects.get_or_create( + outgoing_node = OutgoingNode.objects.create( node_id=options['node_id'], secret=options['secret'], ) - self.stdout.write(self.style.SUCCESS('node successfully created')) + + self.stdout.write(self.style.SUCCESS('outgoing node successfully created')) self.stdout.write(f'node_id={outgoing_node.node_id}') self.stdout.write(f'secret={outgoing_node.secret}') From 10e7ff1fce4fa14c2cbb9cbbfba779cbf8f68fb3 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 30 Aug 2019 14:40:51 +0200 Subject: [PATCH 227/457] fix get node command not found cases --- substrabac/node/management/commands/get_incoming_node.py | 8 ++++++-- substrabac/node/management/commands/get_outgoing_node.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/substrabac/node/management/commands/get_incoming_node.py b/substrabac/node/management/commands/get_incoming_node.py index 020e222e5..19a18dd4c 100644 --- a/substrabac/node/management/commands/get_incoming_node.py +++ b/substrabac/node/management/commands/get_incoming_node.py @@ -17,8 +17,12 @@ def handle(self, *args, **options): self.stdout.write(pretty("_" * 64, "_" * 128)) if options['node_id']: - incoming_node = IncomingNode.objects.get(node_id=options['node_id']) - self.stdout.write(self.style.SUCCESS(pretty(incoming_node.node_id, incoming_node.secret))) + try: + incoming_node = IncomingNode.objects.get(node_id=options['node_id']) + except IncomingNode.DoesNotExist: + self.stdout.write(self.style.ERROR(f'Node with id {options["node_id"]} does not exist')) + else: + self.stdout.write(self.style.SUCCESS(pretty(incoming_node.node_id, incoming_node.secret))) else: incoming_nodes = IncomingNode.objects.all() for node in incoming_nodes: diff --git a/substrabac/node/management/commands/get_outgoing_node.py b/substrabac/node/management/commands/get_outgoing_node.py index f6fed292d..fddd53f35 100644 --- a/substrabac/node/management/commands/get_outgoing_node.py +++ b/substrabac/node/management/commands/get_outgoing_node.py @@ -17,8 +17,12 @@ def handle(self, *args, **options): self.stdout.write(pretty("_" * 64, "_" * 128)) if options['node_id']: - outgoing_node = OutgoingNode.objects.get(node_id=options['node_id']) - self.stdout.write(self.style.SUCCESS(pretty(outgoing_node.node_id, outgoing_node.secret))) + try: + outgoing_node = OutgoingNode.objects.get(node_id=options['node_id']) + except OutgoingNode.DoesNotExist: + self.stdout.write(self.style.ERROR(f'Node with id {options["node_id"]} does not exist')) + else: + self.stdout.write(self.style.SUCCESS(pretty(outgoing_node.node_id, outgoing_node.secret))) else: outgoing_nodes = OutgoingNode.objects.all() for node in outgoing_nodes: From fe4fce6d7b555673c9e82b706f0e21f4f389135c Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 3 Sep 2019 15:21:15 +0200 Subject: [PATCH 228/457] move restframework dependencies import --- substrabac/substrabac/settings/common.py | 1 - substrabac/substrabac/settings/dev.py | 1 + substrabac/substrabac/settings/prod.py | 1 + substrabac/substrabac/settings/test.py | 1 + 4 files changed, 3 insertions(+), 1 deletion(-) diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 38be95575..c928c3a67 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -13,7 +13,6 @@ import os import sys from libs.gen_secret_key import write_secret_key -from .deps.restframework import * # noqa # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index b39beebd0..37efc0e89 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -4,6 +4,7 @@ from .deps.cors import * from .deps.org import * from .deps.ledger import * +from .deps.restframework import * # noqa DEBUG = True diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 376ae6f76..1d36bb316 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -5,6 +5,7 @@ from .deps.raven import * from .deps.org import * from .deps.ledger import * +from .deps.restframework import * # noqa DEBUG = False diff --git a/substrabac/substrabac/settings/test.py b/substrabac/substrabac/settings/test.py index 17b5c92fc..d94d84c7b 100644 --- a/substrabac/substrabac/settings/test.py +++ b/substrabac/substrabac/settings/test.py @@ -1,5 +1,6 @@ from .common import * # noqa from .deps.cors import * # noqa +from .deps.restframework import * # noqa import logging logging.disable(logging.CRITICAL) From befdaa8995ebb251203fab379aec2a233bc71948 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 3 Sep 2019 15:41:07 +0200 Subject: [PATCH 229/457] remove backend auth constant config --- docker/start.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docker/start.py b/docker/start.py index 006a1b4a3..7f8f1c8e1 100644 --- a/docker/start.py +++ b/docker/start.py @@ -20,8 +20,6 @@ 'clb': 8002 } -BACKEND_AUTH = ('foo', 'bar') - SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') @@ -147,8 +145,8 @@ def generate_docker_compose_file(conf, launch_settings): f'DJANGO_SETTINGS_MODULE=substrabac.settings.{launch_settings}', # Basic auth - f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', BACKEND_AUTH[0])}", - f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', BACKEND_AUTH[1])}", + f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', '')}", + f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', '')}", f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", ] From b9f07933a15d6b5ea9f902efce5bdef5afe11d24 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Wed, 4 Sep 2019 09:51:30 +0200 Subject: [PATCH 230/457] remove useless noqa --- substrabac/substrabac/settings/dev.py | 2 +- substrabac/substrabac/settings/prod.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 37efc0e89..d2b971bb6 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -4,7 +4,7 @@ from .deps.cors import * from .deps.org import * from .deps.ledger import * -from .deps.restframework import * # noqa +from .deps.restframework import * DEBUG = True diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 1d36bb316..4737a7199 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -5,7 +5,7 @@ from .deps.raven import * from .deps.org import * from .deps.ledger import * -from .deps.restframework import * # noqa +from .deps.restframework import * DEBUG = False From f0997ab2fc938d71de1d6755756231d1f921fb96 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Wed, 4 Sep 2019 09:54:37 +0200 Subject: [PATCH 231/457] remove server_* variables --- substrabac/libs/authentication.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/substrabac/libs/authentication.py b/substrabac/libs/authentication.py index eef326a81..fbc72c63c 100644 --- a/substrabac/libs/authentication.py +++ b/substrabac/libs/authentication.py @@ -10,9 +10,7 @@ def authenticate(self, request, username=None, password=None): if not username or not password: return None - server_username = settings.BASICAUTH_USERNAME - server_password = settings.BASICAUTH_PASSWORD - if username == server_username and password == server_password: + if username == settings.BASICAUTH_USERNAME and password == settings.BASICAUTH_PASSWORD: return User(username) return None From a7a234f3bfed7f4b5871ab5600dfe21b7830693e Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Wed, 4 Sep 2019 10:39:53 +0200 Subject: [PATCH 232/457] update node_id max_length --- substrabac/node/migrations/0001_initial.py | 4 ++-- substrabac/node/models.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrabac/node/migrations/0001_initial.py b/substrabac/node/migrations/0001_initial.py index f29b03031..ba8a0d8f5 100644 --- a/substrabac/node/migrations/0001_initial.py +++ b/substrabac/node/migrations/0001_initial.py @@ -14,7 +14,7 @@ class Migration(migrations.Migration): migrations.CreateModel( name='IncomingNode', fields=[ - ('node_id', models.CharField(max_length=64, primary_key=True, serialize=False)), + ('node_id', models.CharField(max_length=1024, primary_key=True, serialize=False)), ('secret', models.CharField(max_length=128)), ], options={ @@ -24,7 +24,7 @@ class Migration(migrations.Migration): migrations.CreateModel( name='OutgoingNode', fields=[ - ('node_id', models.CharField(max_length=64, primary_key=True, serialize=False)), + ('node_id', models.CharField(max_length=1024, primary_key=True, serialize=False)), ('secret', models.CharField(max_length=128)), ], options={ diff --git a/substrabac/node/models.py b/substrabac/node/models.py index 908da1513..dbb5fde54 100644 --- a/substrabac/node/models.py +++ b/substrabac/node/models.py @@ -3,7 +3,7 @@ class Node(models.Model): - node_id = models.CharField(primary_key=True, max_length=64, blank=False) + node_id = models.CharField(primary_key=True, max_length=1024, blank=False) secret = models.CharField(max_length=128, blank=False) @staticmethod From e1cbb9237ef707dc68ed53741d6b80f59c4a6b69 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Mon, 26 Aug 2019 09:50:37 +0200 Subject: [PATCH 233/457] init draft outgoing node authentication --- substrabac/substrapp/utils.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 456aa97f6..85f3bf181 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -17,6 +17,8 @@ from django.conf import settings from django.core.files.uploadedfile import InMemoryUploadedFile from rest_framework import status +from node.models import OutgoingNode +from requests.auth import HTTPBasicAuth class JsonException(Exception): @@ -190,22 +192,21 @@ class NodeError(Exception): pass -def get_from_node(url): +def get_from_node(url, node_id): kwargs = { 'headers': {'Accept': 'application/json;version=0.0'}, } - username = getattr(settings, 'BASICAUTH_USERNAME', None) - password = getattr(settings, 'BASICAUTH_PASSWORD', None) - if username is not None and password is not None: - kwargs['auth'] = (username, password) + try: + outgoing = OutgoingNode.objects.get(node_id=node_id) + except OutgoingNode.DoesNotExist: + raise NodeError(f'Unauthorized to call node_id: {node_id}') - if settings.DEBUG: - kwargs['verify'] = False + assert(node_id != get_owner()) try: - response = requests.get(url, **kwargs) + response = requests.get(url, auth=HTTPBasicAuth(username, secret), **kwargs) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: raise NodeError(f'Failed to fetch {url}') from e else: From f2d2ba256266c48518194e7d617c2910dca92401 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Mon, 26 Aug 2019 17:19:52 +0200 Subject: [PATCH 234/457] add outgoing basic auth, and fix tests --- substrabac/substrapp/tasks/tasks.py | 36 +++++++-- substrabac/substrapp/tests/tests_tasks.py | 74 +++++++++++-------- .../substrapp/tests/views/tests_views_algo.py | 6 +- .../tests/views/tests_views_datamanager.py | 10 +-- .../tests/views/tests_views_model.py | 10 +-- .../tests/views/tests_views_objective.py | 23 ++++-- substrabac/substrapp/utils.py | 34 ++++----- substrabac/substrapp/views/algo.py | 16 +--- substrabac/substrapp/views/datamanager.py | 30 ++------ substrabac/substrapp/views/model.py | 20 +---- substrabac/substrapp/views/objective.py | 30 +++----- substrabac/substrapp/views/utils.py | 15 +--- 12 files changed, 133 insertions(+), 171 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index bbb698dde..dbca1d49b 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -15,7 +15,7 @@ from substrabac.celery import app from substrapp.utils import get_hash, get_owner, create_directory, get_remote_file, uncompress_content from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, - query_tuples, LedgerError, LedgerStatusError) + query_tuples, LedgerError, LedgerStatusError, get_object_from_ledger) from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code @@ -29,18 +29,24 @@ def get_objective(subtuple): from substrapp.models import Objective - objectiveHash = subtuple['objective']['hash'] + objective_hash = subtuple['objective']['hash'] try: - objective = Objective.objects.get(pk=objectiveHash) + objective = Objective.objects.get(pk=objective_hash) except ObjectDoesNotExist: objective = None # get objective from ledger as it is not available in local db and store it in local db if objective is None or not objective.metrics: - content, computed_hash = get_remote_file(subtuple['objective']['metrics']) + objective_metadata = get_object_from_ledger(objective_hash, 'queryObjective') - objective, _ = Objective.objects.update_or_create(pkhash=objectiveHash, validated=True) + content, _ = get_remote_file( + objective_metadata['metrics']['storageAddress'], + objective_metadata['owner'], + objective_hash, + ) + + objective, _ = Objective.objects.update_or_create(pkhash=objective_hash, validated=True) tmp_file = tempfile.TemporaryFile() tmp_file.write(content) @@ -50,12 +56,28 @@ def get_objective(subtuple): def get_algo(subtuple): - algo_content, _ = get_remote_file(subtuple['algo']) + algo_hash = subtuple['algo']['hash'] + algo_metadata = get_object_from_ledger(algo_hash, 'queryAlgo') + + algo_content, _ = get_remote_file( + algo_metadata['content']['storageAddress'], + algo_metadata['owner'], + algo_hash, + ) + return algo_content def _get_model(model): - model_content, _ = get_remote_file(model, model['traintupleKey']) + traintuple_hash = model['traintupleKey'] + traintuple_metadata = get_object_from_ledger(traintuple_hash, 'queryTraintuple') + + model_content, _ = get_remote_file( + traintuple_metadata['outModel']['storageAddress'], + traintuple_metadata['creator'], + traintuple_hash + ) + return model_content diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index a4b9001a1..72d7c3575 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -6,7 +6,6 @@ from unittest.mock import MagicMock from django.test import override_settings -from django.http import HttpResponse from rest_framework import status from rest_framework.test import APITestCase from django_celery_results.models import TaskResult @@ -14,7 +13,7 @@ from substrapp.models import DataSample from substrapp.ledger_utils import LedgerStatusError from substrapp.utils import store_datasamples_archive -from substrapp.utils import compute_hash, get_computed_hash, get_remote_file, get_hash, create_directory +from substrapp.utils import compute_hash, get_remote_file, get_hash, create_directory from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, put_model, put_models, put_algo, put_metric, put_data_sample, prepare_task, do_task, @@ -22,7 +21,9 @@ from .common import (get_sample_algo, get_sample_script, get_sample_zip_data_sample, get_sample_tar_data_sample, get_sample_model) -from .common import FakeClient, FakeObjective, FakeDataManager, FakeModel +from .common import FakeClient, FakeObjective, FakeDataManager, FakeModel, FakeRequest +from . import assets +from node.models import OutgoingNode import zipfile import docker @@ -50,6 +51,10 @@ def setUp(self): self.ResourcesManager = ResourcesManager() + @classmethod + def setUpTestData(cls): + cls.outgoing_node = OutgoingNode.objects.create(node_id="external_node_id", secret="s3cr37") + def tearDown(self): shutil.rmtree(MEDIA_ROOT, ignore_errors=True) @@ -66,38 +71,30 @@ def test_create_directory(self): except Exception: self.fail('`remove_subtuple_materials` raised Exception unexpectedly!') - def test_get_computed_hash(self): - with mock.patch('substrapp.utils.requests.get') as mget: - mget.return_value = HttpResponse(str(self.script.read())) - _, pkhash = get_computed_hash('localhost') - self.assertEqual(pkhash, get_hash(self.script)) - - with mock.patch('substrapp.utils.requests.get') as mget: - mget.return_value = HttpResponse() - mget.return_value.status_code = status.HTTP_400_BAD_REQUEST - with self.assertRaises(Exception): - get_computed_hash('localhost') - def test_get_remote_file(self): content = str(self.script.read()) + pkhash = compute_hash(content) remote_file = {'storageAddress': 'localhost', - 'hash': compute_hash(content)} + 'hash': pkhash, + 'owner': 'external_node_id', + } - with mock.patch('substrapp.utils.get_computed_hash') as mget_computed_hash: - pkhash = compute_hash(content) - mget_computed_hash.return_value = content, pkhash + with mock.patch('substrapp.utils.get_owner') as get_owner,\ + mock.patch('substrapp.utils.get_from_node') as get_from_node: + get_owner.return_value = 'external_node_id' + get_from_node.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) - content_remote, pkhash_remote = get_remote_file(remote_file) + content_remote, pkhash_remote = get_remote_file(remote_file, 'external_node_id', pkhash) self.assertEqual(pkhash_remote, get_hash(self.script)) self.assertEqual(content_remote, content) - with mock.patch('substrapp.utils.get_computed_hash') as mget_computed_hash: - content = content + ' FAIL' - pkhash = compute_hash(content) - mget_computed_hash.return_value = content, pkhash + with mock.patch('substrapp.utils.get_owner') as get_owner,\ + mock.patch('substrapp.utils.get_from_node') as get_from_node: + get_owner.return_value = 'external_node_id' + get_from_node.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) with self.assertRaises(Exception): - get_remote_file(remote_file) # contents (by pkhash) are different + get_remote_file(remote_file, 'external_node_id', 'fake_pkhash') # contents (by pkhash) are different def test_Ressource_Manager(self): @@ -406,8 +403,10 @@ def test_get_model(self): model_type = 'model' subtuple = {model_type: {'hash': model_hash, 'traintupleKey': traintupleKey}} - with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: + with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ + mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: mget_remote_file.return_value = model_content, model_hash + get_object_from_ledger.return_value = assets.traintuple[1] # uses index 1 to have a set value of outModel model_content = get_model(subtuple) self.assertIsNotNone(model_content) @@ -429,7 +428,8 @@ def test_get_models(self): subtuple = {model_type: [{'hash': model_hash, 'traintupleKey': traintupleKey}, {'hash': model_hash2, 'traintupleKey': traintupleKey2}]} - with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: + with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ + mock.patch('substrapp.tasks.tasks.get_object_from_ledger'): mget_remote_file.side_effect = [[models_content[0], models_hash[0]], [models_content[1], models_hash[1]]] models_content_res = get_models(subtuple) @@ -441,10 +441,21 @@ def test_get_models(self): def test_get_algo(self): algo_content = self.algo.read() algo_hash = get_hash(self.algo) + subtuple = { + 'algo': { + 'storageAddress': assets.algo[0]['content']['storageAddress'], + 'owner': assets.algo[0]['owner'], + 'hash': algo_hash + } + } - with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file: + with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file,\ + mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: mget_remote_file.return_value = algo_content, algo_hash - self.assertEqual(algo_content, get_algo({'algo': ''})) + get_object_from_ledger.return_value = assets.algo[0] + + data = get_algo(subtuple) + self.assertEqual(algo_content, data) def test_get_objective(self): metrics_content = self.script.read().encode('utf-8') @@ -455,11 +466,12 @@ def test_get_objective(self): mget.return_value = FakeObjective() objective = get_objective({'objective': {'hash': objective_hash, - 'metrics': ''}}) + 'metrics': ''}}) self.assertTrue(isinstance(objective, bytes)) self.assertEqual(objective, b'foo') with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ + mock.patch('substrapp.tasks.tasks.get_object_from_ledger'), \ mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: mget.return_value = FakeObjective() @@ -467,7 +479,7 @@ def test_get_objective(self): mupdate_or_create.return_value = FakeObjective(), True objective = get_objective({'objective': {'hash': objective_hash, - 'metrics': ''}}) + 'metrics': ''}}) self.assertTrue(isinstance(objective, bytes)) self.assertEqual(objective, b'foo') diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index a7d4cf7e7..d732aee12 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -18,7 +18,6 @@ from substrapp.utils import get_hash from ..common import get_sample_algo, AuthenticatedClient -from ..common import FakeRequest from ..assets import objective, datamanager, algo, traintuple, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -143,15 +142,14 @@ def test_algo_retrieve(self): url = reverse('substrapp:algo-list') algo_response = [a for a in algo if a['key'] == algo_hash][0] with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.algo.get_from_node') as mrequestsget: + mock.patch('substrapp.views.algo.get_remote_file') as get_remote_file: with open(os.path.join(dir_path, '../../../../fixtures/chunantes/algos/algo4/description.md'), 'rb') as f: content = f.read() mget_object_from_ledger.return_value = algo_response - mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, - content=content) + get_remote_file.return_value = content, algo_hash search_params = f'{algo_hash}/' response = self.client.get(url + search_params, **self.extra) diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 5179dd063..14d9d91f5 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -14,7 +14,7 @@ from substrapp.utils import get_hash -from ..common import get_sample_datamanager, FakeRequest, AuthenticatedClient +from ..common import get_sample_datamanager, AuthenticatedClient from ..assets import objective, datamanager, traintuple, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -113,7 +113,7 @@ def test_datamanager_retrieve(self): datamanager_response = [d for d in datamanager if d['key'] == '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca'][0] with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.datamanager.get_from_node') as mrequestsget: + mock.patch('substrapp.views.datamanager.get_remote_file') as get_remote_file: mget_object_from_ledger.return_value = datamanager_response with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), @@ -125,10 +125,8 @@ def test_datamanager_retrieve(self): '../../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), 'rb') as f: description_content = f.read() - mrequestsget.side_effect = [FakeRequest(status=status.HTTP_200_OK, - content=opener_content), - FakeRequest(status=status.HTTP_200_OK, - content=description_content)] + get_remote_file.side_effect = [(opener_content, ""), + (description_content, "")] search_params = '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/' response = self.client.get(url + search_params, **self.extra) diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substrabac/substrapp/tests/views/tests_views_model.py index 8537492d5..aeed1fbf2 100644 --- a/substrabac/substrapp/tests/views/tests_views_model.py +++ b/substrabac/substrapp/tests/views/tests_views_model.py @@ -14,7 +14,7 @@ from substrapp.utils import get_hash -from ..common import get_sample_model, FakeRequest, AuthenticatedClient +from ..common import get_sample_model, AuthenticatedClient from ..assets import objective, datamanager, algo, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -123,14 +123,10 @@ def test_model_list_filter_algo(self): def test_model_retrieve(self): with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.model.get_from_node') as mrequestsget, \ - mock.patch('substrapp.views.model.ModelViewSet.compute_hash') as mcomputed_hash: + mock.patch('substrapp.views.model.get_remote_file') as get_remote_file: mget_object_from_ledger.return_value = model[1] - mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, - content=self.model.read().encode()) - - mcomputed_hash.return_value = model[1]['traintuple']['outModel']['hash'] + get_remote_file.return_value = (self.model.read().encode(), "") url = reverse('substrapp:model-list') search_params = model[1]['traintuple']['outModel']['hash'] + '/' diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 837e16a0f..a335469c2 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -19,7 +19,7 @@ from substrapp.views.objective import compute_dryrun as objective_compute_dryrun from substrapp.utils import compute_hash, get_hash -from ..common import get_sample_objective, FakeRequest, FakeTask, AuthenticatedClient +from ..common import get_sample_objective, FakeTask, AuthenticatedClient from ..assets import objective, datamanager, traintuple, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -146,17 +146,18 @@ def test_objective_retrieve(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.objective.get_from_node') as mrequestsget: + mock.patch('substrapp.views.objective.get_remote_file') as get_remote_file: mget_object_from_ledger.return_value = objective[0] with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../../../fixtures/owkin/objectives/objective0/description.md'), 'rb') as f: content = f.read() - mrequestsget.return_value = FakeRequest(status=status.HTTP_200_OK, - content=content) + get_remote_file.return_value = (content, '') + + pkhash = compute_hash(content) + search_params = f'{pkhash}/' - search_params = f'{compute_hash(content)}/' response = self.client.get(url + search_params, **self.extra) r = response.json() @@ -289,7 +290,13 @@ def test_objective_compute_dryrun(self): test_data_manager_key = compute_hash(opener_content) with mock.patch('substrapp.views.objective.get_object_from_ledger') as mdatamanager,\ - mock.patch('substrapp.views.objective.get_computed_hash') as mopener: - mdatamanager.return_value = {'opener': {'storageAddress': 'test'}} - mopener.return_value = (opener_content, pkhash) + mock.patch('substrapp.views.objective.get_remote_file') as get_remote_file: + mdatamanager.return_value = { + 'opener': { + 'storageAddress': 'test', + 'hash': pkhash + }, + 'owner': 'external_node_id' + } + get_remote_file.return_value = (opener_content, pkhash) objective_compute_dryrun(zip_path, test_data_manager_key, pkhash) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 85f3bf181..7328ecc21 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -104,24 +104,6 @@ def compute_hash(bytes, key=None): return sha256_hash.hexdigest() -def get_computed_hash(url, key=None): - response = get_from_node(url) - computedHash = compute_hash(response.content, key) - - return response.content, computedHash - - -def get_remote_file(object, key=None): - content, computed_hash = get_computed_hash(object['storageAddress'], key) - - if computed_hash != object['hash']: - msg = 'computed hash is not the same as the hosted file.' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) - - return content, computed_hash - - def create_directory(directory): if not os.path.exists(directory): os.makedirs(directory) @@ -203,10 +185,8 @@ def get_from_node(url, node_id): except OutgoingNode.DoesNotExist: raise NodeError(f'Unauthorized to call node_id: {node_id}') - assert(node_id != get_owner()) - try: - response = requests.get(url, auth=HTTPBasicAuth(username, secret), **kwargs) + response = requests.get(url, auth=HTTPBasicAuth(outgoing.node_id, outgoing.secret), **kwargs) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: raise NodeError(f'Failed to fetch {url}') from e else: @@ -215,3 +195,15 @@ def get_from_node(url, node_id): raise NodeError(f'Url: {url} returned status code: {response.status_code}') return response + + +def get_remote_file(url, node_id, content_hash): + response = get_from_node(url, node_id) + computed_hash = compute_hash(response.content) + + if computed_hash != content_hash: + msg = 'computed hash is not the same as the hosted file.' \ + 'Please investigate for default of synchronization or corruption' + raise Exception(msg) + + return response.content, computed_hash diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index a3f3e011e..c0faac63c 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -10,7 +10,7 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer -from substrapp.utils import get_hash, get_from_node, is_archive +from substrapp.utils import get_hash, get_remote_file, is_archive from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, get_success_create_code, LedgerException, ValidationException) @@ -111,20 +111,10 @@ def create_or_update_algo(self, algo, pk): # get algo description from remote node url = algo['description']['storageAddress'] - response = get_from_node(url) - - try: - computed_hash = self.compute_hash(response.content) - except Exception as e: - raise Exception('Failed to fetch description file') from e - - if computed_hash != algo['description']['hash']: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) + content, _ = get_remote_file(url, algo['owner'], algo['description']['hash']) f = tempfile.TemporaryFile() - f.write(response.content) + f.write(content) # save/update objective in local db for later use instance, created = Algo.objects.update_or_create(pkhash=pk, validated=True) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 1f6ca0c41..ac3ba01ce 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -15,7 +15,7 @@ from substrapp.serializers import DataManagerSerializer, LedgerDataManagerSerializer from substrapp.serializers.ledger.datamanager.util import updateLedgerDataManager from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync -from substrapp.utils import get_hash, get_from_node +from substrapp.utils import get_hash, get_remote_file from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (ManageFileMixin, ComputeHashMixin, find_primary_key_error, validate_pk, get_success_create_code, ValidationException, LedgerException) @@ -150,20 +150,10 @@ def create_or_update_datamanager(self, instance, datamanager, pk): if not instance.data_opener: url = datamanager['opener']['storageAddress'] - response = get_from_node(url) - - try: - computed_hash = self.compute_hash(response.content) - except Exception as e: - raise Exception('Failed to fetch opener file') from e - - if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) + content, _ = get_remote_file(url, datamanager['owner'], datamanager['opener']['hash']) f = tempfile.TemporaryFile() - f.write(response.content) + f.write(content) # save/update data_opener in local db for later use instance.data_opener.save('opener.py', f) @@ -172,20 +162,10 @@ def create_or_update_datamanager(self, instance, datamanager, pk): if not instance.description: url = datamanager['description']['storageAddress'] - response = get_from_node(url) - - try: - computed_hash = self.compute_hash(response.content) - except Exception as e: - raise Exception('Failed to fetch description file') from e - - if computed_hash != datamanager['description']['hash']: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) + content, _ = get_remote_file(url, datamanager['owner'], datamanager['description']['hash']) f = tempfile.TemporaryFile() - f.write(response.content) + f.write(content) # save/update description in local db for later use instance.description.save('description.md', f) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 5ed0f0c97..a9954c9c2 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -10,15 +10,14 @@ from substrapp.models import Model from substrapp.serializers import ModelSerializer -from substrapp.utils import get_from_node +from substrapp.utils import get_remote_file from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError -from substrapp.views.utils import ComputeHashMixin, CustomFileResponse, validate_pk +from substrapp.views.utils import CustomFileResponse, validate_pk from substrapp.views.filters_utils import filter_list class ModelViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, - ComputeHashMixin, GenericViewSet): queryset = Model.objects.all() serializer_class = ModelSerializer @@ -32,22 +31,11 @@ def create_or_update_model(self, traintuple, pk): # get model from remote node url = traintuple['outModel']['storageAddress'] - response = get_from_node(url) - - # verify model received has a good pkhash - try: - computed_hash = self.compute_hash(response.content, traintuple['key']) - except Exception: - raise Exception('Failed to fetch outModel file') - else: - if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) + content, _ = get_remote_file(url, traintuple['creator'], traintuple['key']) # write model in local db for later use tmp_model = tempfile.TemporaryFile() - tmp_model.write(response.content) + tmp_model.write(content) instance, created = Model.objects.update_or_create(pkhash=pk, validated=True) instance.file.save('model', tmp_model) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 843240e08..2d5a3c6eb 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -22,7 +22,7 @@ from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.utils import get_hash, get_computed_hash, get_from_node, create_directory, uncompress_path, is_archive +from substrapp.utils import get_hash, create_directory, uncompress_path, get_remote_file, is_archive from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ get_success_create_code, ValidationException, LedgerException @@ -176,22 +176,11 @@ def create_or_update_objective(self, objective, pk): # get description from remote node url = objective['description']['storageAddress'] - response = get_from_node(url) - - # verify description received has a good pkhash - try: - computed_hash = self.compute_hash(response.content) - except Exception: - raise Exception('Failed to fetch description file') - else: - if computed_hash != pk: - msg = 'computed hash is not the same as the hosted file. ' \ - 'Please investigate for default of synchronization, corruption, or hacked' - raise Exception(msg) + content, _ = get_remote_file(url, objective['owner'], pk) # write objective with description in local db for later use tmp_description = tempfile.TemporaryFile() - tmp_description.write(response.content) + tmp_description.write(content) instance, created = Objective.objects.update_or_create(pkhash=pk, validated=True) instance.description.save('description.md', tmp_description) @@ -209,10 +198,7 @@ def _retrieve(self, pk): instance = None if not instance or not instance.description: - try: - instance = self.create_or_update_objective(data, pk) - except Exception as e: - return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + instance = self.create_or_update_objective(data, pk) # For security reason, do not give access to local file address # Restrain data to some fields @@ -283,7 +269,7 @@ def data(self, request, *args, **kwargs): def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): if not test_data_manager_key: os.remove(archive_path) - raise Exception('Cannot do a objective dryrun without a data manager key.') + raise Exception('Cannot do an objective dryrun without a data manager key.') dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' @@ -293,8 +279,12 @@ def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): os.remove(archive_path) datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') + opener_content, opener_computed_hash = get_remote_file( + datamanager['opener']['storageAddress'], + datamanager['owner'], + datamanager['opener']['hash'], + ) - opener_content, opener_computed_hash = get_computed_hash(datamanager['opener']['storageAddress']) with open(os.path.join(subtuple_directory, 'opener/opener.py'), 'wb') as fh: fh.write(opener_content) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index d8521024e..b8205009c 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -1,10 +1,10 @@ -import hashlib import os from django.http import FileResponse from rest_framework.response import Response from substrapp.ledger_utils import get_object_from_ledger, LedgerError +from substrapp.utils import compute_hash from django.conf import settings from rest_framework import status @@ -12,18 +12,7 @@ class ComputeHashMixin(object): def compute_hash(self, file, key=None): - - sha256_hash = hashlib.sha256() - if isinstance(file, str): - file = file.encode() - - if key is not None and isinstance(key, str): - file += key.encode() - - sha256_hash.update(file) - computedHash = sha256_hash.hexdigest() - - return computedHash + return compute_hash(file, key) class CustomFileResponse(FileResponse): From e71544865499d03c70055f5a92166b607a7837f9 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 27 Aug 2019 09:17:11 +0200 Subject: [PATCH 235/457] add get from node basic auth for internal workers --- substrabac/substrapp/tests/tests_tasks.py | 8 ++++---- substrabac/substrapp/utils.py | 23 ++++++++++++----------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 72d7c3575..0b0d1abd0 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -80,18 +80,18 @@ def test_get_remote_file(self): } with mock.patch('substrapp.utils.get_owner') as get_owner,\ - mock.patch('substrapp.utils.get_from_node') as get_from_node: + mock.patch('substrapp.utils.requests.get') as request_get: get_owner.return_value = 'external_node_id' - get_from_node.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) + request_get.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) content_remote, pkhash_remote = get_remote_file(remote_file, 'external_node_id', pkhash) self.assertEqual(pkhash_remote, get_hash(self.script)) self.assertEqual(content_remote, content) with mock.patch('substrapp.utils.get_owner') as get_owner,\ - mock.patch('substrapp.utils.get_from_node') as get_from_node: + mock.patch('substrapp.utils.requests.get') as request_get: get_owner.return_value = 'external_node_id' - get_from_node.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) + request_get.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) with self.assertRaises(Exception): get_remote_file(remote_file, 'external_node_id', 'fake_pkhash') # contents (by pkhash) are different diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 7328ecc21..03694bd17 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -174,19 +174,20 @@ class NodeError(Exception): pass -def get_from_node(url, node_id): - - kwargs = { - 'headers': {'Accept': 'application/json;version=0.0'}, - } +def _get_from_node(url, node_id): + # This handle worker node authentication + if node_id == get_owner(): + auth = HTTPBasicAuth(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) + else: + try: + outgoing = OutgoingNode.objects.get(node_id=node_id) + except OutgoingNode.DoesNotExist: + raise NodeError(f'Unauthorized to call node_id: {node_id}') - try: - outgoing = OutgoingNode.objects.get(node_id=node_id) - except OutgoingNode.DoesNotExist: - raise NodeError(f'Unauthorized to call node_id: {node_id}') + auth = HTTPBasicAuth(outgoing.node_id, outgoing.secret) try: - response = requests.get(url, auth=HTTPBasicAuth(outgoing.node_id, outgoing.secret), **kwargs) + response = requests.get(url, auth=auth, headers={'Accept': 'application/json;version=0.0'}) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: raise NodeError(f'Failed to fetch {url}') from e else: @@ -198,7 +199,7 @@ def get_from_node(url, node_id): def get_remote_file(url, node_id, content_hash): - response = get_from_node(url, node_id) + response = _get_from_node(url, node_id) computed_hash = compute_hash(response.content) if computed_hash != content_hash: From f883e95b9591f0070bd9977c49b6433a8342b78e Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 27 Aug 2019 10:28:06 +0200 Subject: [PATCH 236/457] fixes tests and rename functions --- substrabac/substrapp/tasks/tasks.py | 40 +++++++++++++++---- substrabac/substrapp/tests/tests_tasks.py | 6 +++ .../substrapp/tests/views/tests_views_algo.py | 5 +-- .../tests/views/tests_views_datamanager.py | 5 +-- .../tests/views/tests_views_model.py | 4 +- .../tests/views/tests_views_objective.py | 8 ++-- substrabac/substrapp/utils.py | 19 ++------- substrabac/substrapp/views/algo.py | 7 ++-- substrabac/substrapp/views/datamanager.py | 9 +++-- substrabac/substrapp/views/model.py | 6 +-- substrabac/substrapp/views/objective.py | 8 ++-- substrabac/substrapp/views/utils.py | 20 +++++++++- 12 files changed, 85 insertions(+), 52 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index dbca1d49b..7f3533a74 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -4,26 +4,50 @@ import shutil import tempfile from os import path +import json +from multiprocessing.managers import BaseManager +import logging +import docker from checksumdir import dirhash from django.core.exceptions import ObjectDoesNotExist from django.conf import settings from rest_framework.reverse import reverse from celery.result import AsyncResult from celery.exceptions import Ignore +from requests.auth import HTTPBasicAuth from substrabac.celery import app -from substrapp.utils import get_hash, get_owner, create_directory, get_remote_file, uncompress_content +from substrapp.utils import get_hash, get_owner, create_directory, get_remote_file, uncompress_content, NodeError from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, query_tuples, LedgerError, LedgerStatusError, get_object_from_ledger) from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code +from node.models import OutgoingNode -import docker -import json -from multiprocessing.managers import BaseManager -import logging +def _authenticate_worker(node_id): + # This handle worker node authentication + # WARN: This should use a different authentication + # Backend (WorkerBackend for example) to be able + # to differiciate regural node users from workers + if node_id == get_owner(): + auth = HTTPBasicAuth(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) + else: + try: + outgoing = OutgoingNode.objects.get(node_id=node_id) + except OutgoingNode.DoesNotExist: + raise NodeError(f'Unauthorized to call node_id: {node_id}') + + auth = HTTPBasicAuth(outgoing.node_id, outgoing.secret) + + return auth + + +def _get_asset_content(url, node_id, content_hash): + content, _ = get_remote_file(url, _authenticate_worker(node_id), content_hash) + + return content def get_objective(subtuple): @@ -40,7 +64,7 @@ def get_objective(subtuple): if objective is None or not objective.metrics: objective_metadata = get_object_from_ledger(objective_hash, 'queryObjective') - content, _ = get_remote_file( + content = _get_asset_content( objective_metadata['metrics']['storageAddress'], objective_metadata['owner'], objective_hash, @@ -59,7 +83,7 @@ def get_algo(subtuple): algo_hash = subtuple['algo']['hash'] algo_metadata = get_object_from_ledger(algo_hash, 'queryAlgo') - algo_content, _ = get_remote_file( + algo_content = _get_asset_content( algo_metadata['content']['storageAddress'], algo_metadata['owner'], algo_hash, @@ -72,7 +96,7 @@ def _get_model(model): traintuple_hash = model['traintupleKey'] traintuple_metadata = get_object_from_ledger(traintuple_hash, 'queryTraintuple') - model_content, _ = get_remote_file( + model_content = _get_asset_content( traintuple_metadata['outModel']['storageAddress'], traintuple_metadata['creator'], traintuple_hash diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 0b0d1abd0..59acee572 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -404,8 +404,10 @@ def test_get_model(self): subtuple = {model_type: {'hash': model_hash, 'traintupleKey': traintupleKey}} with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ + mock.patch('substrapp.tasks.tasks.get_owner') as get_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: mget_remote_file.return_value = model_content, model_hash + get_owner.return_value = assets.traintuple[1]['creator'] get_object_from_ledger.return_value = assets.traintuple[1] # uses index 1 to have a set value of outModel model_content = get_model(subtuple) @@ -429,6 +431,7 @@ def test_get_models(self): {'hash': model_hash2, 'traintupleKey': traintupleKey2}]} with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ + mock.patch('substrapp.tasks.tasks._authenticate_worker'),\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger'): mget_remote_file.side_effect = [[models_content[0], models_hash[0]], [models_content[1], models_hash[1]]] @@ -450,8 +453,10 @@ def test_get_algo(self): } with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file,\ + mock.patch('substrapp.tasks.tasks.get_owner') as get_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: mget_remote_file.return_value = algo_content, algo_hash + get_owner.return_value = assets.algo[0]['owner'] get_object_from_ledger.return_value = assets.algo[0] data = get_algo(subtuple) @@ -472,6 +477,7 @@ def test_get_objective(self): with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ mock.patch('substrapp.tasks.tasks.get_object_from_ledger'), \ + mock.patch('substrapp.tasks.tasks._authenticate_worker'),\ mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: mget.return_value = FakeObjective() diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index d732aee12..7fa4526de 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -142,14 +142,13 @@ def test_algo_retrieve(self): url = reverse('substrapp:algo-list') algo_response = [a for a in algo if a['key'] == algo_hash][0] with mock.patch('substrapp.views.algo.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.algo.get_remote_file') as get_remote_file: + mock.patch('substrapp.views.algo.get_remote_asset') as get_remote_asset: with open(os.path.join(dir_path, '../../../../fixtures/chunantes/algos/algo4/description.md'), 'rb') as f: content = f.read() mget_object_from_ledger.return_value = algo_response - - get_remote_file.return_value = content, algo_hash + get_remote_asset.return_value = content search_params = f'{algo_hash}/' response = self.client.get(url + search_params, **self.extra) diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 14d9d91f5..366afc16c 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -113,7 +113,7 @@ def test_datamanager_retrieve(self): datamanager_response = [d for d in datamanager if d['key'] == '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca'][0] with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.datamanager.get_remote_file') as get_remote_file: + mock.patch('substrapp.views.datamanager.get_remote_asset') as get_remote_asset: mget_object_from_ledger.return_value = datamanager_response with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), @@ -125,8 +125,7 @@ def test_datamanager_retrieve(self): '../../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), 'rb') as f: description_content = f.read() - get_remote_file.side_effect = [(opener_content, ""), - (description_content, "")] + get_remote_asset.side_effect = [opener_content, description_content] search_params = '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/' response = self.client.get(url + search_params, **self.extra) diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substrabac/substrapp/tests/views/tests_views_model.py index aeed1fbf2..27dda4a35 100644 --- a/substrabac/substrapp/tests/views/tests_views_model.py +++ b/substrabac/substrapp/tests/views/tests_views_model.py @@ -123,10 +123,10 @@ def test_model_list_filter_algo(self): def test_model_retrieve(self): with mock.patch('substrapp.views.model.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.model.get_remote_file') as get_remote_file: + mock.patch('substrapp.views.model.get_remote_asset') as get_remote_asset: mget_object_from_ledger.return_value = model[1] - get_remote_file.return_value = (self.model.read().encode(), "") + get_remote_asset.return_value = self.model.read().encode() url = reverse('substrapp:model-list') search_params = model[1]['traintuple']['outModel']['hash'] + '/' diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index a335469c2..fcc772bfc 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -146,14 +146,14 @@ def test_objective_retrieve(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.objective.get_remote_file') as get_remote_file: + mock.patch('substrapp.views.objective.get_remote_asset') as get_remote_asset: mget_object_from_ledger.return_value = objective[0] with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../../../fixtures/owkin/objectives/objective0/description.md'), 'rb') as f: content = f.read() - get_remote_file.return_value = (content, '') + get_remote_asset.return_value = content pkhash = compute_hash(content) search_params = f'{pkhash}/' @@ -290,7 +290,7 @@ def test_objective_compute_dryrun(self): test_data_manager_key = compute_hash(opener_content) with mock.patch('substrapp.views.objective.get_object_from_ledger') as mdatamanager,\ - mock.patch('substrapp.views.objective.get_remote_file') as get_remote_file: + mock.patch('substrapp.views.objective.get_remote_asset') as get_remote_asset: mdatamanager.return_value = { 'opener': { 'storageAddress': 'test', @@ -298,5 +298,5 @@ def test_objective_compute_dryrun(self): }, 'owner': 'external_node_id' } - get_remote_file.return_value = (opener_content, pkhash) + get_remote_asset.return_value = opener_content objective_compute_dryrun(zip_path, test_data_manager_key, pkhash) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 03694bd17..24f9128cf 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -17,8 +17,6 @@ from django.conf import settings from django.core.files.uploadedfile import InMemoryUploadedFile from rest_framework import status -from node.models import OutgoingNode -from requests.auth import HTTPBasicAuth class JsonException(Exception): @@ -174,18 +172,7 @@ class NodeError(Exception): pass -def _get_from_node(url, node_id): - # This handle worker node authentication - if node_id == get_owner(): - auth = HTTPBasicAuth(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) - else: - try: - outgoing = OutgoingNode.objects.get(node_id=node_id) - except OutgoingNode.DoesNotExist: - raise NodeError(f'Unauthorized to call node_id: {node_id}') - - auth = HTTPBasicAuth(outgoing.node_id, outgoing.secret) - +def _get_from_node(url, auth): try: response = requests.get(url, auth=auth, headers={'Accept': 'application/json;version=0.0'}) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: @@ -198,8 +185,8 @@ def _get_from_node(url, node_id): return response -def get_remote_file(url, node_id, content_hash): - response = _get_from_node(url, node_id) +def get_remote_file(url, auth, content_hash): + response = _get_from_node(url, auth) computed_hash = compute_hash(response.content) if computed_hash != content_hash: diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index c0faac63c..cc4c5cfb8 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -10,10 +10,11 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer -from substrapp.utils import get_hash, get_remote_file, is_archive +from substrapp.utils import get_hash, is_archive from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (ComputeHashMixin, ManageFileMixin, find_primary_key_error, - validate_pk, get_success_create_code, LedgerException, ValidationException) + validate_pk, get_success_create_code, LedgerException, ValidationException, + get_remote_asset) from substrapp.views.filters_utils import filter_list @@ -111,7 +112,7 @@ def create_or_update_algo(self, algo, pk): # get algo description from remote node url = algo['description']['storageAddress'] - content, _ = get_remote_file(url, algo['owner'], algo['description']['hash']) + content = get_remote_asset(url, algo['owner'], algo['description']['hash']) f = tempfile.TemporaryFile() f.write(content) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index ac3ba01ce..00383ba98 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -15,10 +15,11 @@ from substrapp.serializers import DataManagerSerializer, LedgerDataManagerSerializer from substrapp.serializers.ledger.datamanager.util import updateLedgerDataManager from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync -from substrapp.utils import get_hash, get_remote_file +from substrapp.utils import get_hash from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (ManageFileMixin, ComputeHashMixin, find_primary_key_error, - validate_pk, get_success_create_code, ValidationException, LedgerException) + validate_pk, get_success_create_code, ValidationException, LedgerException, + get_remote_asset) from substrapp.views.filters_utils import filter_list @@ -150,7 +151,7 @@ def create_or_update_datamanager(self, instance, datamanager, pk): if not instance.data_opener: url = datamanager['opener']['storageAddress'] - content, _ = get_remote_file(url, datamanager['owner'], datamanager['opener']['hash']) + content = get_remote_asset(url, datamanager['owner'], datamanager['opener']['hash']) f = tempfile.TemporaryFile() f.write(content) @@ -162,7 +163,7 @@ def create_or_update_datamanager(self, instance, datamanager, pk): if not instance.description: url = datamanager['description']['storageAddress'] - content, _ = get_remote_file(url, datamanager['owner'], datamanager['description']['hash']) + content = get_remote_asset(url, datamanager['owner'], datamanager['description']['hash']) f = tempfile.TemporaryFile() f.write(content) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index a9954c9c2..37ddcc68e 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -9,10 +9,8 @@ from substrapp.models import Model from substrapp.serializers import ModelSerializer - -from substrapp.utils import get_remote_file from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError -from substrapp.views.utils import CustomFileResponse, validate_pk +from substrapp.views.utils import CustomFileResponse, validate_pk, get_remote_asset from substrapp.views.filters_utils import filter_list @@ -31,7 +29,7 @@ def create_or_update_model(self, traintuple, pk): # get model from remote node url = traintuple['outModel']['storageAddress'] - content, _ = get_remote_file(url, traintuple['creator'], traintuple['key']) + content = get_remote_asset(url, traintuple['creator'], traintuple['key']) # write model in local db for later use tmp_model = tempfile.TemporaryFile() diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 2d5a3c6eb..e3dffcae0 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -22,10 +22,10 @@ from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.utils import get_hash, create_directory, uncompress_path, get_remote_file, is_archive +from substrapp.utils import get_hash, create_directory, uncompress_path, is_archive from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ - get_success_create_code, ValidationException, LedgerException + get_success_create_code, ValidationException, LedgerException, get_remote_asset from substrapp.views.filters_utils import filter_list @@ -176,7 +176,7 @@ def create_or_update_objective(self, objective, pk): # get description from remote node url = objective['description']['storageAddress'] - content, _ = get_remote_file(url, objective['owner'], pk) + content = get_remote_asset(url, objective['owner'], pk) # write objective with description in local db for later use tmp_description = tempfile.TemporaryFile() @@ -279,7 +279,7 @@ def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): os.remove(archive_path) datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') - opener_content, opener_computed_hash = get_remote_file( + opener_content = get_remote_asset( datamanager['opener']['storageAddress'], datamanager['owner'], datamanager['opener']['hash'], diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index b8205009c..1cb2b1f55 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -4,10 +4,28 @@ from rest_framework.response import Response from substrapp.ledger_utils import get_object_from_ledger, LedgerError -from substrapp.utils import compute_hash +from substrapp.utils import compute_hash, NodeError, get_remote_file +from node.models import OutgoingNode from django.conf import settings from rest_framework import status +from requests.auth import HTTPBasicAuth + + +def authenticate_outgoing_request(node_id): + try: + outgoing = OutgoingNode.objects.get(node_id=node_id) + except OutgoingNode.DoesNotExist: + raise NodeError(f'Unauthorized to call node_id: {node_id}') + + return HTTPBasicAuth(outgoing.node_id, outgoing.secret) + + +def get_remote_asset(url, node_id, content_hash): + auth = authenticate_outgoing_request(node_id) + content, _ = get_remote_file(url, auth, content_hash) + + return content class ComputeHashMixin(object): From 78597d94869118201aabc0ec65c9d5ee9fe2f27a Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 27 Aug 2019 10:39:04 +0200 Subject: [PATCH 237/457] change remote_file signature --- substrabac/substrapp/tasks/tasks.py | 4 +--- substrabac/substrapp/tests/tests_tasks.py | 12 +++++------- substrabac/substrapp/utils.py | 2 +- substrabac/substrapp/views/utils.py | 3 +-- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 7f3533a74..b29a06689 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -45,9 +45,7 @@ def _authenticate_worker(node_id): def _get_asset_content(url, node_id, content_hash): - content, _ = get_remote_file(url, _authenticate_worker(node_id), content_hash) - - return content + return get_remote_file(url, _authenticate_worker(node_id), content_hash) def get_objective(subtuple): diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 59acee572..5c8d65f61 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -84,8 +84,7 @@ def test_get_remote_file(self): get_owner.return_value = 'external_node_id' request_get.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) - content_remote, pkhash_remote = get_remote_file(remote_file, 'external_node_id', pkhash) - self.assertEqual(pkhash_remote, get_hash(self.script)) + content_remote = get_remote_file(remote_file, 'external_node_id', pkhash) self.assertEqual(content_remote, content) with mock.patch('substrapp.utils.get_owner') as get_owner,\ @@ -406,7 +405,7 @@ def test_get_model(self): with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ mock.patch('substrapp.tasks.tasks.get_owner') as get_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: - mget_remote_file.return_value = model_content, model_hash + mget_remote_file.return_value = model_content get_owner.return_value = assets.traintuple[1]['creator'] get_object_from_ledger.return_value = assets.traintuple[1] # uses index 1 to have a set value of outModel model_content = get_model(subtuple) @@ -433,8 +432,7 @@ def test_get_models(self): with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ mock.patch('substrapp.tasks.tasks._authenticate_worker'),\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger'): - mget_remote_file.side_effect = [[models_content[0], models_hash[0]], - [models_content[1], models_hash[1]]] + mget_remote_file.side_effect = (models_content[0], models_content[1]) models_content_res = get_models(subtuple) self.assertEqual(models_content_res, models_content) @@ -455,7 +453,7 @@ def test_get_algo(self): with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file,\ mock.patch('substrapp.tasks.tasks.get_owner') as get_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: - mget_remote_file.return_value = algo_content, algo_hash + mget_remote_file.return_value = algo_content get_owner.return_value = assets.algo[0]['owner'] get_object_from_ledger.return_value = assets.algo[0] @@ -481,7 +479,7 @@ def test_get_objective(self): mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: mget.return_value = FakeObjective() - mget_remote_file.return_value = metrics_content, objective_hash + mget_remote_file.return_value = metrics_content mupdate_or_create.return_value = FakeObjective(), True objective = get_objective({'objective': {'hash': objective_hash, diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 24f9128cf..dd77ada3b 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -194,4 +194,4 @@ def get_remote_file(url, auth, content_hash): 'Please investigate for default of synchronization or corruption' raise Exception(msg) - return response.content, computed_hash + return response.content diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 1cb2b1f55..d81fb4083 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -23,9 +23,8 @@ def authenticate_outgoing_request(node_id): def get_remote_asset(url, node_id, content_hash): auth = authenticate_outgoing_request(node_id) - content, _ = get_remote_file(url, auth, content_hash) - return content + return get_remote_file(url, auth, content_hash) class ComputeHashMixin(object): From 936840752db002728899bd7153e9bdf4c4316b74 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 27 Aug 2019 10:43:08 +0200 Subject: [PATCH 238/457] remove compute hash mixin --- substrabac/substrapp/tests/views/tests_views.py | 13 ------------- substrabac/substrapp/views/algo.py | 3 +-- substrabac/substrapp/views/datamanager.py | 3 +-- substrabac/substrapp/views/objective.py | 3 +-- substrabac/substrapp/views/utils.py | 7 +------ 5 files changed, 4 insertions(+), 25 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views.py b/substrabac/substrapp/tests/views/tests_views.py index a864885e1..1f1def046 100644 --- a/substrabac/substrapp/tests/views/tests_views.py +++ b/substrabac/substrapp/tests/views/tests_views.py @@ -2,7 +2,6 @@ from rest_framework.test import APITestCase -from substrapp.views.utils import ComputeHashMixin from substrapp.views.datasample import path_leaf from substrapp.utils import compute_hash from substrapp.ledger_utils import get_object_from_ledger @@ -21,18 +20,6 @@ def test_data_sample_path_view(self): self.assertEqual('tutu', path_leaf('/toto/tata/tutu')) self.assertEqual('toto', path_leaf('/toto/')) - def test_utils_ComputeHashMixin(self): - - compute = ComputeHashMixin() - myfile = 'toto' - key = 'tata' - - myfilehash = compute_hash(myfile) - myfilehashwithkey = compute_hash(myfile, key) - - self.assertEqual(myfilehash, compute.compute_hash(myfile)) - self.assertEqual(myfilehashwithkey, compute.compute_hash(myfile, key)) - def test_utils_get_object_from_ledger(self): with mock.patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index cc4c5cfb8..4f9f4f172 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -12,7 +12,7 @@ from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer from substrapp.utils import get_hash, is_archive from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.views.utils import (ComputeHashMixin, ManageFileMixin, find_primary_key_error, +from substrapp.views.utils import (ManageFileMixin, find_primary_key_error, validate_pk, get_success_create_code, LedgerException, ValidationException, get_remote_asset) from substrapp.views.filters_utils import filter_list @@ -21,7 +21,6 @@ class AlgoViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, - ComputeHashMixin, ManageFileMixin, GenericViewSet): queryset = Algo.objects.all() diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 00383ba98..b5cf3340a 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -17,7 +17,7 @@ from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync from substrapp.utils import get_hash from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.views.utils import (ManageFileMixin, ComputeHashMixin, find_primary_key_error, +from substrapp.views.utils import (ManageFileMixin, find_primary_key_error, validate_pk, get_success_create_code, ValidationException, LedgerException, get_remote_asset) from substrapp.views.filters_utils import filter_list @@ -26,7 +26,6 @@ class DataManagerViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, - ComputeHashMixin, ManageFileMixin, GenericViewSet): queryset = DataManager.objects.all() diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index e3dffcae0..79e098280 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -24,7 +24,7 @@ from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.utils import get_hash, create_directory, uncompress_path, is_archive from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.views.utils import ComputeHashMixin, ManageFileMixin, find_primary_key_error, validate_pk, \ +from substrapp.views.utils import ManageFileMixin, find_primary_key_error, validate_pk, \ get_success_create_code, ValidationException, LedgerException, get_remote_asset from substrapp.views.filters_utils import filter_list @@ -32,7 +32,6 @@ class ObjectiveViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, - ComputeHashMixin, ManageFileMixin, GenericViewSet): queryset = Objective.objects.all() diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index d81fb4083..db2d7ac00 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -4,7 +4,7 @@ from rest_framework.response import Response from substrapp.ledger_utils import get_object_from_ledger, LedgerError -from substrapp.utils import compute_hash, NodeError, get_remote_file +from substrapp.utils import NodeError, get_remote_file from node.models import OutgoingNode from django.conf import settings @@ -27,11 +27,6 @@ def get_remote_asset(url, node_id, content_hash): return get_remote_file(url, auth, content_hash) -class ComputeHashMixin(object): - def compute_hash(self, file, key=None): - return compute_hash(file, key) - - class CustomFileResponse(FileResponse): def set_headers(self, filelike): super(CustomFileResponse, self).set_headers(filelike) From 2be900e819dc21d9dc3c06c607382ada323a1f00 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 27 Aug 2019 17:01:08 +0200 Subject: [PATCH 239/457] fixes node models import in tasks --- substrabac/substrapp/tasks/tasks.py | 3 ++- substrabac/substrapp/tests/tests_tasks.py | 1 - substrabac/substrapp/tests/views/tests_views.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index b29a06689..79222d417 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -23,10 +23,11 @@ query_tuples, LedgerError, LedgerStatusError, get_object_from_ledger) from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.exception_handler import compute_error_code -from node.models import OutgoingNode def _authenticate_worker(node_id): + from node.models import OutgoingNode + # This handle worker node authentication # WARN: This should use a different authentication # Backend (WorkerBackend for example) to be able diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 5c8d65f61..60c39b095 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -424,7 +424,6 @@ def test_get_models(self): traintupleKey2 = compute_hash(models_content[1]) model_hash2 = compute_hash(models_content[1], traintupleKey2) - models_hash = [model_hash, model_hash2] model_type = 'inModels' subtuple = {model_type: [{'hash': model_hash, 'traintupleKey': traintupleKey}, {'hash': model_hash2, 'traintupleKey': traintupleKey2}]} diff --git a/substrabac/substrapp/tests/views/tests_views.py b/substrabac/substrapp/tests/views/tests_views.py index 1f1def046..ce1d624e1 100644 --- a/substrabac/substrapp/tests/views/tests_views.py +++ b/substrabac/substrapp/tests/views/tests_views.py @@ -3,7 +3,6 @@ from rest_framework.test import APITestCase from substrapp.views.datasample import path_leaf -from substrapp.utils import compute_hash from substrapp.ledger_utils import get_object_from_ledger From b7777855aa3d39b1cb8ce6f6d87b80c162125dc0 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 29 Aug 2019 13:52:05 +0200 Subject: [PATCH 240/457] node to node authentication: fixes after populate tests outgoing node authentication: fix username check correct hash when getting remote asset add salt to compute hash of remote asset content --- substrabac/substrapp/tasks/tasks.py | 17 ++++++++++------- substrabac/substrapp/utils.py | 10 +++------- substrabac/substrapp/views/utils.py | 9 ++++----- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 79222d417..d8759173b 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -28,11 +28,13 @@ def _authenticate_worker(node_id): from node.models import OutgoingNode + owner = get_owner() + # This handle worker node authentication # WARN: This should use a different authentication # Backend (WorkerBackend for example) to be able # to differiciate regural node users from workers - if node_id == get_owner(): + if node_id == owner: auth = HTTPBasicAuth(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) else: try: @@ -40,13 +42,13 @@ def _authenticate_worker(node_id): except OutgoingNode.DoesNotExist: raise NodeError(f'Unauthorized to call node_id: {node_id}') - auth = HTTPBasicAuth(outgoing.node_id, outgoing.secret) + auth = HTTPBasicAuth(owner, outgoing.secret) return auth -def _get_asset_content(url, node_id, content_hash): - return get_remote_file(url, _authenticate_worker(node_id), content_hash) +def _get_asset_content(url, node_id, content_hash, salt=None): + return get_remote_file(url, _authenticate_worker(node_id), content_hash, salt=salt) def get_objective(subtuple): @@ -66,7 +68,7 @@ def get_objective(subtuple): content = _get_asset_content( objective_metadata['metrics']['storageAddress'], objective_metadata['owner'], - objective_hash, + objective_metadata['metrics']['hash'], ) objective, _ = Objective.objects.update_or_create(pkhash=objective_hash, validated=True) @@ -85,7 +87,7 @@ def get_algo(subtuple): algo_content = _get_asset_content( algo_metadata['content']['storageAddress'], algo_metadata['owner'], - algo_hash, + algo_metadata['content']['hash'], ) return algo_content @@ -98,7 +100,8 @@ def _get_model(model): model_content = _get_asset_content( traintuple_metadata['outModel']['storageAddress'], traintuple_metadata['creator'], - traintuple_hash + traintuple_metadata['outModel']['hash'], + salt=traintuple_hash, ) return model_content diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index dd77ada3b..c0374202d 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -185,13 +185,9 @@ def _get_from_node(url, auth): return response -def get_remote_file(url, auth, content_hash): +def get_remote_file(url, auth, content_hash, salt=None): response = _get_from_node(url, auth) - computed_hash = compute_hash(response.content) - + computed_hash = compute_hash(response.content, key=salt) if computed_hash != content_hash: - msg = 'computed hash is not the same as the hosted file.' \ - 'Please investigate for default of synchronization or corruption' - raise Exception(msg) - + raise NodeError(f"url {url}: hash doesn't match {content_hash} vs {computed_hash}") return response.content diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index db2d7ac00..2077b349d 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -4,7 +4,7 @@ from rest_framework.response import Response from substrapp.ledger_utils import get_object_from_ledger, LedgerError -from substrapp.utils import NodeError, get_remote_file +from substrapp.utils import NodeError, get_remote_file, get_owner from node.models import OutgoingNode from django.conf import settings @@ -18,13 +18,12 @@ def authenticate_outgoing_request(node_id): except OutgoingNode.DoesNotExist: raise NodeError(f'Unauthorized to call node_id: {node_id}') - return HTTPBasicAuth(outgoing.node_id, outgoing.secret) + return HTTPBasicAuth(get_owner(), outgoing.secret) -def get_remote_asset(url, node_id, content_hash): +def get_remote_asset(url, node_id, content_hash, salt=None): auth = authenticate_outgoing_request(node_id) - - return get_remote_file(url, auth, content_hash) + return get_remote_file(url, auth, content_hash, salt=salt) class CustomFileResponse(FileResponse): From f78ea197e1d50ea2869e34ae059302f570d4225b Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 30 Aug 2019 16:07:59 +0200 Subject: [PATCH 241/457] fixes after review --- substrabac/substrapp/tasks/tasks.py | 2 +- substrabac/substrapp/tests/views/tests_views_datamanager.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index d8759173b..981fe058e 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -33,7 +33,7 @@ def _authenticate_worker(node_id): # This handle worker node authentication # WARN: This should use a different authentication # Backend (WorkerBackend for example) to be able - # to differiciate regural node users from workers + # to differentiate regular node users from workers if node_id == owner: auth = HTTPBasicAuth(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) else: diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 366afc16c..503abbdf8 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -113,7 +113,7 @@ def test_datamanager_retrieve(self): datamanager_response = [d for d in datamanager if d['key'] == '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca'][0] with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mget_object_from_ledger, \ - mock.patch('substrapp.views.datamanager.get_remote_asset') as get_remote_asset: + mock.patch('substrapp.views.datamanager.get_remote_asset') as mget_remote_asset: mget_object_from_ledger.return_value = datamanager_response with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), @@ -125,7 +125,7 @@ def test_datamanager_retrieve(self): '../../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), 'rb') as f: description_content = f.read() - get_remote_asset.side_effect = [opener_content, description_content] + mget_remote_asset.side_effect = [opener_content, description_content] search_params = '8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/' response = self.client.get(url + search_params, **self.extra) From 513fb806b92bbd0209467781142ba1b268a78b7b Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 30 Aug 2019 16:17:40 +0200 Subject: [PATCH 242/457] remove _get_from_node method --- substrabac/substrapp/utils.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index c0374202d..2dd500457 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -172,7 +172,7 @@ class NodeError(Exception): pass -def _get_from_node(url, auth): +def get_remote_file(url, auth, content_hash, salt=None): try: response = requests.get(url, auth=auth, headers={'Accept': 'application/json;version=0.0'}) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: @@ -182,11 +182,6 @@ def _get_from_node(url, auth): logging.error(response.text) raise NodeError(f'Url: {url} returned status code: {response.status_code}') - return response - - -def get_remote_file(url, auth, content_hash, salt=None): - response = _get_from_node(url, auth) computed_hash = compute_hash(response.content, key=salt) if computed_hash != content_hash: raise NodeError(f"url {url}: hash doesn't match {content_hash} vs {computed_hash}") From e7d9c07b083a0211f4be5c57bf5c8347c814664e Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Mon, 2 Sep 2019 17:38:53 +0200 Subject: [PATCH 243/457] add comment to explain how authenticate_outgoing_request works --- substrabac/substrapp/views/utils.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 2077b349d..ce3da06a1 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -12,13 +12,17 @@ from requests.auth import HTTPBasicAuth -def authenticate_outgoing_request(node_id): +def authenticate_outgoing_request(outgoing_node_id): try: - outgoing = OutgoingNode.objects.get(node_id=node_id) + outgoing = OutgoingNode.objects.get(node_id=outgoing_node_id) except OutgoingNode.DoesNotExist: - raise NodeError(f'Unauthorized to call node_id: {node_id}') + raise NodeError(f'Unauthorized to call remote node with node_id: {outgoing_node_id}') - return HTTPBasicAuth(get_owner(), outgoing.secret) + # to authenticate to remote node we use the current node id + # with the associated outgoing secret. + current_node_id = get_owner() + + return HTTPBasicAuth(current_node_id, outgoing.secret) def get_remote_asset(url, node_id, content_hash, salt=None): From b8033a145edbe1096353aa8a4c3f7e3437d4a189 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Mon, 2 Sep 2019 17:46:11 +0200 Subject: [PATCH 244/457] put back debug option to disable verify --- substrabac/substrapp/utils.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 2dd500457..7c26754e4 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -173,8 +173,16 @@ class NodeError(Exception): def get_remote_file(url, auth, content_hash, salt=None): + kwargs = { + 'headers': {'Accept': 'application/json;version=0.0'}, + 'auth': auth + } + + if settings.DEBUG: + kwargs['verify'] = False + try: - response = requests.get(url, auth=auth, headers={'Accept': 'application/json;version=0.0'}) + response = requests.get(url, **kwargs) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: raise NodeError(f'Failed to fetch {url}') from e else: From 725b4056331a874bc16a5623c08efa09f10c9356 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 4 Sep 2019 13:42:32 +0200 Subject: [PATCH 245/457] add script to generate nodes fixtures --- scripts/generate_nodes_fixtures.py | 72 ++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 scripts/generate_nodes_fixtures.py diff --git a/scripts/generate_nodes_fixtures.py b/scripts/generate_nodes_fixtures.py new file mode 100644 index 000000000..83ff08938 --- /dev/null +++ b/scripts/generate_nodes_fixtures.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +import collections +import json +import os +import secrets +import yaml + + +def create_random_secret(): + return secrets.token_hex(64) + + +def generate_network_credentials(nodes): + node_ids = [node_id for name, node_id in nodes] + network_creds = collections.defaultdict(dict) + + # generate random outgoing credentials for all nodes + for node_name, node_id in nodes: + network_creds[node_id]['name'] = node_name + network_creds[node_id]['outgoing'] = { + other_id: create_random_secret() + for other_id in node_ids if other_id != node_id + } + + # parse outgoing credentials to set incoming credentials + for node_id, node_creds in network_creds.items(): + node_creds['incoming'] = { + other_id: network_creds[other_id]['outgoing'][node_id] + for other_id in node_ids if other_id != node_id + } + + return network_creds + + +def create_fixture(node_credentials): + data = [] + for pk, v in node_credentials['outgoing'].items(): + data.append({ + 'model': 'node.outgoingnode', + 'pk': pk, + 'fields': {'secret': v}, + }) + for pk, v in node_credentials['incoming'].items(): + data.append({ + 'model': 'node.incomingnode', + 'pk': pk, + 'fields': {'secret': v}, + }) + return data + + +if __name__ == '__main__': + node_ids = [ + ('chunantes', 'chu-nantesMSP'), + ('owkin', 'owkinMSP'), + ('clb', 'clbMSP'), + ] + # generate credentials + network_credentials = generate_network_credentials(node_ids) + print(json.dumps(network_credentials, sort_keys=True, indent=4)) + + # create fixture files + fixtures_path = 'substrabac/node/fixtures' + try: + os.makedirs(fixtures_path) + except OSError: + pass + for node_id, node_credentials in network_credentials.items(): + data = create_fixture(node_credentials) + node_name = node_credentials['name'] + with open(os.path.join(fixtures_path, f'nodes-{node_name}.yaml'), 'w') as f: + f.write(yaml.dump(data)) From 04cd21705f30a4ee07a7be7f80a10589c947316f Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 4 Sep 2019 13:44:06 +0200 Subject: [PATCH 246/457] update docker start.py to load fixtures - define admin username and password in populate - add nodes fixtures to set credentials in local dbs --- docker/start.py | 11 ++++++++--- populate.py | 2 +- substrabac/node/fixtures/nodes-chunantes.yaml | 16 ++++++++++++++++ substrabac/node/fixtures/nodes-clb.yaml | 16 ++++++++++++++++ substrabac/node/fixtures/nodes-owkin.yaml | 16 ++++++++++++++++ substrabac/substrabac/settings/common.py | 3 --- substrabac/substrabac/settings/dev.py | 3 +++ substrabac/substrabac/settings/prod.py | 3 +++ 8 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 substrabac/node/fixtures/nodes-chunantes.yaml create mode 100644 substrabac/node/fixtures/nodes-clb.yaml create mode 100644 substrabac/node/fixtures/nodes-owkin.yaml diff --git a/docker/start.py b/docker/start.py index 7f8f1c8e1..21ccfb34f 100644 --- a/docker/start.py +++ b/docker/start.py @@ -145,8 +145,8 @@ def generate_docker_compose_file(conf, launch_settings): f'DJANGO_SETTINGS_MODULE=substrabac.settings.{launch_settings}', # Basic auth - f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', '')}", - f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', '')}", + f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', 'admin')}", + f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', 'admin')}", f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", ] @@ -163,6 +163,11 @@ def generate_docker_compose_file(conf, launch_settings): for tls_key in ['tlsCACerts', 'clientCert', 'clientKey']: hlf_volumes.append(f'{org["peer"][tls_key]}:{org["peer"][tls_key]}:ro') + # load incoming/outgoing node fixtures/ that should not be executed in production env + fixtures_command = '' + if launch_settings == 'dev': + fixtures_command = f"python manage.py loaddata nodes-{org_name_stripped}" + backend = { 'container_name': f'{org_name_stripped}.substrabac', 'labels': ['substra'], @@ -170,7 +175,7 @@ def generate_docker_compose_file(conf, launch_settings): 'restart': 'unless-stopped', 'ports': [f'{port}:{port}'], 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - f'yes | python manage.py migrate; {django_server}"', + f'yes | python manage.py migrate; {fixtures_command}; {django_server}"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), 'volumes': [ diff --git a/populate.py b/populate.py index 4ed46c93e..3cb4ad47c 100644 --- a/populate.py +++ b/populate.py @@ -12,7 +12,7 @@ dir_path = os.path.dirname(os.path.realpath(__file__)) -USER, PASSWORD = ('foo', 'bar') +USER, PASSWORD = ('admin', 'admin') SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') server_path = f'{SUBSTRA_FOLDER}/servermedias' diff --git a/substrabac/node/fixtures/nodes-chunantes.yaml b/substrabac/node/fixtures/nodes-chunantes.yaml new file mode 100644 index 000000000..97626a47f --- /dev/null +++ b/substrabac/node/fixtures/nodes-chunantes.yaml @@ -0,0 +1,16 @@ +- fields: + secret: 22a5fa0c3e8d681fba881f745baad652fc05a04abedd02a202fce47243482d25a752277159689e3b944ee61c4938c3919878aad79dad28a2cedbd949a55d5792 + model: node.outgoingnode + pk: owkinMSP +- fields: + secret: 7f37ca057ce8631ea5cce999697026701f47ffbc9c43fb88f7bf107856615fbeb1dbca6b7a5ae4c4415b0bfd141fa267661eb270a1e79e4a77502cf125ade021 + model: node.outgoingnode + pk: clbMSP +- fields: + secret: 2df765d2aecc51c844dda3017d7b21ff79ffaf68ea11f3273639b462c70e0a5820e96ff15aa2511a539f33ac5cfd5954b7a5087ae4007d2e9837749de77d23dd + model: node.incomingnode + pk: owkinMSP +- fields: + secret: e804ffc806ed55ef546b0a2395b9a2de53ebedf533e84ef68f7a311b9f480213b98d88c22df1a2f0cb2adcd0436ad0dbf86846d936ebb7dd8156e56c06f8116c + model: node.incomingnode + pk: clbMSP diff --git a/substrabac/node/fixtures/nodes-clb.yaml b/substrabac/node/fixtures/nodes-clb.yaml new file mode 100644 index 000000000..60b99d274 --- /dev/null +++ b/substrabac/node/fixtures/nodes-clb.yaml @@ -0,0 +1,16 @@ +- fields: + secret: e804ffc806ed55ef546b0a2395b9a2de53ebedf533e84ef68f7a311b9f480213b98d88c22df1a2f0cb2adcd0436ad0dbf86846d936ebb7dd8156e56c06f8116c + model: node.outgoingnode + pk: chu-nantesMSP +- fields: + secret: fb3cd57a6e7c688a61021388b1ef7b321640e600b0fd187d6faf4ebbd5ac59d9bc8e286f6177e206576435ab1a7fb7a470dfedb2e6152958980e6e17eb783031 + model: node.outgoingnode + pk: owkinMSP +- fields: + secret: 7f37ca057ce8631ea5cce999697026701f47ffbc9c43fb88f7bf107856615fbeb1dbca6b7a5ae4c4415b0bfd141fa267661eb270a1e79e4a77502cf125ade021 + model: node.incomingnode + pk: chu-nantesMSP +- fields: + secret: 3e3e02045cf47fc37c6e0c7d5440fa17889c106a865254a0eeae3ccda60a8f0b90a2de218aa39ed074d71b0a1674cd5bdd0bf74ffc7fc385d8b9c9b63a7675c0 + model: node.incomingnode + pk: owkinMSP diff --git a/substrabac/node/fixtures/nodes-owkin.yaml b/substrabac/node/fixtures/nodes-owkin.yaml new file mode 100644 index 000000000..5578f9790 --- /dev/null +++ b/substrabac/node/fixtures/nodes-owkin.yaml @@ -0,0 +1,16 @@ +- fields: + secret: 2df765d2aecc51c844dda3017d7b21ff79ffaf68ea11f3273639b462c70e0a5820e96ff15aa2511a539f33ac5cfd5954b7a5087ae4007d2e9837749de77d23dd + model: node.outgoingnode + pk: chu-nantesMSP +- fields: + secret: 3e3e02045cf47fc37c6e0c7d5440fa17889c106a865254a0eeae3ccda60a8f0b90a2de218aa39ed074d71b0a1674cd5bdd0bf74ffc7fc385d8b9c9b63a7675c0 + model: node.outgoingnode + pk: clbMSP +- fields: + secret: 22a5fa0c3e8d681fba881f745baad652fc05a04abedd02a202fce47243482d25a752277159689e3b944ee61c4938c3919878aad79dad28a2cedbd949a55d5792 + model: node.incomingnode + pk: chu-nantesMSP +- fields: + secret: fb3cd57a6e7c688a61021388b1ef7b321640e600b0fd187d6faf4ebbd5ac59d9bc8e286f6177e206576435ab1a7fb7a470dfedb2e6152958980e6e17eb783031 + model: node.incomingnode + pk: clbMSP diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index c928c3a67..81ec6b0dd 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -62,9 +62,6 @@ 'node', ] -BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') -BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD') - AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'libs.authentication.SettingsBackend', diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index d2b971bb6..a56cf8d44 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -7,6 +7,9 @@ from .deps.restframework import * +BASICAUTH_USERNAME = "admin" +BASICAUTH_PASSWORD = "admin" + DEBUG = True # Database diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 4737a7199..53322f546 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -10,6 +10,9 @@ DEBUG = False +BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') +BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD') + USE_X_FORWARDED_HOST = True SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') os.environ['HTTPS'] = "on" From e758e8d17ae8047b456250c3bfcb992815aa713a Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 23 Aug 2019 15:11:39 +0200 Subject: [PATCH 247/457] check permissions when downloading data --- substrabac/substrapp/tests/common.py | 20 +++++++++ .../substrapp/tests/query/tests_query_algo.py | 8 ++-- .../tests/query/tests_query_objective.py | 4 +- substrabac/substrapp/views/algo.py | 4 +- substrabac/substrapp/views/datamanager.py | 4 +- substrabac/substrapp/views/objective.py | 4 +- substrabac/substrapp/views/utils.py | 42 +++++++++++++++---- 7 files changed, 67 insertions(+), 19 deletions(-) diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 9e9ab3282..4829e4c3f 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -278,6 +278,26 @@ def get_sample_model(): return model, model_filename +DEFAULT_PERMISSIONS = { + 'process': { + 'public': True, + 'authorizedIDs': [], + } +} + + +def get_sample_algo_metadata(): + return { + 'permissions': DEFAULT_PERMISSIONS, + } + + +def get_sample_objective_metadata(): + return { + 'permissions': DEFAULT_PERMISSIONS, + } + + class FakeContainer(object): def __init__(self): self.c_stats = Stats.get_stats() diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substrabac/substrapp/tests/query/tests_query_algo.py index 56b44a0b0..efb369d17 100644 --- a/substrabac/substrapp/tests/query/tests_query_algo.py +++ b/substrabac/substrapp/tests/query/tests_query_algo.py @@ -16,7 +16,9 @@ from substrapp.ledger_utils import LedgerError from ..common import get_sample_objective, get_sample_datamanager, \ - get_sample_algo, get_sample_algo_zip, AuthenticatedClient + get_sample_algo, get_sample_algo_zip, AuthenticatedClient, \ + get_sample_algo_metadata + MEDIA_ROOT = tempfile.mkdtemp() @@ -216,14 +218,14 @@ def test_get_algo_files(self): algo = Algo.objects.create(file=self.algo) with mock.patch( 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.return_value = self.algo + mget_object_from_ledger.return_value = get_sample_algo_metadata() + extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } response = self.client.get(f'/algo/{algo.pkhash}/file/', **extra) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(algo.pkhash, compute_hash(response.getvalue())) - # self.assertEqual(r, f'http://testserver/media/algos/{algo.pkhash}/{self.algo_filename}') def test_get_algo_files_no_version(self): algo = Algo.objects.create(file=self.algo) diff --git a/substrabac/substrapp/tests/query/tests_query_objective.py b/substrabac/substrapp/tests/query/tests_query_objective.py index f97d99aba..25025356c 100644 --- a/substrabac/substrapp/tests/query/tests_query_objective.py +++ b/substrabac/substrapp/tests/query/tests_query_objective.py @@ -15,7 +15,7 @@ from substrapp.utils import get_hash, compute_hash from ..common import get_sample_objective, get_sample_datamanager, \ - get_temporary_text_file, AuthenticatedClient + get_temporary_text_file, AuthenticatedClient, get_sample_objective_metadata MEDIA_ROOT = tempfile.mkdtemp() @@ -220,7 +220,7 @@ def test_get_objective_metrics(self): with mock.patch( 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: - mget_object_from_ledger.return_value = self.objective_metrics + mget_object_from_ledger.return_value = get_sample_objective_metadata() extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', } diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 4f9f4f172..7e73617e8 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -186,8 +186,8 @@ def list(self, request, *args, **kwargs): @action(detail=True) def file(self, request, *args, **kwargs): - return self.manage_file('file') + return self.download_file(request, 'file') @action(detail=True) def description(self, request, *args, **kwargs): - return self.manage_file('description') + return self.download_file(request, 'description') diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index b5cf3340a..5ee68dfdf 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -269,8 +269,8 @@ def update_ledger(self, request, *args, **kwargs): @action(detail=True) def description(self, request, *args, **kwargs): - return self.manage_file('description') + return self.download_file(request, 'description') @action(detail=True) def opener(self, request, *args, **kwargs): - return self.manage_file('data_opener') + return self.download_file(request, 'data_opener') diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 79e098280..4e156fdef 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -247,11 +247,11 @@ def list(self, request, *args, **kwargs): @action(detail=True) def description(self, request, *args, **kwargs): - return self.manage_file('description') + return self.download_file(request, 'description') @action(detail=True) def metrics(self, request, *args, **kwargs): - return self.manage_file('metrics') + return self.download_file(request, 'metrics') @action(detail=True) def data(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index ce3da06a1..19409754c 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -37,22 +37,48 @@ def set_headers(self, filelike): self['Access-Control-Expose-Headers'] = 'Content-Disposition' +def is_local_user(user): + return user.username == settings.BASICAUTH_USERNAME + + +def has_access(user, asset): + """Returns true if API consumer can access asset data.""" + if user.is_anonymous: # safeguard, should never happened + return False + + if is_local_user(user): + return True + + permission = asset['permissions']['process'] + if permission['public']: + return True + + node_id = user.username + return node_id in permission['authorizedIDs'] + + class ManageFileMixin(object): - def manage_file(self, field): + def download_file(self, request, field): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] - # TODO get cert for permissions check - try: - get_object_from_ledger(pk, self.ledger_query_call) + asset = get_object_from_ledger(pk, self.ledger_query_call) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - else: - obj = self.get_object() - data = getattr(obj, field) - return CustomFileResponse(open(data.path, 'rb'), as_attachment=True, filename=os.path.basename(data.path)) + if not has_access(request.user, asset): + return Response({'message': 'Unauthorized'}, + status=status.HTTP_401_UNAUTHORIZED) + + obj = self.get_object() + data = getattr(obj, field) + response = CustomFileResponse( + open(data.path, 'rb'), + as_attachment=True, + filename=os.path.basename(data.path) + ) + return response def find_primary_key_error(validation_error, key_name='pkhash'): From 15ba0305cf584a52a79b7fdc2522e2ba94cc2363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 28 Aug 2019 10:58:56 +0200 Subject: [PATCH 248/457] leaderboard --- substrabac/substrapp/tests/assets.py | 44 +++++++++++++++++++ .../tests/views/tests_views_objective.py | 11 ++++- substrabac/substrapp/views/objective.py | 11 +++++ 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index d322a2d63..00d3f1583 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -40,6 +40,50 @@ } ] +leaderboard = { + "objective": { + "description": { + "hash": "5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379", + "storageAddress": "https://toto/objective/222/description" + }, + "key": "5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379", + "metrics": { + "hash": "4a1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379", + "name": "accuracy", + "storageAddress": "https://toto/objective/222/metrics" + }, + "name": "MSI classification", + "owner": "ec722969cb64200ab6638f68ac538e40abab5b19a6485661042a1061c4612776", + "permissions": { + "process": { + "authorizedIDs": [], + "public": True + } + }, + "testDataset": { + "dataManagerKey": "da1bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc", + "dataSampleKeys": [ + "bb1bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc", + "bb2bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc" + ], + "worker": "" + }, + }, + "testtuples": [ + { + "algo": { + "hash": "fd1bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc", + "name": "hog + svm", + "storageAddress": "https://toto/algo/222/algo"}, + "perf": 0.5, + "model": { + "hash": "eedbb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482eed", + "storageAddress": "https://substrabac/model/toto", + "traintupleKey": "4ef2002b70fdeb9d91679a98eb74a74edb7db852cd064209807f79d5dfd22cd6"}, + }, + ] +} + datamanager = [ { "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index fcc772bfc..f25a3ae2f 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -20,7 +20,7 @@ from substrapp.utils import compute_hash, get_hash from ..common import get_sample_objective, FakeTask, AuthenticatedClient -from ..assets import objective, datamanager, traintuple, model +from ..assets import objective, datamanager, traintuple, model, leaderboard MEDIA_ROOT = "/tmp/unittests_views/" @@ -300,3 +300,12 @@ def test_objective_compute_dryrun(self): } get_remote_asset.return_value = opener_content objective_compute_dryrun(zip_path, test_data_manager_key, pkhash) + + def test_objective_leaderboard(self): + url = reverse('substrapp:objective-leaderboard', args=[leaderboard['objective']['key']]) + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.return_value = leaderboard + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(list(r.keys()), ['objective', 'testtuples']) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 79e098280..734eeff8d 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -263,6 +263,17 @@ def data(self, request, *args, **kwargs): serializer = self.get_serializer(instance) return Response(serializer.data) + @action(detail=True, methods=['GET']) + def leaderboard(self, request, pk): + validate_pk(pk) + + try: + leaderboard = query_ledger(fcn='getObjectiveLeaderboard', args={'key': pk}) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + + return Response(leaderboard, status=status.HTTP_200_OK) + @app.task(bind=True, ignore_result=False) def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): From c7c97468aaf813f9ef8a1149ac04ffd015957b18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 28 Aug 2019 15:37:28 +0200 Subject: [PATCH 249/457] leaderboard: sort parameter --- .../tests/views/tests_views_objective.py | 24 +++++++++++++++++++ substrabac/substrapp/views/objective.py | 13 ++++++++-- substrabac/substrapp/views/utils.py | 5 ++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index f25a3ae2f..63fbd8212 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -309,3 +309,27 @@ def test_objective_leaderboard(self): response = self.client.get(url, **self.extra) r = response.json() self.assertEqual(list(r.keys()), ['objective', 'testtuples']) + + def test_objective_leaderboard_sort(self): + url = reverse('substrapp:objective-leaderboard', args=[leaderboard['objective']['key']]) + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.return_value = leaderboard + + self.client.get(url, data={'sort': 'desc'}, **self.extra) + mquery_ledger.assert_called_with( + fcn='getObjectiveLeaderboard', + args={ + 'key': leaderboard['objective']['key'], + 'AscendingSort': False, + }) + + self.client.get(url, data={'sort': 'asc'}, **self.extra) + mquery_ledger.assert_called_with( + fcn='getObjectiveLeaderboard', + args={ + 'key': leaderboard['objective']['key'], + 'AscendingSort': True, + }) + + response = self.client.get(url, data={'sort': 'foo'}, **self.extra) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 734eeff8d..7faa965bb 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -25,7 +25,7 @@ from substrapp.utils import get_hash, create_directory, uncompress_path, is_archive from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import ManageFileMixin, find_primary_key_error, validate_pk, \ - get_success_create_code, ValidationException, LedgerException, get_remote_asset + get_success_create_code, ValidationException, LedgerException, get_remote_asset, validate_sort from substrapp.views.filters_utils import filter_list @@ -267,8 +267,17 @@ def data(self, request, *args, **kwargs): def leaderboard(self, request, pk): validate_pk(pk) + sort = request.query_params.get('sort', 'desc') try: - leaderboard = query_ledger(fcn='getObjectiveLeaderboard', args={'key': pk}) + validate_sort(sort) + except Exception as e: + return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) + + try: + leaderboard = query_ledger(fcn='getObjectiveLeaderboard', args={ + 'key': pk, + 'AscendingSort': sort == 'asc', + }) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index ce3da06a1..7ed2f74c0 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -94,6 +94,11 @@ def validate_pk(pk): raise Exception(f'Wrong pk {pk}') +def validate_sort(sort): + if sort not in ['asc', 'desc']: + raise Exception(f"Invalid sort value (must be either 'desc' or 'asc'): {sort}") + + class LedgerException(Exception): def __init__(self, data, st): self.data = data From 232802fdf2e6cb8e24c396d396ea0b465a030b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 2 Sep 2019 17:56:39 +0200 Subject: [PATCH 250/457] update leaderboard query params --- substrabac/substrapp/views/objective.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 7faa965bb..56667646f 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -275,8 +275,8 @@ def leaderboard(self, request, pk): try: leaderboard = query_ledger(fcn='getObjectiveLeaderboard', args={ - 'key': pk, - 'AscendingSort': sort == 'asc', + 'objectiveKey': pk, + 'ascendingSort': sort == 'asc', }) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) From ef0ef5d09ffd93bf2e66aad1d9a960717a3d89da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 2 Sep 2019 18:04:00 +0200 Subject: [PATCH 251/457] remove useless test and fixture --- substrabac/substrapp/tests/assets.py | 44 ------------------- .../tests/views/tests_views_objective.py | 23 +++------- 2 files changed, 7 insertions(+), 60 deletions(-) diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index 00d3f1583..d322a2d63 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -40,50 +40,6 @@ } ] -leaderboard = { - "objective": { - "description": { - "hash": "5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379", - "storageAddress": "https://toto/objective/222/description" - }, - "key": "5c1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379", - "metrics": { - "hash": "4a1d9cd1c2c1082dde0921b56d11030c81f62fbb51932758b58ac2569dd0b379", - "name": "accuracy", - "storageAddress": "https://toto/objective/222/metrics" - }, - "name": "MSI classification", - "owner": "ec722969cb64200ab6638f68ac538e40abab5b19a6485661042a1061c4612776", - "permissions": { - "process": { - "authorizedIDs": [], - "public": True - } - }, - "testDataset": { - "dataManagerKey": "da1bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc", - "dataSampleKeys": [ - "bb1bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc", - "bb2bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc" - ], - "worker": "" - }, - }, - "testtuples": [ - { - "algo": { - "hash": "fd1bb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482dcc", - "name": "hog + svm", - "storageAddress": "https://toto/algo/222/algo"}, - "perf": 0.5, - "model": { - "hash": "eedbb7c31f62244c0f3a761cc168804227115793d01c270021fe3f7935482eed", - "storageAddress": "https://substrabac/model/toto", - "traintupleKey": "4ef2002b70fdeb9d91679a98eb74a74edb7db852cd064209807f79d5dfd22cd6"}, - }, - ] -} - datamanager = [ { "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 63fbd8212..cb89ffd72 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -20,7 +20,7 @@ from substrapp.utils import compute_hash, get_hash from ..common import get_sample_objective, FakeTask, AuthenticatedClient -from ..assets import objective, datamanager, traintuple, model, leaderboard +from ..assets import objective, datamanager, traintuple, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -301,34 +301,25 @@ def test_objective_compute_dryrun(self): get_remote_asset.return_value = opener_content objective_compute_dryrun(zip_path, test_data_manager_key, pkhash) - def test_objective_leaderboard(self): - url = reverse('substrapp:objective-leaderboard', args=[leaderboard['objective']['key']]) - with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.return_value = leaderboard - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(list(r.keys()), ['objective', 'testtuples']) - def test_objective_leaderboard_sort(self): - url = reverse('substrapp:objective-leaderboard', args=[leaderboard['objective']['key']]) + url = reverse('substrapp:objective-leaderboard', args=[objective[0]['key']]) with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.return_value = leaderboard + mquery_ledger.return_value = {} self.client.get(url, data={'sort': 'desc'}, **self.extra) mquery_ledger.assert_called_with( fcn='getObjectiveLeaderboard', args={ - 'key': leaderboard['objective']['key'], - 'AscendingSort': False, + 'objectiveKey': objective[0]['key'], + 'ascendingSort': False, }) self.client.get(url, data={'sort': 'asc'}, **self.extra) mquery_ledger.assert_called_with( fcn='getObjectiveLeaderboard', args={ - 'key': leaderboard['objective']['key'], - 'AscendingSort': True, + 'objectiveKey': objective[0]['key'], + 'ascendingSort': True, }) response = self.client.get(url, data={'sort': 'foo'}, **self.extra) From d8e0a56aa8fc6d39af14f4880c81aab987077b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 4 Sep 2019 09:44:41 +0200 Subject: [PATCH 252/457] update chaincode params for leaderboard --- substrabac/substrapp/tests/views/tests_views_objective.py | 8 ++++---- substrabac/substrapp/views/objective.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index cb89ffd72..666a28ee5 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -308,18 +308,18 @@ def test_objective_leaderboard_sort(self): self.client.get(url, data={'sort': 'desc'}, **self.extra) mquery_ledger.assert_called_with( - fcn='getObjectiveLeaderboard', + fcn='queryObjectiveLeaderboard', args={ 'objectiveKey': objective[0]['key'], - 'ascendingSort': False, + 'ascendingOrder': False, }) self.client.get(url, data={'sort': 'asc'}, **self.extra) mquery_ledger.assert_called_with( - fcn='getObjectiveLeaderboard', + fcn='queryObjectiveLeaderboard', args={ 'objectiveKey': objective[0]['key'], - 'ascendingSort': True, + 'ascendingOrder': True, }) response = self.client.get(url, data={'sort': 'foo'}, **self.extra) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 56667646f..3154af75e 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -274,9 +274,9 @@ def leaderboard(self, request, pk): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) try: - leaderboard = query_ledger(fcn='getObjectiveLeaderboard', args={ + leaderboard = query_ledger(fcn='queryObjectiveLeaderboard', args={ 'objectiveKey': pk, - 'ascendingSort': sort == 'asc', + 'ascendingOrder': sort == 'asc', }) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) From b99b499b75de62394e5889e0443b8f187ac27788 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 26 Jul 2019 11:21:50 +0200 Subject: [PATCH 253/457] Support new chaincode event callback --- substrabac/events/apps.py | 23 ++++------------------- substrabac/requirements.txt | 2 +- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index ef45ce6c6..1f775866c 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -15,7 +15,6 @@ from hfc.fabric.peer import Peer from hfc.fabric.user import create_user from hfc.util.keyvaluestore import FileKeyValueStore -from hfc.protos.peer.transaction_pb2 import TxValidationCode from substrapp.tasks.tasks import prepare_tuple from substrapp.utils import get_owner @@ -37,23 +36,8 @@ def get_event_loop(): loop.close() -def get_block_payload(block): - payload = json.loads( - block['data']['data'][0]['payload']['data']['actions'][0]['payload']['action']['proposal_response_payload'][ - 'extension']['events']['payload']) - return payload - - -def on_tuples(block): - try: - meta = block['metadata']['metadata'][-1] - if isinstance(meta, list): - meta = int(meta.pop()) - tx_validation_code = TxValidationCode.Name(meta) - except Exception: - tx_validation_code = None - - payload = get_block_payload(block) +def on_tuples(cc_event, block_number, tx_id, tx_status): + payload = json.loads(cc_event['payload']) owner = get_owner() worker_queue = f"{LEDGER['name']}.worker" @@ -66,7 +50,7 @@ def on_tuples(block): status = _tuple['status'] logger.info(f'Processing task {key}: type={tuple_type} status={status}' - f' with tx status: {tx_validation_code}') + f' with tx status: {tx_status}') if status != 'todo': continue @@ -139,6 +123,7 @@ def wait(): channel_event_hub.registerChaincodeEvent(chaincode_name, 'tuples-updated', onEvent=on_tuples) + loop.run_until_complete(stream) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index f0fc33fd4..7f5055b30 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -27,4 +27,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -git+git://github.com/hyperledger/fabric-sdk-py.git@4d41aef84785ab790471db4ad9226b19294a27e7 # fabric-sdk-py==0.8.0 +git+git://github.com/hyperledger/fabric-sdk-py.git@7772adca1c4e2a1cda1c596d9c23fdec9b4dc799 # fabric-sdk-py==0.8.1 From f7e3620b631f00b5bae10f718200d63da4344f0c Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 5 Sep 2019 19:31:40 +0200 Subject: [PATCH 254/457] fixes to handle permissions --- populate.py | 16 ++++++++-------- substrabac/substrapp/ledger_utils.py | 3 --- .../serializers/ledger/algo/serializer.py | 8 ++++++-- .../serializers/ledger/datamanager/serializer.py | 8 ++++++-- .../serializers/ledger/objective/serializer.py | 8 ++++++-- substrabac/substrapp/serializers/ledger/utils.py | 6 ++++++ substrabac/substrapp/views/algo.py | 8 +++++++- substrabac/substrapp/views/datamanager.py | 8 +++++++- substrabac/substrapp/views/objective.py | 8 +++++++- 9 files changed, 53 insertions(+), 20 deletions(-) diff --git a/populate.py b/populate.py index 3cb4ad47c..20681a196 100644 --- a/populate.py +++ b/populate.py @@ -142,7 +142,7 @@ def do_populate(): 'data_opener': os.path.join(dir_path, './fixtures/chunantes/datamanagers/datamanager0/opener.py'), 'type': 'Images', 'description': os.path.join(dir_path, './fixtures/chunantes/datamanagers/datamanager0/description.md'), - 'permissions': 'all', + 'permissions': {'public': True, 'authorized_ids': []}, } data_manager_org1_key = get_or_create(data, org_1, 'dataset', dryrun=True) @@ -186,7 +186,7 @@ def do_populate(): 'data_opener': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/opener.py'), 'type': 'Images', 'description': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/description.md'), - 'permissions': 'all' + 'permissions': {'public': True, 'authorized_ids': []}, } data_manager_org0_key = get_or_create(data, org_0, 'dataset') @@ -196,7 +196,7 @@ def do_populate(): 'data_opener': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/opener.py'), 'type': 'Images', 'description': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/description.md'), - 'permissions': 'all' + 'permissions': {'public': True, 'authorized_ids': []}, } get_or_create(data, org_1, 'dataset') @@ -253,7 +253,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/chunantes/objectives/objective0/description.md'), 'metrics_name': 'macro-average recall', 'metrics': zip_path, - 'permissions': 'all', + 'permissions': {'public': True, 'authorized_ids': []}, 'test_data_sample_keys': test_data_sample_keys, 'test_data_manager_key': data_manager_org0_key } @@ -273,7 +273,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/owkin/objectives/objective0/description.md'), 'metrics_name': 'macro-average recall', 'metrics': zip_path, - 'permissions': 'all' + 'permissions': {'public': True, 'authorized_ids': []}, } get_or_create(data, org_0, 'objective', dryrun=True) @@ -295,7 +295,7 @@ def do_populate(): 'name': 'Logistic regression', 'file': os.path.join(dir_path, './fixtures/chunantes/algos/algo3/algo.tar.gz'), 'description': os.path.join(dir_path, './fixtures/chunantes/algos/algo3/description.md'), - 'permissions': 'all', + 'permissions': {'public': True, 'authorized_ids': []}, } algo_key = get_or_create(data, org_2, 'algo') @@ -306,7 +306,7 @@ def do_populate(): 'name': 'Neural Network', 'file': os.path.join(dir_path, './fixtures/chunantes/algos/algo0/algo.tar.gz'), 'description': os.path.join(dir_path, './fixtures/chunantes/algos/algo0/description.md'), - 'permissions': 'all', + 'permissions': {'public': True, 'authorized_ids': []}, } algo_key_2 = get_or_create(data, org_1, 'algo') @@ -316,7 +316,7 @@ def do_populate(): 'name': 'Random Forest', 'file': os.path.join(dir_path, './fixtures/chunantes/algos/algo4/algo.tar.gz'), 'description': os.path.join(dir_path, './fixtures/chunantes/algos/algo4/description.md'), - 'permissions': 'all', + 'permissions': {'public': True, 'authorized_ids': []}, } algo_key_3 = get_or_create(data, org_1, 'algo') diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 960e4cd28..0bf55376c 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -181,9 +181,6 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): status_code = response['status'] exception_class = STATUS_TO_EXCEPTION.get(status_code, LedgerBadResponse) raise exception_class.from_response(response) - # Check permissions - if response and 'permissions' in response and response['permissions'] != 'all': - raise LedgerForbidden('Not allowed') return response diff --git a/substrabac/substrapp/serializers/ledger/algo/serializer.py b/substrabac/substrapp/serializers/ledger/algo/serializer.py index dcec28214..78365f26e 100644 --- a/substrabac/substrapp/serializers/ledger/algo/serializer.py +++ b/substrabac/substrapp/serializers/ledger/algo/serializer.py @@ -4,13 +4,14 @@ from rest_framework.reverse import reverse from substrapp.utils import get_hash +from substrapp.serializers.ledger.utils import PermissionsSerializer from .util import createLedgerAlgo from .tasks import createLedgerAlgoAsync class LedgerAlgoSerializer(serializers.Serializer): name = serializers.CharField(min_length=1, max_length=100) - permissions = serializers.CharField(min_length=1, max_length=60) + permissions = PermissionsSerializer() def create(self, validated_data): instance = self.initial_data.get('instance') @@ -32,7 +33,10 @@ def create(self, validated_data): 'storageAddress': protocol + host + reverse('substrapp:algo-file', args=[instance.pk]), 'descriptionHash': get_hash(instance.description), 'descriptionStorageAddress': protocol + host + reverse('substrapp:algo-description', args=[instance.pk]), - 'permissions': permissions + 'permissions': {'process': { + 'public': permissions.get('public'), + 'authorizedIDs': permissions.get('authorized_ids'), + }} } if getattr(settings, 'LEDGER_SYNC_ENABLED'): diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py index 6969e662b..3d9f87beb 100644 --- a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py +++ b/substrabac/substrapp/serializers/ledger/datamanager/serializer.py @@ -4,6 +4,7 @@ from rest_framework.reverse import reverse from substrapp.utils import get_hash +from substrapp.serializers.ledger.utils import PermissionsSerializer from .util import createLedgerDataManager from .tasks import createLedgerDataManagerAsync @@ -12,7 +13,7 @@ class LedgerDataManagerSerializer(serializers.Serializer): name = serializers.CharField(max_length=100) type = serializers.CharField(max_length=30) objective_key = serializers.CharField(max_length=256, allow_blank=True, required=False) - permissions = serializers.CharField(min_length=1, max_length=60) + permissions = PermissionsSerializer() def create(self, validated_data): instance = self.initial_data.get('instance') @@ -39,7 +40,10 @@ def create(self, validated_data): 'descriptionStorageAddress': protocol + host + reverse('substrapp:data_manager-description', args=[instance.pk]), 'objectiveKey': objective_key, - 'permissions': permissions + 'permissions': {'process': { + 'public': permissions.get('public'), + 'authorizedIDs': permissions.get('authorized_ids'), + }} } if getattr(settings, 'LEDGER_SYNC_ENABLED'): diff --git a/substrabac/substrapp/serializers/ledger/objective/serializer.py b/substrabac/substrapp/serializers/ledger/objective/serializer.py index 08f616bd4..f21862456 100644 --- a/substrabac/substrapp/serializers/ledger/objective/serializer.py +++ b/substrabac/substrapp/serializers/ledger/objective/serializer.py @@ -4,6 +4,7 @@ from rest_framework.reverse import reverse from substrapp.utils import get_hash +from substrapp.serializers.ledger.utils import PermissionsSerializer from .util import createLedgerObjective from .tasks import createLedgerObjectiveAsync @@ -14,7 +15,7 @@ class LedgerObjectiveSerializer(serializers.Serializer): required=False) name = serializers.CharField(min_length=1, max_length=100) test_data_manager_key = serializers.CharField(max_length=256, allow_blank=True, required=False) - permissions = serializers.CharField(min_length=1, max_length=60) + permissions = PermissionsSerializer() metrics_name = serializers.CharField(min_length=1, max_length=100) def create(self, validated_data): @@ -45,7 +46,10 @@ def create(self, validated_data): 'dataManagerKey': test_data_manager_key, 'dataSampleKeys': test_data_sample_keys, }, - 'permissions': permissions + 'permissions': {'process': { + 'public': permissions.get('public'), + 'authorizedIDs': permissions.get('authorized_ids'), + }} } if getattr(settings, 'LEDGER_SYNC_ENABLED'): diff --git a/substrabac/substrapp/serializers/ledger/utils.py b/substrabac/substrapp/serializers/ledger/utils.py index 32b93920e..28b2e96a9 100644 --- a/substrabac/substrapp/serializers/ledger/utils.py +++ b/substrabac/substrapp/serializers/ledger/utils.py @@ -1,7 +1,13 @@ +from rest_framework import serializers from django.core.exceptions import ObjectDoesNotExist from substrapp.ledger_utils import invoke_ledger, LedgerError, LedgerTimeout +class PermissionsSerializer(serializers.Serializer): + public = serializers.BooleanField() + authorized_ids = serializers.ListField(child=serializers.CharField()) + + def create_ledger_asset(model, fcn, args, pkhash, sync=False): try: instance = model.objects.get(pk=pkhash) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 7e73617e8..ae5fb0af5 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -36,7 +36,13 @@ def commit(self, serializer, request): ledger_data = { 'name': request.data.get('name'), - 'permissions': request.data.get('permissions', 'all'), + # XXX workaround because input is a QueryDict and not a JSON object. This + # is due to the fact that we are sending file object and body in a + # single HTTP request + 'permissions': { + 'public': request.data.get('permissions_public'), + 'authorized_ids': request.data.get('permissions_authorized_ids', []), + }, } # init ledger serializer diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 5ee68dfdf..5ff9d3386 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -55,7 +55,13 @@ def commit(self, serializer, request): # create on ledger + db ledger_data = { 'name': request.data.get('name'), - 'permissions': request.data.get('permissions'), + # XXX workaround because input is a QueryDict and not a JSON object. This + # is due to the fact that we are sending file object and body in a + # single HTTP request + 'permissions': { + 'public': request.data.get('permissions_public'), + 'authorized_ids': request.data.get('permissions_authorized_ids', []), + }, 'type': request.data.get('type'), 'objective_keys': request.data.getlist('objective_keys'), } diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 4e156fdef..a5131bd40 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -84,7 +84,13 @@ def commit(self, serializer, request): 'test_data_sample_keys': request.data.getlist('test_data_sample_keys', []), 'test_data_manager_key': request.data.get('test_data_manager_key', ''), 'name': request.data.get('name'), - 'permissions': request.data.get('permissions'), + # XXX workaround because input is a QueryDict and not a JSON object. This + # is due to the fact that we are sending file object and body in a + # single HTTP request + 'permissions': { + 'public': request.data.get('permissions_public'), + 'authorized_ids': request.data.get('permissions_authorized_ids', []), + }, 'metrics_name': request.data.get('metrics_name'), } ledger_data.update({'instance': instance}) From 8e8344d81acda32792ece5e6765e2fa177f81996 Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 6 Sep 2019 09:46:51 +0200 Subject: [PATCH 255/457] fix tests --- .../substrapp/tests/query/tests_query_algo.py | 18 ++++++++++++------ .../tests/query/tests_query_datamanager.py | 3 ++- .../tests/query/tests_query_objective.py | 3 ++- .../substrapp/tests/views/tests_views_algo.py | 3 ++- .../tests/views/tests_views_datamanager.py | 3 ++- .../tests/views/tests_views_objective.py | 6 ++++-- 6 files changed, 24 insertions(+), 12 deletions(-) diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substrabac/substrapp/tests/query/tests_query_algo.py index efb369d17..7580112ea 100644 --- a/substrabac/substrapp/tests/query/tests_query_algo.py +++ b/substrabac/substrapp/tests/query/tests_query_algo.py @@ -57,7 +57,8 @@ def get_default_algo_data(self): 'description': self.data_description, # fake it 'name': 'super top algo', 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' + 'permissions_public': True, + 'permissions_authorized_ids': [], } return expected_hash, data @@ -70,7 +71,8 @@ def get_default_algo_data_zip(self): 'description': self.data_description, # fake it 'name': 'super top algo', 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' + 'permissions_public': True, + 'permissions_authorized_ids': [], } return expected_hash, data @@ -138,7 +140,8 @@ def test_add_algo_ko(self): 'description': self.data_description, 'name': 'super top algo', 'objective_key': 'non existing objectivexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - 'permissions': 'all' + 'permissions_public': True, + 'permissions_authorized_ids': [], } extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', @@ -159,7 +162,8 @@ def test_add_algo_ko(self): data = { 'name': 'super top algo', 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' + 'permissions_public': True, + 'permissions_authorized_ids': [], } response = self.client.post(url, data, format='multipart', **extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -184,7 +188,8 @@ def test_add_algo_no_version(self): 'description': self.data_description, 'name': 'super top algo', 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' + 'permissions_public': True, + 'permissions_authorized_ids': [], } response = self.client.post(url, data, format='multipart') r = response.json() @@ -203,7 +208,8 @@ def test_add_algo_wrong_version(self): 'description': self.data_description, 'name': 'super top algo', 'objective_key': get_hash(self.objective_description), - 'permissions': 'all' + 'permissions_public': True, + 'permissions_authorized_ids': [], } extra = { 'HTTP_ACCEPT': 'application/json;version=-1.0', diff --git a/substrabac/substrapp/tests/query/tests_query_datamanager.py b/substrabac/substrapp/tests/query/tests_query_datamanager.py index 4a5c883de..1282eab31 100644 --- a/substrabac/substrapp/tests/query/tests_query_datamanager.py +++ b/substrabac/substrapp/tests/query/tests_query_datamanager.py @@ -39,7 +39,8 @@ def get_default_datamanager_data(self): data = { 'name': 'slide opener', 'type': 'images', - 'permissions': 'all', + 'permissions_public': True, + 'permissions_authorized_ids': [], 'objective_key': '', 'description': self.data_description, 'data_opener': self.data_data_opener diff --git a/substrabac/substrapp/tests/query/tests_query_objective.py b/substrabac/substrapp/tests/query/tests_query_objective.py index 25025356c..f513a1555 100644 --- a/substrabac/substrapp/tests/query/tests_query_objective.py +++ b/substrabac/substrapp/tests/query/tests_query_objective.py @@ -60,7 +60,8 @@ def get_default_objective_data(self): 'test_data_sample_keys': self.test_data_sample_keys, 'description': self.objective_description, 'metrics': self.objective_metrics, - 'permissions': 'all', + 'permissions_public': True, + 'permissions_authorized_ids': [], 'metrics_name': 'accuracy' } return expected_hash, data diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index 7fa4526de..04fbb0602 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -195,7 +195,8 @@ def test_algo_create(self): 'description': open(description_path, 'rb'), 'objective_key': get_hash(os.path.join( dir_path, '../../../../fixtures/chunantes/objectives/objective0/description.md')), - 'permissions': 'all'} + 'permissions_public': True, + 'permissions_authorized_ids': []} with mock.patch.object(LedgerAlgoSerializer, 'create') as mcreate: diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 503abbdf8..a943d5e06 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -173,7 +173,8 @@ def test_datamanager_create_dryrun(self): data = { 'name': 'ISIC 2018', 'type': 'Images', - 'permissions': 'all', + 'permissions_public': True, + 'permissions_authorized_ids': [], 'dryrun': True } diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index fcc772bfc..ae608c264 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -211,7 +211,8 @@ def test_objective_create(self): 'description': open(description_path, 'rb'), 'metrics_name': 'macro-average recall', 'metrics': open(metrics_path, 'rb'), - 'permissions': 'all', + 'permissions_public': True, + 'permissions_authorized_ids': [], 'test_data_sample_keys': self.test_data_sample_keys, 'test_data_manager_key': test_data_manager_key } @@ -250,7 +251,8 @@ def test_objective_create_dryrun(self): 'description': open(description_path, 'rb'), 'metrics_name': 'macro-average recall', 'metrics': open(metrics_path, 'rb'), - 'permissions': 'all', + 'permissions_public': True, + 'permissions_authorized_ids': [], 'test_data_sample_keys': self.test_data_sample_keys, 'test_data_manager_key': test_data_manager_key, 'dryrun': True From 0dec8b3166672c88a5f920c73dd8b0aac5d9af8e Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 6 Sep 2019 10:50:14 +0200 Subject: [PATCH 256/457] fix dry run --- substrabac/substrapp/tasks/tasks.py | 37 +++---------------- substrabac/substrapp/tasks/utils.py | 29 +++++++++++++++ substrabac/substrapp/tests/tests_tasks.py | 16 ++++---- .../tests/views/tests_views_objective.py | 4 +- substrabac/substrapp/views/objective.py | 3 +- 5 files changed, 46 insertions(+), 43 deletions(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 981fe058e..e79a892c8 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -15,42 +15,15 @@ from rest_framework.reverse import reverse from celery.result import AsyncResult from celery.exceptions import Ignore -from requests.auth import HTTPBasicAuth from substrabac.celery import app -from substrapp.utils import get_hash, get_owner, create_directory, get_remote_file, uncompress_content, NodeError +from substrapp.utils import get_hash, get_owner, create_directory, uncompress_content from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, query_tuples, LedgerError, LedgerStatusError, get_object_from_ledger) -from substrapp.tasks.utils import ResourcesManager, compute_docker +from substrapp.tasks.utils import ResourcesManager, compute_docker, get_asset_content from substrapp.tasks.exception_handler import compute_error_code -def _authenticate_worker(node_id): - from node.models import OutgoingNode - - owner = get_owner() - - # This handle worker node authentication - # WARN: This should use a different authentication - # Backend (WorkerBackend for example) to be able - # to differentiate regular node users from workers - if node_id == owner: - auth = HTTPBasicAuth(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) - else: - try: - outgoing = OutgoingNode.objects.get(node_id=node_id) - except OutgoingNode.DoesNotExist: - raise NodeError(f'Unauthorized to call node_id: {node_id}') - - auth = HTTPBasicAuth(owner, outgoing.secret) - - return auth - - -def _get_asset_content(url, node_id, content_hash, salt=None): - return get_remote_file(url, _authenticate_worker(node_id), content_hash, salt=salt) - - def get_objective(subtuple): from substrapp.models import Objective @@ -65,7 +38,7 @@ def get_objective(subtuple): if objective is None or not objective.metrics: objective_metadata = get_object_from_ledger(objective_hash, 'queryObjective') - content = _get_asset_content( + content = get_asset_content( objective_metadata['metrics']['storageAddress'], objective_metadata['owner'], objective_metadata['metrics']['hash'], @@ -84,7 +57,7 @@ def get_algo(subtuple): algo_hash = subtuple['algo']['hash'] algo_metadata = get_object_from_ledger(algo_hash, 'queryAlgo') - algo_content = _get_asset_content( + algo_content = get_asset_content( algo_metadata['content']['storageAddress'], algo_metadata['owner'], algo_metadata['content']['hash'], @@ -97,7 +70,7 @@ def _get_model(model): traintuple_hash = model['traintupleKey'] traintuple_metadata = get_object_from_ledger(traintuple_hash, 'queryTraintuple') - model_content = _get_asset_content( + model_content = get_asset_content( traintuple_metadata['outModel']['storageAddress'], traintuple_metadata['creator'], traintuple_metadata['outModel']['hash'], diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index 86a420b2f..620baa226 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -8,12 +8,41 @@ from subprocess import check_output from django.conf import settings +from requests.auth import HTTPBasicAuth +from substrapp.utils import get_owner, get_remote_file, NodeError + DOCKER_LABEL = 'substra_task' logger = logging.getLogger(__name__) +def authenticate_worker(node_id): + from node.models import OutgoingNode + + owner = get_owner() + + # This handle worker node authentication + # WARN: This should use a different authentication + # Backend (WorkerBackend for example) to be able + # to differentiate regular node users from workers + if node_id == owner: + auth = HTTPBasicAuth(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) + else: + try: + outgoing = OutgoingNode.objects.get(node_id=node_id) + except OutgoingNode.DoesNotExist: + raise NodeError(f'Unauthorized to call node_id: {node_id}') + + auth = HTTPBasicAuth(owner, outgoing.secret) + + return auth + + +def get_asset_content(url, node_id, content_hash, salt=None): + return get_remote_file(url, authenticate_worker(node_id), content_hash, salt=salt) + + def get_cpu_sets(cpu_count, concurrency): cpu_step = max(1, cpu_count // concurrency) cpu_sets = [] diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 60c39b095..00348ffe5 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -402,8 +402,8 @@ def test_get_model(self): model_type = 'model' subtuple = {model_type: {'hash': model_hash, 'traintupleKey': traintupleKey}} - with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ - mock.patch('substrapp.tasks.tasks.get_owner') as get_owner,\ + with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file, \ + mock.patch('substrapp.tasks.utils.get_owner') as get_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: mget_remote_file.return_value = model_content get_owner.return_value = assets.traintuple[1]['creator'] @@ -428,8 +428,8 @@ def test_get_models(self): subtuple = {model_type: [{'hash': model_hash, 'traintupleKey': traintupleKey}, {'hash': model_hash2, 'traintupleKey': traintupleKey2}]} - with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ - mock.patch('substrapp.tasks.tasks._authenticate_worker'),\ + with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file, \ + mock.patch('substrapp.tasks.utils.authenticate_worker'),\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger'): mget_remote_file.side_effect = (models_content[0], models_content[1]) models_content_res = get_models(subtuple) @@ -449,8 +449,8 @@ def test_get_algo(self): } } - with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file,\ - mock.patch('substrapp.tasks.tasks.get_owner') as get_owner,\ + with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file,\ + mock.patch('substrapp.tasks.utils.get_owner') as get_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: mget_remote_file.return_value = algo_content get_owner.return_value = assets.algo[0]['owner'] @@ -472,9 +472,9 @@ def test_get_objective(self): self.assertTrue(isinstance(objective, bytes)) self.assertEqual(objective, b'foo') - with mock.patch('substrapp.tasks.tasks.get_remote_file') as mget_remote_file, \ + with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file, \ mock.patch('substrapp.tasks.tasks.get_object_from_ledger'), \ - mock.patch('substrapp.tasks.tasks._authenticate_worker'),\ + mock.patch('substrapp.tasks.utils.authenticate_worker'),\ mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: mget.return_value = FakeObjective() diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index fcc772bfc..14b41c536 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -290,7 +290,7 @@ def test_objective_compute_dryrun(self): test_data_manager_key = compute_hash(opener_content) with mock.patch('substrapp.views.objective.get_object_from_ledger') as mdatamanager,\ - mock.patch('substrapp.views.objective.get_remote_asset') as get_remote_asset: + mock.patch('substrapp.views.objective.get_asset_content') as mget_asset_content: mdatamanager.return_value = { 'opener': { 'storageAddress': 'test', @@ -298,5 +298,5 @@ def test_objective_compute_dryrun(self): }, 'owner': 'external_node_id' } - get_remote_asset.return_value = opener_content + mget_asset_content.return_value = opener_content objective_compute_dryrun(zip_path, test_data_manager_key, pkhash) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 79e098280..eee4ec11b 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -24,6 +24,7 @@ from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.utils import get_hash, create_directory, uncompress_path, is_archive from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials +from substrapp.tasks.utils import get_asset_content from substrapp.views.utils import ManageFileMixin, find_primary_key_error, validate_pk, \ get_success_create_code, ValidationException, LedgerException, get_remote_asset from substrapp.views.filters_utils import filter_list @@ -278,7 +279,7 @@ def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): os.remove(archive_path) datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') - opener_content = get_remote_asset( + opener_content = get_asset_content( datamanager['opener']['storageAddress'], datamanager['owner'], datamanager['opener']['hash'], From e8d173ef4de71f77ed8dc6ec9b13a5a10271d350 Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 6 Sep 2019 11:59:43 +0200 Subject: [PATCH 257/457] populate: define default permissions in global variable --- populate.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/populate.py b/populate.py index 20681a196..5e35c56a3 100644 --- a/populate.py +++ b/populate.py @@ -19,6 +19,9 @@ client = substra.Client() +PUBLIC_PERMISSIONS = {'public': True, 'authorized_ids': []} + + def setup_config(network='docker'): print('Init config in /tmp/.substrabac for owkin and chunantes') if network == 'docker': @@ -142,7 +145,7 @@ def do_populate(): 'data_opener': os.path.join(dir_path, './fixtures/chunantes/datamanagers/datamanager0/opener.py'), 'type': 'Images', 'description': os.path.join(dir_path, './fixtures/chunantes/datamanagers/datamanager0/description.md'), - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': PUBLIC_PERMISSIONS, } data_manager_org1_key = get_or_create(data, org_1, 'dataset', dryrun=True) @@ -186,7 +189,7 @@ def do_populate(): 'data_opener': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/opener.py'), 'type': 'Images', 'description': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/description.md'), - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': PUBLIC_PERMISSIONS, } data_manager_org0_key = get_or_create(data, org_0, 'dataset') @@ -196,7 +199,7 @@ def do_populate(): 'data_opener': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/opener.py'), 'type': 'Images', 'description': os.path.join(dir_path, './fixtures/owkin/datamanagers/datamanager0/description.md'), - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': PUBLIC_PERMISSIONS, } get_or_create(data, org_1, 'dataset') @@ -253,7 +256,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/chunantes/objectives/objective0/description.md'), 'metrics_name': 'macro-average recall', 'metrics': zip_path, - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': PUBLIC_PERMISSIONS, 'test_data_sample_keys': test_data_sample_keys, 'test_data_manager_key': data_manager_org0_key } @@ -273,7 +276,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/owkin/objectives/objective0/description.md'), 'metrics_name': 'macro-average recall', 'metrics': zip_path, - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': PUBLIC_PERMISSIONS, } get_or_create(data, org_0, 'objective', dryrun=True) @@ -295,7 +298,7 @@ def do_populate(): 'name': 'Logistic regression', 'file': os.path.join(dir_path, './fixtures/chunantes/algos/algo3/algo.tar.gz'), 'description': os.path.join(dir_path, './fixtures/chunantes/algos/algo3/description.md'), - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': PUBLIC_PERMISSIONS, } algo_key = get_or_create(data, org_2, 'algo') @@ -306,7 +309,7 @@ def do_populate(): 'name': 'Neural Network', 'file': os.path.join(dir_path, './fixtures/chunantes/algos/algo0/algo.tar.gz'), 'description': os.path.join(dir_path, './fixtures/chunantes/algos/algo0/description.md'), - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': PUBLIC_PERMISSIONS, } algo_key_2 = get_or_create(data, org_1, 'algo') @@ -316,7 +319,7 @@ def do_populate(): 'name': 'Random Forest', 'file': os.path.join(dir_path, './fixtures/chunantes/algos/algo4/algo.tar.gz'), 'description': os.path.join(dir_path, './fixtures/chunantes/algos/algo4/description.md'), - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': PUBLIC_PERMISSIONS, } algo_key_3 = get_or_create(data, org_1, 'algo') From 5dfe1cd691865367991dd5935d0e63b1f9d16ddf Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 6 Sep 2019 15:12:57 +0200 Subject: [PATCH 258/457] Add docker run parameters --- substrabac/substrapp/tasks/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index 620baa226..e53335c63 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -245,7 +245,11 @@ def compute_docker(client, resources_manager, dockerfile_path, image_name, conta 'labels': [DOCKER_LABEL], 'detach': False, 'auto_remove': False, - 'remove': False} + 'remove': False, + 'network_disabled': True, + 'network_mode': 'none', + 'privileged': False, + 'cap_drop': ['ALL']} if gpu_set is not None: task_args['environment'] = {'NVIDIA_VISIBLE_DEVICES': gpu_set} From ad1733122b4945c0bf6a2bb0092ab0415d408170 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 5 Sep 2019 15:57:43 +0200 Subject: [PATCH 259/457] Fix archive checker --- substrabac/substrapp/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 7c26754e4..0152addfa 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -15,7 +15,7 @@ from checksumdir import dirhash from django.conf import settings -from django.core.files.uploadedfile import InMemoryUploadedFile +from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile from rest_framework import status @@ -157,6 +157,10 @@ def is_archive(archive_content): if isinstance(archive_content, InMemoryUploadedFile): archive_content = archive_content.file.read() + + if isinstance(archive_content, TemporaryUploadedFile): + archive_content = archive_content.file.read() + if zipfile.is_zipfile(io.BytesIO(archive_content)): return True else: From 31459160f33186c06d3aea64302e614e3481db1d Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 5 Sep 2019 16:16:11 +0200 Subject: [PATCH 260/457] Send directly bytes --- substrabac/substrapp/utils.py | 7 ------- substrabac/substrapp/views/algo.py | 2 +- substrabac/substrapp/views/objective.py | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 0152addfa..24f1a4bdb 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -15,7 +15,6 @@ from checksumdir import dirhash from django.conf import settings -from django.core.files.uploadedfile import InMemoryUploadedFile, TemporaryUploadedFile from rest_framework import status @@ -155,12 +154,6 @@ def uncompress_content(archive_content, to_directory): def is_archive(archive_content): - if isinstance(archive_content, InMemoryUploadedFile): - archive_content = archive_content.file.read() - - if isinstance(archive_content, TemporaryUploadedFile): - archive_content = archive_content.file.read() - if zipfile.is_zipfile(io.BytesIO(archive_content)): return True else: diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 4f9f4f172..5e7412679 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -70,7 +70,7 @@ def commit(self, serializer, request): def _create(self, request, file): - if not is_archive(file): + if not is_archive(file.file.read()): raise Exception('Archive must be zip or tar.*') pkhash = get_hash(file) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index e91edfdcc..d260640ca 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -122,7 +122,7 @@ def _create(self, request, dryrun): description = request.data.get('description') test_data_manager_key = request.data.get('test_data_manager_key', '') - if not is_archive(metrics): + if not is_archive(metrics.file.read()): raise Exception('Archive must be zip or tar.*') pkhash = get_hash(description) From a13ca4f9a9869849b544dcfc7494bbf163fd5eff Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 6 Sep 2019 15:35:03 +0200 Subject: [PATCH 261/457] Put archive check in serializer --- substrabac/substrapp/serializers/objective.py | 52 +++++++++++++++++++ substrabac/substrapp/utils.py | 13 ----- substrabac/substrapp/views/algo.py | 5 +- substrabac/substrapp/views/objective.py | 5 +- 4 files changed, 54 insertions(+), 21 deletions(-) diff --git a/substrabac/substrapp/serializers/objective.py b/substrabac/substrapp/serializers/objective.py index ca6c49263..939282e38 100644 --- a/substrabac/substrapp/serializers/objective.py +++ b/substrabac/substrapp/serializers/objective.py @@ -1,8 +1,60 @@ +import tarfile +import zipfile + +from django.core.exceptions import ValidationError +from rest_framework import serializers + from libs.serializers import DynamicFieldsModelSerializer from substrapp.models import Objective +from django.utils.deconstruct import deconstructible + + +@deconstructible +class FileValidator(object): + error_messages = { + 'open': ("Cannot handle this file object."), + 'compressed': ("Ensure this file is an archive (zip or tar.* compressed file)."), + 'docker': ("Ensure your archive contains a Dockerfile."), + 'file': ("Ensure your archive contains at least one metrics file (for instance metrics.py)."), + } + + def validate_archive(self, files): + if 'Dockerfile' not in files: + raise ValidationError(self.error_messages['docker']) + + if len(files) < 2: + raise ValidationError(self.error_messages['file']) + + def __call__(self, data): + + archive = None + try: + data.file.seek(0) + except Exception: + raise ValidationError(self.error_messages['open']) + else: + try: + # is tarfile? + archive = tarfile.open(fileobj=data.file) + except tarfile.TarError: + # is zipfile? + if not zipfile.is_zipfile(data.file): + raise ValidationError(self.error_messages['compressed']) + + archive = zipfile.ZipFile(file=data.file) + self.validate_archive(archive.namelist()) + else: + self.validate_archive([x.name for x in archive.getmembers()]) + finally: + if archive: + archive.close() + else: + raise ValidationError(self.error_messages['open']) + class ObjectiveSerializer(DynamicFieldsModelSerializer): + metrics = serializers.FileField(validators=[FileValidator()]) class Meta: model = Objective diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index 24f1a4bdb..a374cd454 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -152,19 +152,6 @@ def uncompress_content(archive_content, to_directory): raise Exception('Archive must be zip or tar.*') -def is_archive(archive_content): - - if zipfile.is_zipfile(io.BytesIO(archive_content)): - return True - else: - try: - tar = tarfile.open(fileobj=io.BytesIO(archive_content)) - tar.close() - return True - except tarfile.TarError: - return False - - class NodeError(Exception): pass diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 5e7412679..abb263414 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -10,7 +10,7 @@ from substrapp.models import Algo from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer -from substrapp.utils import get_hash, is_archive +from substrapp.utils import get_hash from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (ManageFileMixin, find_primary_key_error, validate_pk, get_success_create_code, LedgerException, ValidationException, @@ -70,9 +70,6 @@ def commit(self, serializer, request): def _create(self, request, file): - if not is_archive(file.file.read()): - raise Exception('Archive must be zip or tar.*') - pkhash = get_hash(file) serializer = self.get_serializer(data={ 'pkhash': pkhash, diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index d260640ca..48ec36f60 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -22,7 +22,7 @@ from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.utils import get_hash, create_directory, uncompress_path, is_archive +from substrapp.utils import get_hash, create_directory, uncompress_path from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.tasks.utils import get_asset_content from substrapp.views.utils import ManageFileMixin, find_primary_key_error, validate_pk, \ @@ -122,9 +122,6 @@ def _create(self, request, dryrun): description = request.data.get('description') test_data_manager_key = request.data.get('test_data_manager_key', '') - if not is_archive(metrics.file.read()): - raise Exception('Archive must be zip or tar.*') - pkhash = get_hash(description) serializer = self.get_serializer(data={ From 95b9589552cbe18c546d78ab36df8bb5fea6375a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 6 Sep 2019 16:07:06 +0200 Subject: [PATCH 262/457] Refacto serializer --- substrabac/substrapp/serializers/algo.py | 49 +------------------ substrabac/substrapp/serializers/objective.py | 49 +------------------ substrabac/substrapp/serializers/utils.py | 49 +++++++++++++++++++ 3 files changed, 51 insertions(+), 96 deletions(-) create mode 100644 substrabac/substrapp/serializers/utils.py diff --git a/substrabac/substrapp/serializers/algo.py b/substrabac/substrapp/serializers/algo.py index e4a2e82d0..2b0d15e98 100644 --- a/substrabac/substrapp/serializers/algo.py +++ b/substrabac/substrapp/serializers/algo.py @@ -1,56 +1,9 @@ -import tarfile -import zipfile - -from django.core.exceptions import ValidationError from rest_framework import serializers from libs.serializers import DynamicFieldsModelSerializer from substrapp.models import Algo -from django.utils.deconstruct import deconstructible - - -@deconstructible -class FileValidator(object): - error_messages = { - 'open': ("Cannot handle this file object."), - 'compressed': ("Ensure this file is an archive (zip or tar.* compressed file)."), - 'docker': ("Ensure your archive contains a Dockerfile."), - 'file': ("Ensure your archive contains at least one algo file (for instance algo.py)."), - } - - def validate_archive(self, files): - if 'Dockerfile' not in files: - raise ValidationError(self.error_messages['docker']) - - if len(files) < 2: - raise ValidationError(self.error_messages['file']) - - def __call__(self, data): - - archive = None - try: - data.file.seek(0) - except Exception: - raise ValidationError(self.error_messages['open']) - else: - try: - # is tarfile? - archive = tarfile.open(fileobj=data.file) - except tarfile.TarError: - # is zipfile? - if not zipfile.is_zipfile(data.file): - raise ValidationError(self.error_messages['compressed']) - - archive = zipfile.ZipFile(file=data.file) - self.validate_archive(archive.namelist()) - else: - self.validate_archive([x.name for x in archive.getmembers()]) - finally: - if archive: - archive.close() - else: - raise ValidationError(self.error_messages['open']) +from substrapp.serializers.utils import FileValidator class AlgoSerializer(DynamicFieldsModelSerializer): diff --git a/substrabac/substrapp/serializers/objective.py b/substrabac/substrapp/serializers/objective.py index 939282e38..5c5eef6f4 100644 --- a/substrabac/substrapp/serializers/objective.py +++ b/substrabac/substrapp/serializers/objective.py @@ -1,56 +1,9 @@ -import tarfile -import zipfile - -from django.core.exceptions import ValidationError from rest_framework import serializers from libs.serializers import DynamicFieldsModelSerializer from substrapp.models import Objective -from django.utils.deconstruct import deconstructible - - -@deconstructible -class FileValidator(object): - error_messages = { - 'open': ("Cannot handle this file object."), - 'compressed': ("Ensure this file is an archive (zip or tar.* compressed file)."), - 'docker': ("Ensure your archive contains a Dockerfile."), - 'file': ("Ensure your archive contains at least one metrics file (for instance metrics.py)."), - } - - def validate_archive(self, files): - if 'Dockerfile' not in files: - raise ValidationError(self.error_messages['docker']) - - if len(files) < 2: - raise ValidationError(self.error_messages['file']) - - def __call__(self, data): - - archive = None - try: - data.file.seek(0) - except Exception: - raise ValidationError(self.error_messages['open']) - else: - try: - # is tarfile? - archive = tarfile.open(fileobj=data.file) - except tarfile.TarError: - # is zipfile? - if not zipfile.is_zipfile(data.file): - raise ValidationError(self.error_messages['compressed']) - - archive = zipfile.ZipFile(file=data.file) - self.validate_archive(archive.namelist()) - else: - self.validate_archive([x.name for x in archive.getmembers()]) - finally: - if archive: - archive.close() - else: - raise ValidationError(self.error_messages['open']) +from substrapp.serializers.utils import FileValidator class ObjectiveSerializer(DynamicFieldsModelSerializer): diff --git a/substrabac/substrapp/serializers/utils.py b/substrabac/substrapp/serializers/utils.py new file mode 100644 index 000000000..3442cd491 --- /dev/null +++ b/substrabac/substrapp/serializers/utils.py @@ -0,0 +1,49 @@ +import tarfile +import zipfile + +from django.core.exceptions import ValidationError + +from django.utils.deconstruct import deconstructible + + +@deconstructible +class FileValidator(object): + error_messages = { + 'open': ("Cannot handle this file object."), + 'compressed': ("Ensure this file is an archive (zip or tar.* compressed file)."), + 'docker': ("Ensure your archive contains a Dockerfile."), + 'file': ("Ensure your archive contains at least one python file."), + } + + def validate_archive(self, files): + if 'Dockerfile' not in files: + raise ValidationError(self.error_messages['docker']) + + if len(files) < 2: + raise ValidationError(self.error_messages['file']) + + def __call__(self, data): + + archive = None + try: + data.file.seek(0) + except Exception: + raise ValidationError(self.error_messages['open']) + else: + try: + # is tarfile? + archive = tarfile.open(fileobj=data.file) + except tarfile.TarError: + # is zipfile? + if not zipfile.is_zipfile(data.file): + raise ValidationError(self.error_messages['compressed']) + + archive = zipfile.ZipFile(file=data.file) + self.validate_archive(archive.namelist()) + else: + self.validate_archive([x.name for x in archive.getmembers()]) + finally: + if archive: + archive.close() + else: + raise ValidationError(self.error_messages['open']) From 869c4823c813a595806ff690eed9670f0200c1b2 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 6 Sep 2019 16:45:06 +0200 Subject: [PATCH 263/457] update to last fabric-sdk-py commit --- substrabac/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/requirements.txt b/substrabac/requirements.txt index 7f5055b30..cb6ed95ce 100644 --- a/substrabac/requirements.txt +++ b/substrabac/requirements.txt @@ -27,4 +27,4 @@ rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 -git+git://github.com/hyperledger/fabric-sdk-py.git@7772adca1c4e2a1cda1c596d9c23fdec9b4dc799 # fabric-sdk-py==0.8.1 +git+git://github.com/hyperledger/fabric-sdk-py.git@36cc15021f74c11c7ae3196e380a5275c220145f # fabric-sdk-py==0.8.1 From 1c88b671ae327691f25ab7fb7d3f76c6203bfc78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 9 Sep 2019 14:54:01 +0200 Subject: [PATCH 264/457] fix user auth backends --- substrabac/libs/authentication.py | 2 +- substrabac/node/authentication.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/libs/authentication.py b/substrabac/libs/authentication.py index fbc72c63c..f0de5735b 100644 --- a/substrabac/libs/authentication.py +++ b/substrabac/libs/authentication.py @@ -11,7 +11,7 @@ def authenticate(self, request, username=None, password=None): return None if username == settings.BASICAUTH_USERNAME and password == settings.BASICAUTH_PASSWORD: - return User(username) + return User(username=username) return None diff --git a/substrabac/node/authentication.py b/substrabac/node/authentication.py index c4a7f8610..6dbe3f858 100644 --- a/substrabac/node/authentication.py +++ b/substrabac/node/authentication.py @@ -15,7 +15,7 @@ def authenticate(self, request, username=None, password=None): incoming_node_exists = IncomingNode.objects.filter(node_id=node_id, secret=secret).exists() if incoming_node_exists: - return User(node_id) + return User(username=node_id) return None From 997ff58b5bc06764a86c42d195e075218780675c Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 9 Sep 2019 16:56:19 +0200 Subject: [PATCH 265/457] Non invasive way for disabling user basic auth while keeping it for node to node authentication --- README.md | 15 ++++ docker/start.py | 18 +++-- substrabac/libs/authentication.py | 1 + substrabac/node/authentication.py | 7 +- substrabac/node/models.py | 2 + substrabac/substrabac/settings/common.py | 4 + .../substrabac/settings/deps/restframework.py | 5 +- .../settings/events/nobasicauth/__init__.py | 0 .../settings/events/nobasicauth/dev.py | 3 + .../settings/events/nobasicauth/prod.py | 3 + substrabac/substrabac/settings/test.py | 13 ++-- substrabac/substrapp/tests/common.py | 23 ++++-- substrabac/substrapp/tests/tests_tasks.py | 8 +- .../tests/views/test_views_authentication.py | 30 +++++-- substrabac/substrapp/urls.py | 5 +- substrabac/substrapp/views/__init__.py | 12 +-- substrabac/substrapp/views/algo.py | 10 ++- substrabac/substrapp/views/datamanager.py | 10 ++- substrabac/substrapp/views/objective.py | 28 ++++--- substrabac/substrapp/views/utils.py | 78 +++++++++++++++---- 20 files changed, 205 insertions(+), 70 deletions(-) create mode 100644 substrabac/substrabac/settings/events/nobasicauth/__init__.py create mode 100644 substrabac/substrabac/settings/events/nobasicauth/dev.py create mode 100644 substrabac/substrabac/settings/events/nobasicauth/prod.py diff --git a/README.md b/README.md index 540eace83..455ff15a1 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,22 @@ Go in the `substrabac` folder and run the server locally: SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.events.dev SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.events.dev ``` + + If you want to bypass the basic authentication when you browse the server on localhost:8000 or localhost:8001, you can use the `nobasicauth` settings. + Simply replace `events.dev` by `nobasicauth`, like: + ``` + SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.nobasicauth + SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.nobasicauth + ``` + It allows the substrafront project to work correctly too. + +## Load data fixtures +For working with node to node authentication, you need load some extra fixtures +``` +SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py loaddata nodes-owkin.yaml --settings=substrabac.settings.events.dev +SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py loaddata nodes-chunantes.yaml --settings=substrabac.settings.events.dev +``` ## Test with unit and functional tests diff --git a/docker/start.py b/docker/start.py index 21ccfb34f..442ff1014 100644 --- a/docker/start.py +++ b/docker/start.py @@ -23,7 +23,7 @@ SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') -def generate_docker_compose_file(conf, launch_settings): +def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): # POSTGRES POSTGRES_USER = 'substrabac' @@ -127,7 +127,9 @@ def generate_docker_compose_file(conf, launch_settings): f'--module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics ' \ f'--master --processes {processes} --threads 2' else: - django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.events.dev ' \ + print('nobasicauth: ', nobasicauth, flush=True) + extra_settings = '.nobasicauth' if nobasicauth is True else '' + django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.events{extra_settings}.dev ' \ f'python3 manage.py runserver --noreload 0.0.0.0:{port}' backend_global_env = [ @@ -281,9 +283,9 @@ def stop(docker_compose=None): os.path.join(dir_path, '../'), 'down', '--remove-orphans']) -def start(conf, launch_settings, no_backup): +def start(conf, launch_settings, no_backup, nobasicauth=False): print('Generate docker-compose file\n') - docker_compose = generate_docker_compose_file(conf, launch_settings) + docker_compose = generate_docker_compose_file(conf, launch_settings, nobasicauth) stop(docker_compose) @@ -307,6 +309,8 @@ def start(conf, launch_settings, no_backup): parser = argparse.ArgumentParser() parser.add_argument('-d', '--dev', action='store_true', default=False, help="use dev settings") + parser.add_argument('--nobasicauth', action='store_true', default=False, + help="use dev settings without basic authentication") parser.add_argument('--no-backup', action='store_true', default=False, help="Remove backup binded volume, medias and db data. Launch from scratch") args = vars(parser.parse_args()) @@ -316,6 +320,10 @@ def start(conf, launch_settings, no_backup): else: launch_settings = 'prod' + nobasicauth = False + if args['nobasicauth']: + nobasicauth = True + no_backup = args['no_backup'] conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/substrabac/conf.json')] @@ -327,4 +335,4 @@ def start(conf, launch_settings, no_backup): print('', flush=True) - start(conf, launch_settings, no_backup) + start(conf, launch_settings, no_backup, nobasicauth) diff --git a/substrabac/libs/authentication.py b/substrabac/libs/authentication.py index f0de5735b..fb7f2d0d8 100644 --- a/substrabac/libs/authentication.py +++ b/substrabac/libs/authentication.py @@ -2,6 +2,7 @@ from django.contrib.auth.models import User +#TODO should be removed when local users are handled with registering/logging and session class SettingsBackend: """Authenticate against user and password defined in settings.""" diff --git a/substrabac/node/authentication.py b/substrabac/node/authentication.py index 6dbe3f858..af2578de7 100644 --- a/substrabac/node/authentication.py +++ b/substrabac/node/authentication.py @@ -2,6 +2,11 @@ from .models import IncomingNode +class NodeUser(User): + pass + + +# TODO: should be removed when node to node authent will be done via certificates class NodeBackend: """Authenticate node """ @@ -15,7 +20,7 @@ def authenticate(self, request, username=None, password=None): incoming_node_exists = IncomingNode.objects.filter(node_id=node_id, secret=secret).exists() if incoming_node_exists: - return User(username=node_id) + return NodeUser(username=node_id) return None diff --git a/substrabac/node/models.py b/substrabac/node/models.py index dbb5fde54..1de3989aa 100644 --- a/substrabac/node/models.py +++ b/substrabac/node/models.py @@ -1,4 +1,6 @@ from django.db import models +from django.contrib.auth.models import User + import secrets diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 81ec6b0dd..245254358 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -74,6 +74,7 @@ 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.RemoteUserMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'libs.SQLPrintingMiddleware.SQLPrintingMiddleware', @@ -159,3 +160,6 @@ CELERY_BROKER_URL = os.environ.get('CELERY_BROKER_URL', 'amqp://localhost:5672//'), DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 + + +BASIC_AUTHENTICATION_MODULE = 'rest_framework.authentication' diff --git a/substrabac/substrabac/settings/deps/restframework.py b/substrabac/substrabac/settings/deps/restframework.py index 189e836c8..7d7062470 100644 --- a/substrabac/substrabac/settings/deps/restframework.py +++ b/substrabac/substrabac/settings/deps/restframework.py @@ -6,12 +6,9 @@ 'rest_framework.renderers.BrowsableAPIRenderer', ), 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ], - 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.IsAuthenticated', - ], + 'DEFAULT_PERMISSION_CLASSES': [], 'UNICODE_JSON': False, 'DEFAULT_VERSIONING_CLASS': 'libs.versioning.AcceptHeaderVersioningRequired', 'ALLOWED_VERSIONS': ('0.0',), diff --git a/substrabac/substrabac/settings/events/nobasicauth/__init__.py b/substrabac/substrabac/settings/events/nobasicauth/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/substrabac/settings/events/nobasicauth/dev.py b/substrabac/substrabac/settings/events/nobasicauth/dev.py new file mode 100644 index 000000000..7c6c71cbc --- /dev/null +++ b/substrabac/substrabac/settings/events/nobasicauth/dev.py @@ -0,0 +1,3 @@ +from ..dev import * + +BASIC_AUTHENTICATION_MODULE = 'substrapp.views.utils' diff --git a/substrabac/substrabac/settings/events/nobasicauth/prod.py b/substrabac/substrabac/settings/events/nobasicauth/prod.py new file mode 100644 index 000000000..07963050b --- /dev/null +++ b/substrabac/substrabac/settings/events/nobasicauth/prod.py @@ -0,0 +1,3 @@ +from ..prod import * + +BASIC_AUTHENTICATION_MODULE = 'substrapp.views.utils' diff --git a/substrabac/substrabac/settings/test.py b/substrabac/substrabac/settings/test.py index d94d84c7b..3fa8821e8 100644 --- a/substrabac/substrabac/settings/test.py +++ b/substrabac/substrabac/settings/test.py @@ -1,9 +1,12 @@ -from .common import * # noqa -from .deps.cors import * # noqa -from .deps.restframework import * # noqa +from .common import * +from .deps.cors import * +from .deps.restframework import * import logging logging.disable(logging.CRITICAL) -BASICAUTH_USERNAME = "admin" -BASICAUTH_PASSWORD = "admin" +BASICAUTH_USERNAME = "test" +BASICAUTH_PASSWORD = "test" + +# by default, bypass basic auth +BASIC_AUTHENTICATION_MODULE = 'substrapp.views.utils' diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 4829e4c3f..19d8a5bd7 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -235,8 +235,7 @@ def get_sample_tar_data_sample(): dir_path, '../../../fixtures/owkin/datasamples/datasample4/0024900.tar.gz'), 'rb') as tar_file: flength = f.write(tar_file.read()) - file = InMemoryUploadedFile(f, None, file_filename, - 'application/zip', flength, None) + file = InMemoryUploadedFile(f, None, file_filename, 'application/zip', flength, None) file.seek(0) return file, file_filename @@ -249,8 +248,7 @@ def get_sample_algo(): with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/algo.tar.gz'), 'rb') as tar_file: flength = f.write(tar_file.read()) - file = InMemoryUploadedFile(f, None, file_filename, - 'application/tar+gzip', flength, None) + file = InMemoryUploadedFile(f, None, file_filename, 'application/tar+gzip', flength, None) file.seek(0) return file, file_filename @@ -258,18 +256,29 @@ def get_sample_algo(): def get_sample_algo_zip(): dir_path = os.path.dirname(os.path.realpath(__file__)) - file_filename = "file.tar.gz" + file_filename = "file.zip" f = BytesIO() with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo0/algo.zip'), 'rb') as tar_file: flength = f.write(tar_file.read()) - file = InMemoryUploadedFile(f, None, file_filename, - 'application/tar+gzip', flength, None) + file = InMemoryUploadedFile(f, None, file_filename, 'application/tar+gzip', flength, None) file.seek(0) return file, file_filename +def get_description_algo(): + dir_path = os.path.dirname(os.path.realpath(__file__)) + file_filename = "file.md" + f = BytesIO() + with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo3/description.md'), 'rb') as desc_file: + flength = f.write(desc_file.read()) + + file = InMemoryUploadedFile(f, None, file_filename, 'application/text', flength, None) + file.seek(0) + + return file, file_filename + def get_sample_model(): model_content = "0.1, 0.2, -1.0" model_filename = "model.bin" diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 00348ffe5..6bd00401d 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -403,11 +403,11 @@ def test_get_model(self): subtuple = {model_type: {'hash': model_hash, 'traintupleKey': traintupleKey}} with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file, \ - mock.patch('substrapp.tasks.utils.get_owner') as get_owner,\ - mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: + mock.patch('substrapp.tasks.utils.get_owner') as mget_owner,\ + mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as mget_object_from_ledger: mget_remote_file.return_value = model_content - get_owner.return_value = assets.traintuple[1]['creator'] - get_object_from_ledger.return_value = assets.traintuple[1] # uses index 1 to have a set value of outModel + mget_owner.return_value = assets.traintuple[1]['creator'] + mget_object_from_ledger.return_value = assets.traintuple[1] # uses index 1 to have a set value of outModel model_content = get_model(subtuple) self.assertIsNotNone(model_content) diff --git a/substrabac/substrapp/tests/views/test_views_authentication.py b/substrabac/substrapp/tests/views/test_views_authentication.py index c9b137463..ec8468585 100644 --- a/substrabac/substrapp/tests/views/test_views_authentication.py +++ b/substrabac/substrapp/tests/views/test_views_authentication.py @@ -1,8 +1,11 @@ +import mock +from django.urls import reverse from rest_framework import status from rest_framework.test import APITestCase from node.models import IncomingNode +from substrapp.models import Algo -from ..common import generate_basic_auth_header +from ..common import generate_basic_auth_header, get_sample_algo_metadata, get_sample_algo, get_description_algo from django.conf import settings @@ -12,12 +15,18 @@ def setUp(self): 'HTTP_ACCEPT': 'application/json;version=0.0' } + # create algo instance which file download is protected + self.algo_file, self.algo_filename = get_sample_algo() + self.algo_description_file, self.algo_description_filename = get_description_algo() + self.algo = Algo.objects.create(file=self.algo_file, description=self.algo_description_file) + self.algo_url = reverse('substrapp:algo-file', kwargs={'pk': self.algo.pk}) + @classmethod def setUpTestData(cls): cls.incoming_node = IncomingNode.objects.create(node_id="external_node_id", secret="s3cr37") def test_authentication_fail(self): - response = self.client.get('/', **self.extra) + response = self.client.get(self.algo_url, **self.extra) self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) @@ -25,15 +34,18 @@ def test_authentication_with_settings_success(self): authorization_header = generate_basic_auth_header(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) self.client.credentials(HTTP_AUTHORIZATION=authorization_header) - response = self.client.get('/', **self.extra) - self.assertEqual(status.HTTP_200_OK, response.status_code) + with mock.patch('substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = get_sample_algo_metadata() + response = self.client.get(self.algo_url, **self.extra) + + self.assertEqual(status.HTTP_200_OK, response.status_code) def test_authentication_with_bad_settings_credentials_fail(self): authorization_header = generate_basic_auth_header('unauthorized_username', 'unauthorized_password') self.client.credentials(HTTP_AUTHORIZATION=authorization_header) - response = self.client.get('/', **self.extra) + response = self.client.get(self.algo_url, **self.extra) self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) @@ -41,9 +53,11 @@ def test_authentication_with_node(self): authorization_header = generate_basic_auth_header('external_node_id', 's3cr37') self.client.credentials(HTTP_AUTHORIZATION=authorization_header) - response = self.client.get('/', **self.extra) + with mock.patch('substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + mget_object_from_ledger.return_value = get_sample_algo_metadata() + response = self.client.get(self.algo_url, **self.extra) - self.assertEqual(status.HTTP_200_OK, response.status_code) + self.assertEqual(status.HTTP_200_OK, response.status_code) def test_authentication_with_node_fail(self): bad_authorization_headers = [ @@ -54,6 +68,6 @@ def test_authentication_with_node_fail(self): for header in bad_authorization_headers: self.client.credentials(HTTP_AUTHORIZATION=header) - response = self.client.get('/', **self.extra) + response = self.client.get(self.algo_url, **self.extra) self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index 4e5d4b704..62f12949e 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -7,16 +7,19 @@ from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ - ComputePlanViewSet + ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet # Create a router and register our viewsets with it. router = DefaultRouter() router.register(r'objective', ObjectiveViewSet, base_name='objective') +router.register(r'objective', ObjectivePermissionViewSet, base_name='objective') router.register(r'model', ModelViewSet, base_name='model') router.register(r'data_sample', DataSampleViewSet, base_name='data_sample') router.register(r'data_manager', DataManagerViewSet, base_name='data_manager') +router.register(r'data_manager', DataManagerPermissionViewSet, base_name='data_manager') router.register(r'algo', AlgoViewSet, base_name='algo') +router.register(r'algo', AlgoPermissionViewSet, base_name='algo') router.register(r'traintuple', TrainTupleViewSet, base_name='traintuple') router.register(r'testtuple', TestTupleViewSet, base_name='testtuple') router.register(r'task', TaskViewSet, base_name='task') diff --git a/substrabac/substrapp/views/__init__.py b/substrabac/substrapp/views/__init__.py index b44f571af..6f3ef8758 100644 --- a/substrabac/substrapp/views/__init__.py +++ b/substrabac/substrapp/views/__init__.py @@ -1,15 +1,15 @@ # encoding: utf-8 from .datasample import DataSampleViewSet -from .datamanager import DataManagerViewSet -from .objective import ObjectiveViewSet +from .datamanager import DataManagerViewSet, DataManagerPermissionViewSet +from .objective import ObjectiveViewSet, ObjectivePermissionViewSet from .model import ModelViewSet -from .algo import AlgoViewSet +from .algo import AlgoViewSet, AlgoPermissionViewSet from .traintuple import TrainTupleViewSet from .testtuple import TestTupleViewSet from .task import TaskViewSet from .computeplan import ComputePlanViewSet -__all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'ObjectiveViewSet', 'ModelViewSet', - 'AlgoViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', - 'TaskViewSet', 'ComputePlanViewSet'] +__all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'DataManagerPermissionViewSet', 'ObjectiveViewSet', + 'ObjectivePermissionViewSet', 'ModelViewSet', 'AlgoViewSet', 'AlgoPermissionViewSet', 'TrainTupleViewSet', + 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet'] diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 32900610a..a3ae52059 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -12,7 +12,7 @@ from substrapp.serializers import LedgerAlgoSerializer, AlgoSerializer from substrapp.utils import get_hash from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.views.utils import (ManageFileMixin, find_primary_key_error, +from substrapp.views.utils import (PermissionMixin, find_primary_key_error, validate_pk, get_success_create_code, LedgerException, ValidationException, get_remote_asset) from substrapp.views.filters_utils import filter_list @@ -21,7 +21,6 @@ class AlgoViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, - ManageFileMixin, GenericViewSet): queryset = Algo.objects.all() serializer_class = AlgoSerializer @@ -187,6 +186,13 @@ def list(self, request, *args, **kwargs): return Response(algos_list, status=status.HTTP_200_OK) + +class AlgoPermissionViewSet(PermissionMixin, + GenericViewSet): + queryset = Algo.objects.all() + serializer_class = AlgoSerializer + ledger_query_call = 'queryAlgo' + @action(detail=True) def file(self, request, *args, **kwargs): return self.download_file(request, 'file') diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 5ff9d3386..b32cb6141 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -17,7 +17,7 @@ from substrapp.serializers.ledger.datamanager.tasks import updateLedgerDataManagerAsync from substrapp.utils import get_hash from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.views.utils import (ManageFileMixin, find_primary_key_error, +from substrapp.views.utils import (PermissionMixin, find_primary_key_error, validate_pk, get_success_create_code, ValidationException, LedgerException, get_remote_asset) from substrapp.views.filters_utils import filter_list @@ -26,7 +26,6 @@ class DataManagerViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, - ManageFileMixin, GenericViewSet): queryset = DataManager.objects.all() serializer_class = DataManagerSerializer @@ -273,6 +272,13 @@ def update_ledger(self, request, *args, **kwargs): return Response(data, status=st) + +class DataManagerPermissionViewSet(PermissionMixin, + GenericViewSet): + queryset = DataManager.objects.all() + serializer_class = DataManagerSerializer + ledger_query_call = 'queryDataManager' + @action(detail=True) def description(self, request, *args, **kwargs): return self.download_file(request, 'description') diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 1927760ce..f2960d1a3 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -25,7 +25,7 @@ from substrapp.utils import get_hash, create_directory, uncompress_path from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.tasks.utils import get_asset_content -from substrapp.views.utils import ManageFileMixin, find_primary_key_error, validate_pk, \ +from substrapp.views.utils import PermissionMixin, find_primary_key_error, validate_pk, \ get_success_create_code, ValidationException, LedgerException, get_remote_asset, validate_sort from substrapp.views.filters_utils import filter_list @@ -33,14 +33,11 @@ class ObjectiveViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, - ManageFileMixin, GenericViewSet): queryset = Objective.objects.all() serializer_class = ObjectiveSerializer ledger_query_call = 'queryObjective' - # permission_classes = (permissions.IsAuthenticated,) - def perform_create(self, serializer): return serializer.save() @@ -249,14 +246,6 @@ def list(self, request, *args, **kwargs): return Response(objectives_list, status=status.HTTP_200_OK) - @action(detail=True) - def description(self, request, *args, **kwargs): - return self.download_file(request, 'description') - - @action(detail=True) - def metrics(self, request, *args, **kwargs): - return self.download_file(request, 'metrics') - @action(detail=True) def data(self, request, *args, **kwargs): instance = self.get_object() @@ -353,3 +342,18 @@ def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): logging.error(e, exc_info=True) remove_subtuple_materials(subtuple_directory) + + +class ObjectivePermissionViewSet(PermissionMixin, + GenericViewSet): + queryset = Objective.objects.all() + serializer_class = ObjectiveSerializer + ledger_query_call = 'queryObjective' + + @action(detail=True) + def description(self, request, *args, **kwargs): + return self.download_file(request, 'description') + + @action(detail=True) + def metrics(self, request, *args, **kwargs): + return self.download_file(request, 'metrics') diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 1c5428f6a..71efcb15a 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -1,6 +1,12 @@ import os +import base64 +import binascii +from importlib import import_module + from django.http import FileResponse +from rest_framework.authentication import SessionAuthentication, BasicAuthentication, get_authorization_header +from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from substrapp.ledger_utils import get_object_from_ledger, LedgerError @@ -11,6 +17,10 @@ from rest_framework import status from requests.auth import HTTPBasicAuth +from django.utils.translation import ugettext_lazy as _ + +from rest_framework import HTTP_HEADER_ENCODING, exceptions + def authenticate_outgoing_request(outgoing_node_id): try: @@ -41,23 +51,65 @@ def is_local_user(user): return user.username == settings.BASICAUTH_USERNAME -def has_access(user, asset): - """Returns true if API consumer can access asset data.""" - if user.is_anonymous: # safeguard, should never happened - return False +class BasicAuthentication(BasicAuthentication): + def authenticate(self, request): + """ + Returns a `User` if a correct username and password have been supplied + using HTTP Basic authentication. Otherwise returns `None`. + """ + auth = get_authorization_header(request).split() + + if not auth or auth[0].lower() != b'basic': + if not settings.DEBUG: + return None + else: + # create fake auth in debug mode, if no provided (user case, not node) + auth = [b'Basic', base64.b64encode(f'{settings.BASICAUTH_USERNAME}:{settings.BASICAUTH_PASSWORD}'.encode(HTTP_HEADER_ENCODING))] + + if len(auth) == 1: + msg = _('Invalid basic header. No credentials provided.') + raise exceptions.AuthenticationFailed(msg) + elif len(auth) > 2: + msg = _('Invalid basic header. Credentials string should not contain spaces.') + raise exceptions.AuthenticationFailed(msg) + + try: + auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':') + except (TypeError, UnicodeDecodeError, binascii.Error): + msg = _('Invalid basic header. Credentials not correctly base64 encoded.') + raise exceptions.AuthenticationFailed(msg) + + userid, password = auth_parts[0], auth_parts[2] + return self.authenticate_credentials(userid, password, request) + + def authenticate_header(self, request): + if not settings.DEBUG: + return 'Basic realm="%s"' % self.www_authenticate_realm + + # do not prompt basic auth prompt in debug mode + return '' + + +class PermissionMixin(object): + + authentication_classes = [import_module(settings.BASIC_AUTHENTICATION_MODULE).BasicAuthentication, SessionAuthentication] + permission_classes = [IsAuthenticated] - if is_local_user(user): - return True + def _has_access(self, user, asset): + """Returns true if API consumer can access asset data.""" + if user.is_anonymous: # safeguard, should never happened + return False - permission = asset['permissions']['process'] - if permission['public']: - return True + if is_local_user(user): + return True - node_id = user.username - return node_id in permission['authorizedIDs'] + permission = asset['permissions']['process'] + if permission['public']: + return True + node_id = user.username + return node_id in permission['authorizedIDs'] -class ManageFileMixin(object): def download_file(self, request, field): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] @@ -67,7 +119,7 @@ def download_file(self, request, field): except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - if not has_access(request.user, asset): + if not self._has_access(request.user, asset): return Response({'message': 'Unauthorized'}, status=status.HTTP_401_UNAUTHORIZED) From 2f98c80b5aa7ef25351789f47b78b31da25334cf Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 10 Sep 2019 09:27:54 +0200 Subject: [PATCH 266/457] clean flake8 --- .flake8 | 1 + substrabac/libs/authentication.py | 2 +- substrabac/node/models.py | 1 - substrabac/substrapp/tests/common.py | 1 + substrabac/substrapp/views/utils.py | 6 ++++-- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.flake8 b/.flake8 index e20e69f23..63caeb3d6 100644 --- a/.flake8 +++ b/.flake8 @@ -3,4 +3,5 @@ max-line-length = 120 ignore = E402, W504, F403, F405 exclude = substrabac/substrapp/migrations/*, substrabac/substrapp/tests/assets.py, + substrabac/substrabac/settings/*, .env, .venv diff --git a/substrabac/libs/authentication.py b/substrabac/libs/authentication.py index fb7f2d0d8..44b80694c 100644 --- a/substrabac/libs/authentication.py +++ b/substrabac/libs/authentication.py @@ -2,7 +2,7 @@ from django.contrib.auth.models import User -#TODO should be removed when local users are handled with registering/logging and session +# TODO should be removed when local users are handled with registering/logging and session class SettingsBackend: """Authenticate against user and password defined in settings.""" diff --git a/substrabac/node/models.py b/substrabac/node/models.py index 1de3989aa..73c5f7a19 100644 --- a/substrabac/node/models.py +++ b/substrabac/node/models.py @@ -1,5 +1,4 @@ from django.db import models -from django.contrib.auth.models import User import secrets diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 19d8a5bd7..04dbb0afa 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -279,6 +279,7 @@ def get_description_algo(): return file, file_filename + def get_sample_model(): model_content = "0.1, 0.2, -1.0" model_filename = "model.bin" diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 71efcb15a..623aac3c8 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -64,7 +64,8 @@ def authenticate(self, request): return None else: # create fake auth in debug mode, if no provided (user case, not node) - auth = [b'Basic', base64.b64encode(f'{settings.BASICAUTH_USERNAME}:{settings.BASICAUTH_PASSWORD}'.encode(HTTP_HEADER_ENCODING))] + debug_basic_auth = f'{settings.BASICAUTH_USERNAME}:{settings.BASICAUTH_PASSWORD}' + auth = [b'Basic', base64.b64encode(debug_basic_auth.encode(HTTP_HEADER_ENCODING))] if len(auth) == 1: msg = _('Invalid basic header. No credentials provided.') @@ -92,7 +93,8 @@ def authenticate_header(self, request): class PermissionMixin(object): - authentication_classes = [import_module(settings.BASIC_AUTHENTICATION_MODULE).BasicAuthentication, SessionAuthentication] + authentication_classes = [import_module(settings.BASIC_AUTHENTICATION_MODULE).BasicAuthentication, + SessionAuthentication] permission_classes = [IsAuthenticated] def _has_access(self, user, asset): From 1e0efa41d82123e3e78fda355daa14c508cd110c Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 10 Sep 2019 11:51:41 +0200 Subject: [PATCH 267/457] fix README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 455ff15a1..19bfe68aa 100644 --- a/README.md +++ b/README.md @@ -161,8 +161,8 @@ Go in the `substrabac` folder and run the server locally: If you want to bypass the basic authentication when you browse the server on localhost:8000 or localhost:8001, you can use the `nobasicauth` settings. Simply replace `events.dev` by `nobasicauth`, like: ``` - SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.nobasicauth - SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.nobasicauth + SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.events.nobasicauth + SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.events.nobasicauth ``` It allows the substrafront project to work correctly too. From 07cb7e5fb656239c20ce66755485751c099c0524 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 10 Sep 2019 12:18:54 +0200 Subject: [PATCH 268/457] fix test mock algo application/zip application MIME type --- substrabac/substrapp/tests/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 04dbb0afa..8dad5fbab 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -261,7 +261,7 @@ def get_sample_algo_zip(): with open(os.path.join(dir_path, '../../../fixtures/chunantes/algos/algo0/algo.zip'), 'rb') as tar_file: flength = f.write(tar_file.read()) - file = InMemoryUploadedFile(f, None, file_filename, 'application/tar+gzip', flength, None) + file = InMemoryUploadedFile(f, None, file_filename, 'application/zip', flength, None) file.seek(0) return file, file_filename From f2dea28835a1261a9c038946bcd5e6c0cda5fa0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 11 Sep 2019 09:04:22 +0200 Subject: [PATCH 269/457] add tuple filtering by tag and compute_plan_id (#301) * add tuple filtering by tag and compute_plan_id * update populate.py and tests fixtures * fix test + refactor comment in asset --- populate.py | 49 ++- substrabac/substrapp/tests/assets.py | 280 ++++++++++++------ substrabac/substrapp/tests/generate_assets.py | 8 +- .../substrapp/tests/views/tests_views_algo.py | 2 +- .../tests/views/tests_views_model.py | 6 +- .../tests/views/tests_views_tuples.py | 51 +++- substrabac/substrapp/views/filters_utils.py | 4 +- substrabac/substrapp/views/testtuple.py | 23 +- substrabac/substrapp/views/traintuple.py | 23 +- 9 files changed, 336 insertions(+), 110 deletions(-) diff --git a/populate.py b/populate.py index 5e35c56a3..7b7a52f50 100644 --- a/populate.py +++ b/populate.py @@ -156,7 +156,8 @@ def do_populate(): if not args['archive']: print(f'register train data (from server) on datamanager {org_1} (will take datamanager creator as worker)') data_samples_path = ['./fixtures/chunantes/datasamples/train/0024306', - './fixtures/chunantes/datasamples/train/0024307'] + './fixtures/chunantes/datasamples/train/0024307', + './fixtures/chunantes/datasamples/train/0024308'] for d in data_samples_path: try: shutil.copytree(os.path.join(dir_path, d), @@ -174,7 +175,8 @@ def do_populate(): data = { 'paths': [ os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024306'), - os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024307') + os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024307'), + os.path.join(dir_path, './fixtures/chunantes/datasamples/train/0024308') ], 'data_manager_keys': [data_manager_org1_key], 'test_only': False, @@ -331,7 +333,7 @@ def do_populate(): 'algo_key': algo_key, 'objective_key': objective_key, 'data_manager_key': data_manager_org1_key, - 'train_data_sample_keys': train_data_sample_keys, + 'train_data_sample_keys': train_data_sample_keys[:2], 'tag': 'substra' } traintuple_key = get_or_create(data, org_1, 'traintuple') @@ -341,7 +343,7 @@ def do_populate(): 'algo_key': algo_key_2, 'data_manager_key': data_manager_org1_key, 'objective_key': objective_key, - 'train_data_sample_keys': train_data_sample_keys, + 'train_data_sample_keys': train_data_sample_keys[:2], 'tag': 'My super tag' } @@ -352,7 +354,7 @@ def do_populate(): 'algo_key': algo_key_3, 'data_manager_key': data_manager_org1_key, 'objective_key': objective_key, - 'train_data_sample_keys': train_data_sample_keys, + 'train_data_sample_keys': train_data_sample_keys[:2], } get_or_create(data, org_1, 'traintuple') @@ -366,7 +368,8 @@ def do_populate(): # create testtuple print('create testtuple') data = { - 'traintuple_key': traintuple_key + 'traintuple_key': traintuple_key, + 'tag': 'substra', } testtuple_key = get_or_create(data, org_1, 'testtuple') @@ -395,6 +398,40 @@ def do_populate(): time.sleep(3) + #################################################### + # Compute plan + + print('create compute plan') + traintuples_data = [ + { + "data_manager_key": data_manager_org1_key, + "train_data_sample_keys": [train_data_sample_keys[0], train_data_sample_keys[2]], + "traintuple_id": "dummy_traintuple_id", + "in_models_ids": [], + "tag": "", + }, + ] + testtuples_data = [ + # { + # "traintuple_id": "dummy_traintuple_id", + # "tag": "", + # } + ] + compute_plan_data = { + "algo_key": algo_key, # logistic regression, org2 + "objective_key": objective_key, # org 0 + "traintuples": traintuples_data, + "testtuples": testtuples_data, + } + # until both chaincode, backend and sdk can handle compute plan collisions, we need to have a + # generic try-except so that this script can run multiple times in a row + try: + client.set_profile(org_1) + res = client.add_compute_plan(compute_plan_data) + print(colored(json.dumps(res, indent=2), 'green')) + except: # noqa: E722 + print(colored('Could not create compute plan', 'red')) + if __name__ == '__main__': try: diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index d322a2d63..94bd1e751 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -1,3 +1,12 @@ +""" +WARNING +======= + +DO NOT MANUALLY EDIT THIS FILE! + +It is generated using substrapp/tests/generate_assets.py +""" + objective = [ { "key": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", @@ -8,10 +17,10 @@ }, "metrics": { "name": "macro-average recall", - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" }, - "owner": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", + "owner": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", "testDataset": None, "permissions": "all" }, @@ -24,10 +33,10 @@ }, "metrics": { "name": "macro-average recall", - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" }, - "owner": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", + "owner": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", "testDataset": { "dataManagerKey": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "dataSampleKeys": [ @@ -44,38 +53,52 @@ { "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "description": { - "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", - "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" + "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" }, - "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "name": "ISIC 2018", + "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "name": "Simplified ISIC 2018", "opener": { - "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" + "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" }, - "owner": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "owner": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", "permissions": "all", "type": "Images" }, { "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "description": { - "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", - "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" + "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" }, - "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "name": "Simplified ISIC 2018", + "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "name": "ISIC 2018", "opener": { - "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" + "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" }, - "owner": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", + "owner": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "permissions": "all", "type": "Images" } ] algo = [ + { + "key": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "name": "Logistic regression", + "content": { + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "description": { + "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" + }, + "owner": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", + "permissions": "all" + }, { "key": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "name": "Neural Network", @@ -87,7 +110,7 @@ "hash": "b9463411a01ea00869bdffce6e59a5c100a4e635c0a9386266cad3c77eb28e9e", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/description/" }, - "owner": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "owner": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "permissions": "all" }, { @@ -101,36 +124,22 @@ "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" }, - "owner": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", - "permissions": "all" - }, - { - "key": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "name": "Logistic regression", - "content": { - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "description": { - "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" - }, - "owner": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", + "owner": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "permissions": "all" } ] traintuple = [ { - "key": "8e8c724a3308b81b01f69ea96da80bac9cd5c2f31d08f54531da17aa1a8cca7e", + "key": "e7120600f8d6076fea588e162fcead50c0c7b9108e73292050f8fecf0b94d9c7", "algo": { "name": "Neural Network", "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" }, - "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "dataset": { - "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -138,13 +147,13 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, - "compute_plan_id": "", + "computePlanID": "", "inModels": None, - "log": "[00-01-0032-8a01ed9]", + "log": "[01-01-0014-5ace351]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, @@ -155,15 +164,51 @@ "tag": "My super tag" }, { - "key": "00227da7d49a20c228e0c10a3283891b9c0ded90685959cba55f0ba3f38123bb", + "key": "2ba521986dff869ead51cbdf7124393f25f993e3812f17a1c6c01c5f675e3d87", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "dataset": { + "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "2ba521986dff869ead51cbdf7124393f25f993e3812f17a1c6c01c5f675e3d87", + "inModels": None, + "log": "Train - CPU:141.55 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "fc852535c12278e406c4d00e4f57a53f66cb1ca5b7ec08cffedea31aa0e563a5", + "storageAddress": "http://testserver/model/fc852535c12278e406c4d00e4f57a53f66cb1ca5b7ec08cffedea31aa0e563a5/file/" + }, + "permissions": "all", + "rank": 0, + "status": "done", + "tag": "" + }, + { + "key": "3945fe491ed81ff7c83b27464a91a86989bb1bbdf21665fb9e83f122e6069206", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, - "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "dataset": { - "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -171,19 +216,19 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "compute_plan_id": "", + "computePlanID": "", "inModels": None, - "log": "Train - CPU:268.84 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Train - CPU:118.08 % - Mem:0.12 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717", - "storageAddress": "http://testserver/model/a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717/file/" + "hash": "0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f", + "storageAddress": "http://testserver/model/0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f/file/" }, "permissions": "all", "rank": 0, @@ -191,15 +236,15 @@ "tag": "substra" }, { - "key": "6ac5dc6f51bf793248b18906171f3133cf24eb04e2fd0bafa3f86ff9b518c886", + "key": "80d7a55b7cbd0abc5d930e904abef2bf03e66172c70e3c0039e66fe0dd9a5b76", "algo": { "name": "Random Forest", "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, - "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "dataset": { - "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -207,13 +252,13 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, - "compute_plan_id": "", + "computePlanID": "", "inModels": None, - "log": "[00-01-0032-4647065]", + "log": "[01-01-0014-9910bb3]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, @@ -227,16 +272,16 @@ testtuple = [ { - "key": "8fbcd8f301447c73e7cfd0afac9dca9300d6fc948060af588de02c8ca946ffc0", + "key": "58689879e90637827cb190198c3fad60d806a80bd56a6e9091dccf5b7f962cf2", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, "certified": True, - "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "dataset": { - "worker": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", + "worker": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", "keys": [ "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" @@ -244,37 +289,37 @@ "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "perf": 0 }, - "log": "Test - CPU:0.00 % - Mem:0.00 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Test - CPU:79.95 % - Mem:0.10 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "model": { - "traintupleKey": "00227da7d49a20c228e0c10a3283891b9c0ded90685959cba55f0ba3f38123bb", - "hash": "a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717", - "storageAddress": "http://testserver/model/a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717/file/" + "traintupleKey": "3945fe491ed81ff7c83b27464a91a86989bb1bbdf21665fb9e83f122e6069206", + "hash": "0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f", + "storageAddress": "http://testserver/model/0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "permissions": "all", "status": "done", - "tag": "" + "tag": "substra" } ] model = [ { "traintuple": { - "key": "8e8c724a3308b81b01f69ea96da80bac9cd5c2f31d08f54531da17aa1a8cca7e", + "key": "e7120600f8d6076fea588e162fcead50c0c7b9108e73292050f8fecf0b94d9c7", "algo": { "name": "Neural Network", "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" }, - "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "dataset": { - "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -282,13 +327,13 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, - "compute_plan_id": "", + "computePlanID": "", "inModels": None, - "log": "[00-01-0032-8a01ed9]", + "log": "[01-01-0014-5ace351]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, @@ -314,15 +359,66 @@ }, { "traintuple": { - "key": "00227da7d49a20c228e0c10a3283891b9c0ded90685959cba55f0ba3f38123bb", + "key": "2ba521986dff869ead51cbdf7124393f25f993e3812f17a1c6c01c5f675e3d87", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, - "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "dataset": { - "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "2ba521986dff869ead51cbdf7124393f25f993e3812f17a1c6c01c5f675e3d87", + "inModels": None, + "log": "Train - CPU:141.55 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "fc852535c12278e406c4d00e4f57a53f66cb1ca5b7ec08cffedea31aa0e563a5", + "storageAddress": "http://testserver/model/fc852535c12278e406c4d00e4f57a53f66cb1ca5b7ec08cffedea31aa0e563a5/file/" + }, + "permissions": "all", + "rank": 0, + "status": "done", + "tag": "" + }, + "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "permissions": "", + "status": "", + "tag": "" + } + }, + { + "traintuple": { + "key": "3945fe491ed81ff7c83b27464a91a86989bb1bbdf21665fb9e83f122e6069206", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "dataset": { + "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -330,19 +426,19 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "compute_plan_id": "", + "computePlanID": "", "inModels": None, - "log": "Train - CPU:268.84 % - Mem:0.11 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Train - CPU:118.08 % - Mem:0.12 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717", - "storageAddress": "http://testserver/model/a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717/file/" + "hash": "0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f", + "storageAddress": "http://testserver/model/0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f/file/" }, "permissions": "all", "rank": 0, @@ -350,16 +446,16 @@ "tag": "substra" }, "testtuple": { - "key": "8fbcd8f301447c73e7cfd0afac9dca9300d6fc948060af588de02c8ca946ffc0", + "key": "58689879e90637827cb190198c3fad60d806a80bd56a6e9091dccf5b7f962cf2", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, "certified": True, - "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "dataset": { - "worker": "f745cba1182632bc7a0bed0bd9dac12abc33ed4120d840665c7405fa2719dc1e", + "worker": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", "keys": [ "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" @@ -367,35 +463,35 @@ "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "perf": 0 }, - "log": "Test - CPU:0.00 % - Mem:0.00 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Test - CPU:79.95 % - Mem:0.10 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "model": { - "traintupleKey": "00227da7d49a20c228e0c10a3283891b9c0ded90685959cba55f0ba3f38123bb", - "hash": "a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717", - "storageAddress": "http://testserver/model/a2a21351da7665e0fc37a2173e1f33fb9e217e9c46c279ec9a1895e82ece6717/file/" + "traintupleKey": "3945fe491ed81ff7c83b27464a91a86989bb1bbdf21665fb9e83f122e6069206", + "hash": "0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f", + "storageAddress": "http://testserver/model/0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "permissions": "all", "status": "done", - "tag": "" + "tag": "substra" } }, { "traintuple": { - "key": "6ac5dc6f51bf793248b18906171f3133cf24eb04e2fd0bafa3f86ff9b518c886", + "key": "80d7a55b7cbd0abc5d930e904abef2bf03e66172c70e3c0039e66fe0dd9a5b76", "algo": { "name": "Random Forest", "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, - "creator": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "dataset": { - "worker": "9d62c8eb34f3cb04c15e1d893afd3639dbc6a2491f5115856a98c10c256a034e", + "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -403,13 +499,13 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 0 }, - "compute_plan_id": "", + "computePlanID": "", "inModels": None, - "log": "[00-01-0032-4647065]", + "log": "[01-01-0014-9910bb3]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "c42dca31fbc2ebb5705643e3bb6ee666bbfd956de13dd03727f825ad8445b4d7", + "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, diff --git a/substrabac/substrapp/tests/generate_assets.py b/substrabac/substrapp/tests/generate_assets.py index 40dd7bb1d..eb2bf5738 100644 --- a/substrabac/substrapp/tests/generate_assets.py +++ b/substrabac/substrapp/tests/generate_assets.py @@ -10,9 +10,9 @@ def main(): client = Client() - client.create_config('owkin', 'http://owkin.substrabac:8000', '0.0') + client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0') - client.set_config('owkin') + client.set_profile('owkin') assets = {} assets['objective'] = json.dumps(client.list_objective(), indent=4) @@ -21,10 +21,12 @@ def main(): assets['traintuple'] = json.dumps(client.list_traintuple(), indent=4) assets['testtuple'] = json.dumps(client.list_testtuple(), indent=4) - assets['model'] = json.dumps([res for res in client._list('model') + assets['model'] = json.dumps([res for res in client.client.list('model') if ('traintuple' in res and 'testtuple' in res)], indent=4) with open(assets_path, 'w') as f: + f.write('"""\nWARNING\n=======\n\nDO NOT MANUALLY EDIT THIS FILE!\n\n' + 'It is generated using substrapp/tests/generate_assets.py\n"""\n\n') for k, v in assets.items(): v = v.replace('owkin.substrabac:8000', 'testserver') v = v.replace('chunantes.substrabac:8001', 'testserver') diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index 04fbb0602..e12d1f799 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -90,7 +90,7 @@ def test_algo_list_filter_dual(self): mquery_ledger.return_value = algo search_params = '?search=algo%253Aname%253ALogistic%2520regression' - search_params += f'%2Calgo%253Aowner%253A{algo[2]["owner"]}' + search_params += f'%2Calgo%253Aowner%253A{algo[0]["owner"]}' response = self.client.get(url + search_params, **self.extra) r = response.json() diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substrabac/substrapp/tests/views/tests_views_model.py index 27dda4a35..c6f5f8e57 100644 --- a/substrabac/substrapp/tests/views/tests_views_model.py +++ b/substrabac/substrapp/tests/views/tests_views_model.py @@ -92,7 +92,7 @@ def test_model_list_filter_datamanager(self): response = self.client.get(url + search_params, **self.extra) r = response.json() - self.assertEqual(len(r[0]), 3) + self.assertEqual(len(r[0]), 4) def test_model_list_filter_objective(self): url = reverse('substrapp:model-list') @@ -105,7 +105,7 @@ def test_model_list_filter_objective(self): response = self.client.get(url + search_params, **self.extra) r = response.json() - self.assertEqual(len(r[0]), 3) + self.assertEqual(len(r[0]), 4) def test_model_list_filter_algo(self): url = reverse('substrapp:model-list') @@ -118,7 +118,7 @@ def test_model_list_filter_algo(self): response = self.client.get(url + search_params, **self.extra) r = response.json() - self.assertEqual(len(r[0]), 1) + self.assertEqual(len(r[0]), 2) def test_model_retrieve(self): diff --git a/substrabac/substrapp/tests/views/tests_views_tuples.py b/substrabac/substrapp/tests/views/tests_views_tuples.py index e03c77fba..e8e3e646c 100644 --- a/substrabac/substrapp/tests/views/tests_views_tuples.py +++ b/substrabac/substrapp/tests/views/tests_views_tuples.py @@ -22,6 +22,14 @@ MEDIA_ROOT = "/tmp/unittests_views/" +def get_compute_plan_id(assets): + for asset in assets: + compute_plan_id = asset.get('computePlanID') + if compute_plan_id: + return compute_plan_id + raise Exception('Could not find a compute plan ID') + + # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @@ -52,7 +60,7 @@ def test_traintuple_queryset(self): def test_traintuple_list_empty(self): url = reverse('substrapp:traintuple-list') with mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: - mquery_ledger.return_value = [[]] + mquery_ledger.return_value = [] response = self.client.get(url, **self.extra) r = response.json() @@ -93,6 +101,28 @@ def test_traintuple_retrieve_fail(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + def test_traintuple_list_filter_tag(self): + url = reverse('substrapp:traintuple-list') + with mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: + mquery_ledger.return_value = traintuple + + search_params = '?search=traintuple%253Atag%253Asubstra' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + def test_traintuple_list_filter_compute_plan_id(self): + url = reverse('substrapp:traintuple-list') + with mock.patch('substrapp.views.traintuple.query_ledger') as mquery_ledger: + mquery_ledger.return_value = traintuple + compute_plan_id = get_compute_plan_id(traintuple) + search_params = f'?search=traintuple%253AcomputePlanID%253A{compute_plan_id}' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) @@ -124,7 +154,7 @@ def test_testtuple_queryset(self): def test_testtuple_list_empty(self): url = reverse('substrapp:testtuple-list') with mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: - mquery_ledger.return_value = [[]] + mquery_ledger.return_value = [] response = self.client.get(url, **self.extra) r = response.json() @@ -164,3 +194,20 @@ def test_testtuple_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_testtuple_list_filter_tag(self): + url = reverse('substrapp:testtuple-list') + with mock.patch('substrapp.views.testtuple.query_ledger') as mquery_ledger: + mquery_ledger.return_value = testtuple + + search_params = '?search=testtuple%253Atag%253Asubstra' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 1) + + search_params = '?search=testtuple%253Atag%253Afoo' + response = self.client.get(url + search_params, **self.extra) + r = response.json() + + self.assertEqual(len(r[0]), 0) diff --git a/substrabac/substrapp/views/filters_utils.py b/substrabac/substrapp/views/filters_utils.py index 682e9b39c..509c17825 100644 --- a/substrabac/substrapp/views/filters_utils.py +++ b/substrabac/substrapp/views/filters_utils.py @@ -15,6 +15,8 @@ 'algo': ['model', 'algo'], 'objective': ['model', 'dataset', 'objective'], 'model': ['model', 'algo', 'dataset', 'objective'], + 'traintuple': ['traintuple'], + 'testtuple': ['testtuple'], } @@ -89,7 +91,7 @@ def filter_list(object_type, data, query_params): else: for attribute, val in subfilters.items(): - filtered_list = [x for x in filtered_list if x[attribute] in val] + filtered_list = [x for x in filtered_list if x.get(attribute) in val] else: # Filter by other asset diff --git a/substrabac/substrapp/views/testtuple.py b/substrabac/substrapp/views/testtuple.py index 4f06a7929..6cff7cf18 100644 --- a/substrabac/substrapp/views/testtuple.py +++ b/substrabac/substrapp/views/testtuple.py @@ -1,9 +1,12 @@ +import logging + from rest_framework import mixins, status from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from substrapp.serializers import LedgerTestTupleSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerConflict +from substrapp.views.filters_utils import filter_list from substrapp.views.utils import validate_pk, get_success_create_code, LedgerException @@ -68,7 +71,25 @@ def list(self, request, *args, **kwargs): data = query_ledger(fcn='queryTesttuples', args=[]) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - return Response(data, status=status.HTTP_200_OK) + + testtuple_list = [data] + + query_params = request.query_params.get('search', None) + if query_params is not None: + try: + testtuple_list = filter_list( + object_type='testtuple', + data=data, + query_params=query_params) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + except Exception as e: + logging.exception(e) + return Response( + {'message': f'Malformed search filters {query_params}'}, + status=status.HTTP_400_BAD_REQUEST) + + return Response(testtuple_list, status=status.HTTP_200_OK) def _retrieve(self, pk): validate_pk(pk) diff --git a/substrabac/substrapp/views/traintuple.py b/substrabac/substrapp/views/traintuple.py index 93ed768dd..e637448d4 100644 --- a/substrabac/substrapp/views/traintuple.py +++ b/substrabac/substrapp/views/traintuple.py @@ -1,9 +1,12 @@ +import logging + from rest_framework import mixins, status from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from substrapp.serializers import LedgerTrainTupleSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerConflict +from substrapp.views.filters_utils import filter_list from substrapp.views.utils import validate_pk, get_success_create_code, LedgerException @@ -73,7 +76,25 @@ def list(self, request, *args, **kwargs): data = query_ledger(fcn='queryTraintuples', args=[]) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) - return Response(data, status=status.HTTP_200_OK) + + traintuple_list = [data] + + query_params = request.query_params.get('search', None) + if query_params is not None: + try: + traintuple_list = filter_list( + object_type='traintuple', + data=data, + query_params=query_params) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + except Exception as e: + logging.exception(e) + return Response( + {'message': f'Malformed search filters {query_params}'}, + status=status.HTTP_400_BAD_REQUEST) + + return Response(traintuple_list, status=status.HTTP_200_OK) def _retrieve(self, pk): validate_pk(pk) From 7b3795816a2248193bc98134650adcdbd5a3dd05 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 12 Sep 2019 13:47:14 +0200 Subject: [PATCH 270/457] fix-views-get-permissions --- substrabac/substrapp/views/algo.py | 2 +- substrabac/substrapp/views/datamanager.py | 2 +- substrabac/substrapp/views/objective.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index a3ae52059..1270d683d 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -40,7 +40,7 @@ def commit(self, serializer, request): # single HTTP request 'permissions': { 'public': request.data.get('permissions_public'), - 'authorized_ids': request.data.get('permissions_authorized_ids', []), + 'authorized_ids': request.data.getlist('permissions_authorized_ids', []), }, } diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index b32cb6141..91c5679cf 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -59,7 +59,7 @@ def commit(self, serializer, request): # single HTTP request 'permissions': { 'public': request.data.get('permissions_public'), - 'authorized_ids': request.data.get('permissions_authorized_ids', []), + 'authorized_ids': request.data.getlist('permissions_authorized_ids', []), }, 'type': request.data.get('type'), 'objective_keys': request.data.getlist('objective_keys'), diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index f2960d1a3..400221d99 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -87,7 +87,7 @@ def commit(self, serializer, request): # single HTTP request 'permissions': { 'public': request.data.get('permissions_public'), - 'authorized_ids': request.data.get('permissions_authorized_ids', []), + 'authorized_ids': request.data.getlist('permissions_authorized_ids', []), }, 'metrics_name': request.data.get('metrics_name'), } From b56f3b3cfc758b371eda303e85421813dbf903fe Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Fri, 13 Sep 2019 18:16:25 +0200 Subject: [PATCH 271/457] Disable flower deployment in case we set flower.enabled --- charts/substrabac/Chart.yaml | 2 +- charts/substrabac/templates/deployment-flower.yaml | 2 ++ charts/substrabac/templates/service-flower.yaml | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml index 70ae60f1e..bae2870a1 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substrabac/Chart.yaml @@ -1,6 +1,6 @@ name: substrabac home: https://substra.org/ -version: 1.0.0-alpha.1 +version: 1.0.0-alpha.2 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: diff --git a/charts/substrabac/templates/deployment-flower.yaml b/charts/substrabac/templates/deployment-flower.yaml index 325f5da8f..a3b282f64 100644 --- a/charts/substrabac/templates/deployment-flower.yaml +++ b/charts/substrabac/templates/deployment-flower.yaml @@ -1,3 +1,4 @@ +{{- if .Values.flower.enabled -}} apiVersion: apps/v1 kind: Deployment metadata: @@ -55,3 +56,4 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} +{{- end }} diff --git a/charts/substrabac/templates/service-flower.yaml b/charts/substrabac/templates/service-flower.yaml index 66f68133c..5fd9a33cf 100644 --- a/charts/substrabac/templates/service-flower.yaml +++ b/charts/substrabac/templates/service-flower.yaml @@ -1,3 +1,4 @@ +{{- if .Values.flower.enabled -}} apiVersion: v1 kind: Service metadata: @@ -48,3 +49,4 @@ spec: selector: app.kubernetes.io/name: {{ template "substra.name" . }}-flower app.kubernetes.io/instance: {{ .Release.Name }} +{{-end }} From 9a9e965888fe632da72b4128856d193e9993fa86 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Fri, 13 Sep 2019 18:46:08 +0200 Subject: [PATCH 272/457] fixup --- charts/substrabac/templates/service-flower.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/substrabac/templates/service-flower.yaml b/charts/substrabac/templates/service-flower.yaml index 5fd9a33cf..2ac3a107f 100644 --- a/charts/substrabac/templates/service-flower.yaml +++ b/charts/substrabac/templates/service-flower.yaml @@ -49,4 +49,4 @@ spec: selector: app.kubernetes.io/name: {{ template "substra.name" . }}-flower app.kubernetes.io/instance: {{ .Release.Name }} -{{-end }} +{{- end }} From be5d1f0c8daad13c93512e0a75105a0a67444271 Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 11 Sep 2019 16:11:46 +0200 Subject: [PATCH 273/457] add job to create incoming/outgoing nodes --- .../templates/job-add-incoming-nodes.yaml | 130 ++++++++++++++++++ .../templates/job-add-outgoing-nodes.yaml | 130 ++++++++++++++++++ charts/substrabac/values.yaml | 11 +- substrabac/substrabac/settings/dev.py | 4 +- 4 files changed, 269 insertions(+), 6 deletions(-) create mode 100644 charts/substrabac/templates/job-add-incoming-nodes.yaml create mode 100644 charts/substrabac/templates/job-add-outgoing-nodes.yaml diff --git a/charts/substrabac/templates/job-add-incoming-nodes.yaml b/charts/substrabac/templates/job-add-incoming-nodes.yaml new file mode 100644 index 000000000..2717dac73 --- /dev/null +++ b/charts/substrabac/templates/job-add-incoming-nodes.yaml @@ -0,0 +1,130 @@ +{{- range .Values.incomingNodes }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "substra.fullname" $ }}-add-incoming-nodes +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: substrabac + image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" + imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" + command: ["/bin/bash"] + args: ["-c", "DJANGO_SETTINGS_MODULE=substrabac.settings.dev python3 manage.py create_incoming_node {{ .name }} {{ .secret }}"] + env: + - name: ORG + value: {{ $.Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ $.Values.organization.name }} + - name: SUBSTRABAC_{{ $.Values.organization.name | upper }}_DB_NAME + value: {{ $.Values.postgresql.postgresqlDatabase }} + - name: SUBSTRABAC_DB_USER + value: {{ $.Values.postgresql.postgresqlUsername }} + - name: SUBSTRABAC_DB_PWD + value: {{ $.Values.postgresql.postgresqlPassword }} + - name: DATABASE_HOST + value: {{ $.Release.Name }}-postgresql + - name: DJANGO_SETTINGS_MODULE + value: substrabac.settings.{{ $.Values.backend.settings }} + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric_cfg + - name: CORE_PEER_ADDRESS_ENV + value: "{{ $.Values.peer.host }}:{{ $.Values.peer.port }}" + - name: FABRIC_LOGGING_SPEC + value: debug + - name: DEFAULT_DOMAIN + value: "{{ $.Values.backend.defaultDomain }}" + - name: CELERY_BROKER_URL + value: "amqp://{{ $.Values.rabbitmq.rabbitmq.username }}:{{ $.Values.rabbitmq.rabbitmq.password }}@{{ $.Release.Name }}-{{ $.Values.rabbitmq.host }}:{{ $.Values.rabbitmq.port }}//" + - name: BACK_AUTH_USER + value: {{ $.user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ $.password | quote }} + - name: SUBSTRABAC_DEFAULT_PORT + value: {{ $.Values.backend.service.port | quote}} + - name: SUBSTRABAC_PEER_PORT + value: "internal" + - name: LEDGER_CONFIG_FILE + value: /conf/{{ $.Values.organization.name }}/substrabac/conf.json + - name: PYTHONUNBUFFERED + value: "1" + - name: MEDIA_ROOT + value: {{ $.Values.persistence.hostPath }}/medias/ + volumeMounts: + - mountPath: {{ $.Values.persistence.hostPath }} + name: data + - mountPath: /conf/{{ $.Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/fabric_cfg + name: fabric + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" $ }} + - name: config + configMap: + name: {{ include "substra.fullname" $ }}-backend + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ $.Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ $.Values.secrets.key }} + - name: cacert + secret: + secretName: {{ $.Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ $.Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ $.Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ $.Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ $.Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ $.Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} +{{- end }} diff --git a/charts/substrabac/templates/job-add-outgoing-nodes.yaml b/charts/substrabac/templates/job-add-outgoing-nodes.yaml new file mode 100644 index 000000000..01cf4a0db --- /dev/null +++ b/charts/substrabac/templates/job-add-outgoing-nodes.yaml @@ -0,0 +1,130 @@ +{{- range .Values.outgoingNodes }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "substra.fullname" $ }}-add-outgoing-nodes +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: substrabac + image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" + imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" + command: ["/bin/bash"] + args: ["-c", "DJANGO_SETTINGS_MODULE=substrabac.settings.dev python3 manage.py create_outgoing_node {{ .name }} {{ .secret }}"] + env: + - name: ORG + value: {{ $.Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ $.Values.organization.name }} + - name: SUBSTRABAC_{{ $.Values.organization.name | upper }}_DB_NAME + value: {{ $.Values.postgresql.postgresqlDatabase }} + - name: SUBSTRABAC_DB_USER + value: {{ $.Values.postgresql.postgresqlUsername }} + - name: SUBSTRABAC_DB_PWD + value: {{ $.Values.postgresql.postgresqlPassword }} + - name: DATABASE_HOST + value: {{ $.Release.Name }}-postgresql + - name: DJANGO_SETTINGS_MODULE + value: substrabac.settings.{{ $.Values.backend.settings }} + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric_cfg + - name: CORE_PEER_ADDRESS_ENV + value: "{{ $.Values.peer.host }}:{{ $.Values.peer.port }}" + - name: FABRIC_LOGGING_SPEC + value: debug + - name: DEFAULT_DOMAIN + value: "{{ $.Values.backend.defaultDomain }}" + - name: CELERY_BROKER_URL + value: "amqp://{{ $.Values.rabbitmq.rabbitmq.username }}:{{ $.Values.rabbitmq.rabbitmq.password }}@{{ $.Release.Name }}-{{ $.Values.rabbitmq.host }}:{{ $.Values.rabbitmq.port }}//" + - name: BACK_AUTH_USER + value: {{ $.user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ $.password | quote }} + - name: SUBSTRABAC_DEFAULT_PORT + value: {{ $.Values.backend.service.port | quote}} + - name: SUBSTRABAC_PEER_PORT + value: "internal" + - name: LEDGER_CONFIG_FILE + value: /conf/{{ $.Values.organization.name }}/substrabac/conf.json + - name: PYTHONUNBUFFERED + value: "1" + - name: MEDIA_ROOT + value: {{ $.Values.persistence.hostPath }}/medias/ + volumeMounts: + - mountPath: {{ $.Values.persistence.hostPath }} + name: data + - mountPath: /conf/{{ $.Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/fabric_cfg + name: fabric + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" $ }} + - name: config + configMap: + name: {{ include "substra.fullname" $ }}-backend + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ $.Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ $.Values.secrets.key }} + - name: cacert + secret: + secretName: {{ $.Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ $.Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ $.Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ $.Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ $.Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ $.Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} +{{- end }} diff --git a/charts/substrabac/values.yaml b/charts/substrabac/values.yaml index a378b576d..636c8ac3e 100644 --- a/charts/substrabac/values.yaml +++ b/charts/substrabac/values.yaml @@ -21,10 +21,10 @@ backend: loadBalancerSourceRanges: [] # nodePort: 30000 - auth: {} - # user: owkward - # password: H9YJh7znjhoje3 - # header: "Basic b3drd2FyZDpIOVlKaDd6bmpob2plMw==" + auth: + user: owkward + password: H9YJh7znjhoje3 + header: "Basic b3drd2FyZDpIOVlKaDd6bmpob2plMw==" ingress: enabled: false @@ -52,6 +52,9 @@ backend: # cpu: 100m # memory: 128Mi +outgoingNodes: [] +incomingNodes: [] + persistence: hostPath: "/substra" size: "10Gi" diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index a56cf8d44..5db4539e2 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -7,8 +7,8 @@ from .deps.restframework import * -BASICAUTH_USERNAME = "admin" -BASICAUTH_PASSWORD = "admin" +BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER', 'admin') +BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', 'admin') DEBUG = True From eacc7cda2630121b765d26ae94b64d279e8bcd4d Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 11 Sep 2019 22:33:43 +0200 Subject: [PATCH 274/457] charts: do not set auth as default values --- charts/substrabac/values.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/substrabac/values.yaml b/charts/substrabac/values.yaml index 636c8ac3e..93380af04 100644 --- a/charts/substrabac/values.yaml +++ b/charts/substrabac/values.yaml @@ -21,10 +21,10 @@ backend: loadBalancerSourceRanges: [] # nodePort: 30000 - auth: - user: owkward - password: H9YJh7znjhoje3 - header: "Basic b3drd2FyZDpIOVlKaDd6bmpob2plMw==" + auth: {} + # user: owkward + # password: H9YJh7znjhoje3 + # header: "Basic b3drd2FyZDpIOVlKaDd6bmpob2plMw==" ingress: enabled: false From c95b57215ecb5f80fd2787aa25938b44a387449c Mon Sep 17 00:00:00 2001 From: Samuel Date: Wed, 11 Sep 2019 23:12:51 +0200 Subject: [PATCH 275/457] populate: add basic auth for skaffold --- populate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/populate.py b/populate.py index 7b7a52f50..f459e74dd 100644 --- a/populate.py +++ b/populate.py @@ -33,11 +33,11 @@ def setup_config(network='docker'): user=USER, password=PASSWORD) if network == 'skaffold': client.add_profile('owkin', 'http://substrabac.node-1', '0.0', - user=USER, password=PASSWORD) + user='peer1', password='baz') client.add_profile('chunantes', 'http://substrabac.node-2', '0.0', - user=USER, password=PASSWORD) + user='peer2', password='baz') client.add_profile('clb', 'http://substrabac.node-3', '0.0', - user=USER, password=PASSWORD) + user='peer3', password='baz') def zip_folder(path, destination): From d7fc2e8b150264aabfd627d0785821d3694e1a39 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 12 Sep 2019 10:44:49 +0200 Subject: [PATCH 276/457] apply changes to charts --- .../templates/job-add-incoming-nodes.yaml | 14 ++++++++++---- .../templates/job-add-outgoing-nodes.yaml | 14 ++++++++++---- charts/substrabac/values.yaml | 4 ++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/charts/substrabac/templates/job-add-incoming-nodes.yaml b/charts/substrabac/templates/job-add-incoming-nodes.yaml index 2717dac73..e7d5d490c 100644 --- a/charts/substrabac/templates/job-add-incoming-nodes.yaml +++ b/charts/substrabac/templates/job-add-incoming-nodes.yaml @@ -1,8 +1,14 @@ -{{- range .Values.incomingNodes }} +{{- range $index, $value := .Values.incomingNodes }} apiVersion: batch/v1 kind: Job metadata: - name: {{ template "substra.fullname" $ }}-add-incoming-nodes + name: {{ template "substra.fullname" $ }}-add-incoming-nodes-{{ $index }} + labels: + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" $ }}-backend + app.kubernetes.io/part-of: {{ template "substra.name" $ }} spec: template: spec: @@ -11,8 +17,8 @@ spec: - name: substrabac image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" - command: ["/bin/bash"] - args: ["-c", "DJANGO_SETTINGS_MODULE=substrabac.settings.dev python3 manage.py create_incoming_node {{ .name }} {{ .secret }}"] + command: ["python3"] + args: ["manage.py", "create_incoming_node", {{ .name }}, {{ .secret }}] env: - name: ORG value: {{ $.Values.organization.name }} diff --git a/charts/substrabac/templates/job-add-outgoing-nodes.yaml b/charts/substrabac/templates/job-add-outgoing-nodes.yaml index 01cf4a0db..242610b99 100644 --- a/charts/substrabac/templates/job-add-outgoing-nodes.yaml +++ b/charts/substrabac/templates/job-add-outgoing-nodes.yaml @@ -1,8 +1,14 @@ -{{- range .Values.outgoingNodes }} +{{- range $index, $value := .Values.outgoingNodes }} apiVersion: batch/v1 kind: Job metadata: - name: {{ template "substra.fullname" $ }}-add-outgoing-nodes + name: {{ template "substra.fullname" $ }}-add-outgoing-nodes-{{ $index }} + labels: + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" $ }}-backend + app.kubernetes.io/part-of: {{ template "substra.name" $ }} spec: template: spec: @@ -11,8 +17,8 @@ spec: - name: substrabac image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" - command: ["/bin/bash"] - args: ["-c", "DJANGO_SETTINGS_MODULE=substrabac.settings.dev python3 manage.py create_outgoing_node {{ .name }} {{ .secret }}"] + command: ["python3"] + args: ["manage.py", "create_outgoing_node", {{ .name }}, {{ .secret }}] env: - name: ORG value: {{ $.Values.organization.name }} diff --git a/charts/substrabac/values.yaml b/charts/substrabac/values.yaml index 93380af04..8360d1b1a 100644 --- a/charts/substrabac/values.yaml +++ b/charts/substrabac/values.yaml @@ -53,7 +53,11 @@ backend: # memory: 128Mi outgoingNodes: [] + # - name: nodeId + # secret: nodeSecret incomingNodes: [] + # - name: nodeId + # secret: nodeSecret persistence: hostPath: "/substra" From 100827945eb2e88c3e5a2af22b7848d6fa2a9d38 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 12 Sep 2019 11:23:04 +0200 Subject: [PATCH 277/457] settings: set default user/password to dev in dev --- substrabac/substrabac/settings/dev.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 5db4539e2..39e9ad652 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -7,8 +7,8 @@ from .deps.restframework import * -BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER', 'admin') -BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', 'admin') +BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER', 'dev') +BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', 'dev') DEBUG = True From 06827f6a8fabf188d4876c3a13448798f10be967 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 12 Sep 2019 13:11:45 +0200 Subject: [PATCH 278/457] add comment in populate --- populate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/populate.py b/populate.py index f459e74dd..7704c9700 100644 --- a/populate.py +++ b/populate.py @@ -32,6 +32,7 @@ def setup_config(network='docker'): client.add_profile('clb', 'http://clb.substrabac:8002', '0.0', user=USER, password=PASSWORD) if network == 'skaffold': + # the usernames and passwords are defined in the skaffold.yaml file client.add_profile('owkin', 'http://substrabac.node-1', '0.0', user='peer1', password='baz') client.add_profile('chunantes', 'http://substrabac.node-2', '0.0', From 613ab806d12a7443e606aebca403d5ab3937e9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gautier?= Date: Thu, 12 Sep 2019 13:42:45 +0200 Subject: [PATCH 279/457] Update charts/substrabac/templates/job-add-incoming-nodes.yaml --- charts/substrabac/templates/job-add-incoming-nodes.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/substrabac/templates/job-add-incoming-nodes.yaml b/charts/substrabac/templates/job-add-incoming-nodes.yaml index e7d5d490c..c604fd61a 100644 --- a/charts/substrabac/templates/job-add-incoming-nodes.yaml +++ b/charts/substrabac/templates/job-add-incoming-nodes.yaml @@ -7,7 +7,7 @@ metadata: app.kubernetes.io/managed-by: {{ $.Release.Service }} app.kubernetes.io/instance: {{ $.Release.Name }} helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} - app.kubernetes.io/name: {{ template "substra.name" $ }}-backend + app.kubernetes.io/name: {{ template "substra.name" $ }}-add-incoming-nodes-{{ $index }} app.kubernetes.io/part-of: {{ template "substra.name" $ }} spec: template: From 779f79699afefaef79277474f7191df34e450ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gautier?= Date: Thu, 12 Sep 2019 13:42:52 +0200 Subject: [PATCH 280/457] Update charts/substrabac/templates/job-add-outgoing-nodes.yaml --- charts/substrabac/templates/job-add-outgoing-nodes.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/substrabac/templates/job-add-outgoing-nodes.yaml b/charts/substrabac/templates/job-add-outgoing-nodes.yaml index 242610b99..fd5ab5aa0 100644 --- a/charts/substrabac/templates/job-add-outgoing-nodes.yaml +++ b/charts/substrabac/templates/job-add-outgoing-nodes.yaml @@ -7,7 +7,7 @@ metadata: app.kubernetes.io/managed-by: {{ $.Release.Service }} app.kubernetes.io/instance: {{ $.Release.Name }} helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} - app.kubernetes.io/name: {{ template "substra.name" $ }}-backend + app.kubernetes.io/name: {{ template "substra.name" $ }}-add-outgoing-nodes-{{ $index }} app.kubernetes.io/part-of: {{ template "substra.name" $ }} spec: template: From 83aed6dd570f467183df7f92b5fa77022c685dd2 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 13 Sep 2019 11:03:56 +0200 Subject: [PATCH 281/457] Change credentials values --- populate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/populate.py b/populate.py index 7704c9700..e1ffebf4b 100644 --- a/populate.py +++ b/populate.py @@ -34,11 +34,11 @@ def setup_config(network='docker'): if network == 'skaffold': # the usernames and passwords are defined in the skaffold.yaml file client.add_profile('owkin', 'http://substrabac.node-1', '0.0', - user='peer1', password='baz') + user='node-1', password='node-1pwd') client.add_profile('chunantes', 'http://substrabac.node-2', '0.0', - user='peer2', password='baz') + user='node-2', password='node-2pwd') client.add_profile('clb', 'http://substrabac.node-3', '0.0', - user='peer3', password='baz') + user='node-3', password='node-3pwd') def zip_folder(path, destination): From 6598a4f99bd87ccf27b9e9c01270d3620a88bb8e Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Mon, 16 Sep 2019 10:07:17 +0200 Subject: [PATCH 282/457] Bump version --- charts/substrabac/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml index bae2870a1..98490e0a4 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substrabac/Chart.yaml @@ -1,6 +1,6 @@ name: substrabac home: https://substra.org/ -version: 1.0.0-alpha.2 +version: 1.0.0-alpha.3 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: From 17a13f7ab76268e400953d6812ddc0ff8ca214d0 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Mon, 16 Sep 2019 13:19:58 +0200 Subject: [PATCH 283/457] Fixup issue with auth job --- charts/substrabac/Chart.yaml | 2 +- charts/substrabac/templates/deployment-backend.yaml | 1 - charts/substrabac/templates/job-add-incoming-nodes.yaml | 7 +++++++ charts/substrabac/templates/job-add-outgoing-nodes.yaml | 7 +++++++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml index 98490e0a4..0b0cdb171 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substrabac/Chart.yaml @@ -1,6 +1,6 @@ name: substrabac home: https://substra.org/ -version: 1.0.0-alpha.3 +version: 1.0.0-alpha.4 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: diff --git a/charts/substrabac/templates/deployment-backend.yaml b/charts/substrabac/templates/deployment-backend.yaml index 8e0bba1bb..ed198562c 100644 --- a/charts/substrabac/templates/deployment-backend.yaml +++ b/charts/substrabac/templates/deployment-backend.yaml @@ -33,7 +33,6 @@ spec: imagePullPolicy: "{{ .Values.backend.image.pullPolicy }}" {{- end }} command: ["/bin/bash"] - {{- if eq .Values.backend.settings "prod" }} args: ["-c", "sed -i '7d' substrabac/settings/prod.py; python manage.py migrate; touch /ready; python3 manage.py collectstatic --noinput; DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} uwsgi --http :8000 --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes 2 --threads 2"] {{- else }} diff --git a/charts/substrabac/templates/job-add-incoming-nodes.yaml b/charts/substrabac/templates/job-add-incoming-nodes.yaml index c604fd61a..6f349e7e0 100644 --- a/charts/substrabac/templates/job-add-incoming-nodes.yaml +++ b/charts/substrabac/templates/job-add-incoming-nodes.yaml @@ -1,4 +1,5 @@ {{- range $index, $value := .Values.incomingNodes }} +--- apiVersion: batch/v1 kind: Job metadata: @@ -13,6 +14,12 @@ spec: template: spec: restartPolicy: OnFailure + {{- with $.Values.backend.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} containers: - name: substrabac image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" diff --git a/charts/substrabac/templates/job-add-outgoing-nodes.yaml b/charts/substrabac/templates/job-add-outgoing-nodes.yaml index fd5ab5aa0..8b0bf5649 100644 --- a/charts/substrabac/templates/job-add-outgoing-nodes.yaml +++ b/charts/substrabac/templates/job-add-outgoing-nodes.yaml @@ -1,4 +1,5 @@ {{- range $index, $value := .Values.outgoingNodes }} +--- apiVersion: batch/v1 kind: Job metadata: @@ -13,6 +14,12 @@ spec: template: spec: restartPolicy: OnFailure + {{- with $.Values.backend.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} containers: - name: substrabac image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" From 59bb4f0f0349a99b0fd488d556d85f3f5ac20e63 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 19 Sep 2019 11:19:16 +0200 Subject: [PATCH 284/457] Add missing model permissions views --- substrabac/substrapp/urls.py | 4 +++- substrabac/substrapp/views/__init__.py | 6 +++--- substrabac/substrapp/views/model.py | 10 +++++++++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index 62f12949e..0a892f0e0 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -7,7 +7,8 @@ from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ - ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet + ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet, \ + ModelPermissionViewSet # Create a router and register our viewsets with it. @@ -15,6 +16,7 @@ router.register(r'objective', ObjectiveViewSet, base_name='objective') router.register(r'objective', ObjectivePermissionViewSet, base_name='objective') router.register(r'model', ModelViewSet, base_name='model') +router.register(r'model', ModelPermissionViewSet, base_name='model') router.register(r'data_sample', DataSampleViewSet, base_name='data_sample') router.register(r'data_manager', DataManagerViewSet, base_name='data_manager') router.register(r'data_manager', DataManagerPermissionViewSet, base_name='data_manager') diff --git a/substrabac/substrapp/views/__init__.py b/substrabac/substrapp/views/__init__.py index 6f3ef8758..54a7b8a79 100644 --- a/substrabac/substrapp/views/__init__.py +++ b/substrabac/substrapp/views/__init__.py @@ -3,7 +3,7 @@ from .datasample import DataSampleViewSet from .datamanager import DataManagerViewSet, DataManagerPermissionViewSet from .objective import ObjectiveViewSet, ObjectivePermissionViewSet -from .model import ModelViewSet +from .model import ModelViewSet, ModelPermissionViewSet from .algo import AlgoViewSet, AlgoPermissionViewSet from .traintuple import TrainTupleViewSet from .testtuple import TestTupleViewSet @@ -11,5 +11,5 @@ from .computeplan import ComputePlanViewSet __all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'DataManagerPermissionViewSet', 'ObjectiveViewSet', - 'ObjectivePermissionViewSet', 'ModelViewSet', 'AlgoViewSet', 'AlgoPermissionViewSet', 'TrainTupleViewSet', - 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet'] + 'ObjectivePermissionViewSet', 'ModelViewSet', 'ModelPermissionViewSet', 'AlgoViewSet', + 'AlgoPermissionViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet'] diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 37ddcc68e..7175155ee 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -10,7 +10,7 @@ from substrapp.models import Model from substrapp.serializers import ModelSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError -from substrapp.views.utils import CustomFileResponse, validate_pk, get_remote_asset +from substrapp.views.utils import CustomFileResponse, validate_pk, get_remote_asset, PermissionMixin from substrapp.views.filters_utils import filter_list @@ -106,6 +106,14 @@ def list(self, request, *args, **kwargs): return Response(models_list, status=status.HTTP_200_OK) + +class ModelPermissionViewSet(PermissionMixin, + GenericViewSet): + + queryset = Model.objects.all() + serializer_class = ModelSerializer + ledger_query_call = 'queryModelDetails' + @action(detail=True) def file(self, request, *args, **kwargs): model_object = self.get_object() From f48a210e922b36c4b6a7e414d5686c2997f63886 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 20 Sep 2019 10:32:07 +0200 Subject: [PATCH 285/457] Fix settings prod to exit when app fails. Remove dirty sed and touch ready --- charts/substrabac/templates/deployment-backend.yaml | 4 ++-- docker/start.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/substrabac/templates/deployment-backend.yaml b/charts/substrabac/templates/deployment-backend.yaml index ed198562c..a82c0218c 100644 --- a/charts/substrabac/templates/deployment-backend.yaml +++ b/charts/substrabac/templates/deployment-backend.yaml @@ -34,9 +34,9 @@ spec: {{- end }} command: ["/bin/bash"] {{- if eq .Values.backend.settings "prod" }} - args: ["-c", "sed -i '7d' substrabac/settings/prod.py; python manage.py migrate; touch /ready; python3 manage.py collectstatic --noinput; DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} uwsgi --http :8000 --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes 2 --threads 2"] + args: ["-c", "python manage.py migrate; python3 manage.py collectstatic --noinput; uwsgi --http :8000 --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} "] {{- else }} - args: ["-c", "python manage.py migrate; touch /ready; DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] + args: ["-c", "python manage.py migrate; DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] {{- end }} env: - name: ORG diff --git a/docker/start.py b/docker/start.py index 442ff1014..57157e630 100644 --- a/docker/start.py +++ b/docker/start.py @@ -123,9 +123,9 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): if launch_settings == 'prod': django_server = f'python3 manage.py collectstatic --noinput; '\ - f'DJANGO_SETTINGS_MODULE=substrabac.settings.events.prod uwsgi --http :{port} ' \ f'--module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics ' \ - f'--master --processes {processes} --threads 2' + f'--master --processes {processes} --threads 2 --need-app' \ + f'--env DJANGO_SETTINGS_MODULE=substrabac.settings.events.prod uwsgi --http :{port} ' else: print('nobasicauth: ', nobasicauth, flush=True) extra_settings = '.nobasicauth' if nobasicauth is True else '' From 53f7345749d825f11b55e9e636301afa57402273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Fri, 20 Sep 2019 10:43:57 +0200 Subject: [PATCH 286/457] remove isic fixtures --- fixtures/isic_2018.py | 109 ------------------------------------------ 1 file changed, 109 deletions(-) delete mode 100644 fixtures/isic_2018.py diff --git a/fixtures/isic_2018.py b/fixtures/isic_2018.py deleted file mode 100644 index 1b1a923fc..000000000 --- a/fixtures/isic_2018.py +++ /dev/null @@ -1,109 +0,0 @@ -import os -import json -from subprocess import PIPE, Popen as popen -import time - -dir_path = os.path.dirname(os.path.realpath(__file__)) - -# Use substra shell SDK -try: - popen(['substra'], stdout=PIPE).communicate()[0] -except BaseException: - print('Substrabac SDK is not installed, please run pip install ' - 'git+https://github.com/SubstraFoundation/substrabacSDK.git@master') -else: - print('Init config in /tmp/.substrabac for owkin and chunantes') - username = "owkestra" - password = "owkestrapwd" - auth = [] - if username is not None and password is not None: - auth = [username, password] - res = popen(['substra', 'config', 'https://substra.owkin.com:9000', '0.0', - '--profile=owkin', '--config=/tmp/.substrabac'] + auth, - stdout=PIPE).communicate()[0] - - print('create data manager with owkin org') - # create data manager with owkin org - data = json.dumps({ - "name": "ISIC 2018", - "data_opener": "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/dataset/isic2018/opener.py", - "type": "Images", - "description": - "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/dataset/isic2018/description.md", - "permissions": "all", - "challenge_keys": [] - }) - - res = popen(['substra', 'add', 'datamanager', '--profile=owkin', '--config=/tmp/.substrabac', data], - stdout=PIPE).communicate()[0] - res_data = json.loads(res.decode('utf-8')) - datamanager_key = res_data['pkhash'] - print(json.dumps(res_data, indent=2)) - - # Register Data on substrabac docker - - print('You have to register data manually') - input("When it is done, press Enter to continue...") - - # register objective - print('register objective') - data = json.dumps({ - "name": "Skin Lesion Classification Objective", - "description": "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/description.md", - "metrics_name": "macro-average recall", - "metrics": "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/metrics.py", - "permissions": "all", - "test_data_sample_keys": ["039eecf8279c570022f000984d91e175ca8efbf858f11b8bffc88d91ccb51096"] - }) - - res = popen(['substra', 'add', 'objective', '--profile=owkin', '--config=/tmp/.substrabac', data], - stdout=PIPE).communicate()[0] - res_data = json.loads(res.decode('utf-8')) - objective_key = res_data['pkhash'] - print(json.dumps(res_data, indent=2)) - - # ############################ - - # register algo - print('register algo') - data = json.dumps({ - "name": "CNN Classifier GPU Updated", - "file": "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/algo/algo.tar.gz", - "description": "/Users/kelvin/Substra/substra-challenge/skin-lesion-classification/algo/description.md", - "objective_key": objective_key, - "permissions": "all", - }) - - res = popen(['substra', 'add', 'algo', '--profile=owkin', '--config=/tmp/.substrabac', data], - stdout=PIPE).communicate()[0] - res_data = json.loads(res.decode('utf-8')) - algo_key = res_data['pkhash'] - print(json.dumps(res_data, indent=2)) - - # #################################### - - # create traintuple - print('create traintuple') - data = json.dumps({ - "algo_key": algo_key, - "model_key": "", - "train_data_keys": ["33d577a1dbbf95c9cfccc4853ad7ca369b535243053f84a206308ad46e89aa59"] - }) - - res = popen(['substra', 'add', 'traintuple', '--profile=owkin', '--config=/tmp/.substrabac', data], - stdout=PIPE).communicate()[0] - res_data = json.loads(res.decode('utf-8')) - trainuple_key = res_data['pkhash'] - print(json.dumps(res_data, indent=2)) - - # Check traintuple - res = popen(['substra', 'get', 'traintuple', trainuple_key, '--profile=owkin', '--config=/tmp/.substrabac'], - stdout=PIPE).communicate()[0] - res = json.loads(res.decode('utf-8')) - print(json.dumps(res, indent=2)) - while res['status'] != 'done': - res = popen(['substra', 'get', 'traintuple', trainuple_key, '--profile=owkin', '--config=/tmp/.substrabac'], - stdout=PIPE).communicate()[0] - res = json.loads(res.decode('utf-8')) - print(json.dumps(res, indent=2)) - time.sleep(3) From e916e3d48765c2577996b869b097c89d627fc649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 23 Sep 2019 09:44:17 +0200 Subject: [PATCH 287/457] Update assets.py (#337) * update assets.py * keep asset relative order --- substrabac/substrapp/tests/assets.py | 275 +++++++++++------- substrabac/substrapp/tests/generate_assets.py | 6 +- 2 files changed, 180 insertions(+), 101 deletions(-) diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index 94bd1e751..4ddf536d0 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -5,6 +5,11 @@ DO NOT MANUALLY EDIT THIS FILE! It is generated using substrapp/tests/generate_assets.py + +In order to update this file: +1. start a clean instance of substra +2. run populate.py +3. run substrapp/tests/generate_assets.py """ objective = [ @@ -17,12 +22,17 @@ }, "metrics": { "name": "macro-average recall", - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" }, - "owner": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", + "owner": "owkinMSP", "testDataset": None, - "permissions": "all" + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } }, { "key": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -33,10 +43,10 @@ }, "metrics": { "name": "macro-average recall", - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" }, - "owner": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", + "owner": "owkinMSP", "testDataset": { "dataManagerKey": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "dataSampleKeys": [ @@ -45,7 +55,12 @@ ], "worker": "" }, - "permissions": "all" + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } } ] @@ -62,8 +77,13 @@ "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" }, - "owner": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", - "permissions": "all", + "owner": "owkinMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, "type": "Images" }, { @@ -78,8 +98,13 @@ "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" }, - "owner": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", - "permissions": "all", + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, "type": "Images" } ] @@ -96,8 +121,13 @@ "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" }, - "owner": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", - "permissions": "all" + "owner": "owkinMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } }, { "key": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", @@ -110,8 +140,13 @@ "hash": "b9463411a01ea00869bdffce6e59a5c100a4e635c0a9386266cad3c77eb28e9e", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/description/" }, - "owner": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", - "permissions": "all" + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } }, { "key": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", @@ -124,22 +159,27 @@ "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" }, - "owner": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", - "permissions": "all" + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } } ] traintuple = [ { - "key": "e7120600f8d6076fea588e162fcead50c0c7b9108e73292050f8fecf0b94d9c7", + "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", "algo": { "name": "Neural Network", "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" }, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "worker": "chu-nantesMSP", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -149,102 +189,117 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0014-5ace351]", + "log": "[01-01-0014-ff6df51]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": None, - "permissions": "all", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, "rank": 0, "status": "failed", "tag": "My super tag" }, { - "key": "2ba521986dff869ead51cbdf7124393f25f993e3812f17a1c6c01c5f675e3d87", + "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "worker": "chu-nantesMSP", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "computePlanID": "2ba521986dff869ead51cbdf7124393f25f993e3812f17a1c6c01c5f675e3d87", + "computePlanID": "", "inModels": None, - "log": "Train - CPU:141.55 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Train - CPU:98.65 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "fc852535c12278e406c4d00e4f57a53f66cb1ca5b7ec08cffedea31aa0e563a5", - "storageAddress": "http://testserver/model/fc852535c12278e406c4d00e4f57a53f66cb1ca5b7ec08cffedea31aa0e563a5/file/" + "hash": "8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27", + "storageAddress": "http://testserver/model/8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } }, - "permissions": "all", "rank": 0, "status": "done", - "tag": "" + "tag": "substra" }, { - "key": "3945fe491ed81ff7c83b27464a91a86989bb1bbdf21665fb9e83f122e6069206", + "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "worker": "chu-nantesMSP", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "computePlanID": "", + "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", "inModels": None, - "log": "Train - CPU:118.08 % - Mem:0.12 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Train - CPU:143.37 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f", - "storageAddress": "http://testserver/model/0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f/file/" + "hash": "a1e39305a1863d96cebec40bd2a0c016eead11a3037329628afe9bcc9a32da90", + "storageAddress": "http://testserver/model/a1e39305a1863d96cebec40bd2a0c016eead11a3037329628afe9bcc9a32da90/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } }, - "permissions": "all", "rank": 0, "status": "done", - "tag": "substra" + "tag": "" }, { - "key": "80d7a55b7cbd0abc5d930e904abef2bf03e66172c70e3c0039e66fe0dd9a5b76", + "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", "algo": { "name": "Random Forest", "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "worker": "chu-nantesMSP", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -254,16 +309,21 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0014-9910bb3]", + "log": "[01-01-0014-2dd325f]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": None, - "permissions": "all", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, "rank": 0, "status": "failed", "tag": "" @@ -272,16 +332,16 @@ testtuple = [ { - "key": "58689879e90637827cb190198c3fad60d806a80bd56a6e9091dccf5b7f962cf2", + "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, "certified": True, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", + "worker": "owkinMSP", "keys": [ "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" @@ -289,20 +349,19 @@ "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "perf": 0 }, - "log": "Test - CPU:79.95 % - Mem:0.10 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Test - CPU:144.06 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "model": { - "traintupleKey": "3945fe491ed81ff7c83b27464a91a86989bb1bbdf21665fb9e83f122e6069206", - "hash": "0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f", - "storageAddress": "http://testserver/model/0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f/file/" + "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "hash": "8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27", + "storageAddress": "http://testserver/model/8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, - "permissions": "all", "status": "done", "tag": "substra" } @@ -311,15 +370,15 @@ model = [ { "traintuple": { - "key": "e7120600f8d6076fea588e162fcead50c0c7b9108e73292050f8fecf0b94d9c7", + "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", "algo": { "name": "Neural Network", "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" }, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "worker": "chu-nantesMSP", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -329,16 +388,21 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0014-5ace351]", + "log": "[01-01-0014-ff6df51]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": None, - "permissions": "all", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, "rank": 0, "status": "failed", "tag": "My super tag" @@ -352,22 +416,21 @@ "log": "", "model": None, "objective": None, - "permissions": "", "status": "", "tag": "" } }, { "traintuple": { - "key": "2ba521986dff869ead51cbdf7124393f25f993e3812f17a1c6c01c5f675e3d87", + "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "worker": "chu-nantesMSP", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" @@ -375,21 +438,26 @@ "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "computePlanID": "2ba521986dff869ead51cbdf7124393f25f993e3812f17a1c6c01c5f675e3d87", + "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", "inModels": None, - "log": "Train - CPU:141.55 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Train - CPU:143.37 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "fc852535c12278e406c4d00e4f57a53f66cb1ca5b7ec08cffedea31aa0e563a5", - "storageAddress": "http://testserver/model/fc852535c12278e406c4d00e4f57a53f66cb1ca5b7ec08cffedea31aa0e563a5/file/" + "hash": "a1e39305a1863d96cebec40bd2a0c016eead11a3037329628afe9bcc9a32da90", + "storageAddress": "http://testserver/model/a1e39305a1863d96cebec40bd2a0c016eead11a3037329628afe9bcc9a32da90/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } }, - "permissions": "all", "rank": 0, "status": "done", "tag": "" @@ -403,22 +471,21 @@ "log": "", "model": None, "objective": None, - "permissions": "", "status": "", "tag": "" } }, { "traintuple": { - "key": "3945fe491ed81ff7c83b27464a91a86989bb1bbdf21665fb9e83f122e6069206", + "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "worker": "chu-nantesMSP", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -428,34 +495,39 @@ }, "computePlanID": "", "inModels": None, - "log": "Train - CPU:118.08 % - Mem:0.12 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Train - CPU:98.65 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f", - "storageAddress": "http://testserver/model/0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f/file/" + "hash": "8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27", + "storageAddress": "http://testserver/model/8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } }, - "permissions": "all", "rank": 0, "status": "done", "tag": "substra" }, "testtuple": { - "key": "58689879e90637827cb190198c3fad60d806a80bd56a6e9091dccf5b7f962cf2", + "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", "algo": { "name": "Logistic regression", "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" }, "certified": True, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "889f6de4a8405537d69c78442a7b8f0b1658c1ff62dc841d7c707e14cc0140a7", + "worker": "owkinMSP", "keys": [ "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" @@ -463,35 +535,34 @@ "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "perf": 0 }, - "log": "Test - CPU:79.95 % - Mem:0.10 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "Test - CPU:144.06 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", "model": { - "traintupleKey": "3945fe491ed81ff7c83b27464a91a86989bb1bbdf21665fb9e83f122e6069206", - "hash": "0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f", - "storageAddress": "http://testserver/model/0b576f310d22d9bb83e59ec05700c0f242b9f9cf40a9a82e71ddf5b46edc372f/file/" + "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "hash": "8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27", + "storageAddress": "http://testserver/model/8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, - "permissions": "all", "status": "done", "tag": "substra" } }, { "traintuple": { - "key": "80d7a55b7cbd0abc5d930e904abef2bf03e66172c70e3c0039e66fe0dd9a5b76", + "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", "algo": { "name": "Random Forest", "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" }, - "creator": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "creator": "chu-nantesMSP", "dataset": { - "worker": "ddf7e363fed48718a1ed0d83b107d50b4fb5a0999ec26d837922a5b2d952682c", + "worker": "chu-nantesMSP", "keys": [ "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" @@ -501,16 +572,21 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0014-9910bb3]", + "log": "[01-01-0014-2dd325f]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "cf968a25d4bdcacc92539d73f553e8ad8989511154736140223633d35c0d5453", + "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": None, - "permissions": "all", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, "rank": 0, "status": "failed", "tag": "" @@ -524,7 +600,6 @@ "log": "", "model": None, "objective": None, - "permissions": "", "status": "", "tag": "" } diff --git a/substrabac/substrapp/tests/generate_assets.py b/substrabac/substrapp/tests/generate_assets.py index eb2bf5738..39b903ca7 100644 --- a/substrabac/substrapp/tests/generate_assets.py +++ b/substrabac/substrapp/tests/generate_assets.py @@ -26,7 +26,11 @@ def main(): with open(assets_path, 'w') as f: f.write('"""\nWARNING\n=======\n\nDO NOT MANUALLY EDIT THIS FILE!\n\n' - 'It is generated using substrapp/tests/generate_assets.py\n"""\n\n') + 'It is generated using substrapp/tests/generate_assets.py\n\n' + 'In order to update this file:\n' + '1. start a clean instance of substra\n' + '2. run populate.py\n' + '3. run substrapp/tests/generate_assets.py\n"""\n\n') for k, v in assets.items(): v = v.replace('owkin.substrabac:8000', 'testserver') v = v.replace('chunantes.substrabac:8001', 'testserver') From 32d8c8bb765c7e630ecdf2d8bfa4d16e83b29dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 23 Sep 2019 10:08:33 +0200 Subject: [PATCH 288/457] fix permissions in create asset cmds --- substrabac/substrapp/management/commands/createdataset.py | 2 +- substrabac/substrapp/management/commands/createobjective.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/substrabac/substrapp/management/commands/createdataset.py b/substrabac/substrapp/management/commands/createdataset.py index a18a8cfdb..71db99bc7 100644 --- a/substrabac/substrapp/management/commands/createdataset.py +++ b/substrabac/substrapp/management/commands/createdataset.py @@ -98,7 +98,7 @@ def handle(self, *args, **options): # init ledger serializer ledger_serializer = LedgerDataManagerSerializer( data={'name': data_manager['name'], - 'permissions': 'all', # forced, TODO changed when permissions are available + 'permissions': {'public': True, 'authorized_ids': []}, 'type': data_manager['type'], 'objective_keys': data_manager.get('objective_keys', []), 'instance': instance}, diff --git a/substrabac/substrapp/management/commands/createobjective.py b/substrabac/substrapp/management/commands/createobjective.py index f5b2e8ea0..24649de4b 100644 --- a/substrabac/substrapp/management/commands/createobjective.py +++ b/substrabac/substrapp/management/commands/createobjective.py @@ -119,7 +119,7 @@ def handle(self, *args, **options): # init ledger serializer ledger_serializer = LedgerDataManagerSerializer( data={'name': data_manager['name'], - 'permissions': 'all', + 'permissions': {'public': True, 'authorized_ids': []}, 'type': data_manager['type'], 'instance': instance}, context={'request': LocalRequest()}) @@ -203,8 +203,7 @@ def handle(self, *args, **options): # init ledger serializer ledger_serializer = LedgerObjectiveSerializer( data={'name': objective['name'], - 'permissions': 'all', - # forced, TODO changed when permissions are available + 'permissions': {'public': True, 'authorized_ids': []}, 'metrics_name': objective['metrics_name'], 'test_data_sample_keys': objective.get('test_data_sample_keys', []), 'test_data_manager_key': objective.get('test_data_manager_key', ''), From f3977ca90c7b532fabc09764f83660243aff81cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 23 Sep 2019 14:56:15 +0200 Subject: [PATCH 289/457] use correct credentials when fetching model --- substrabac/substrapp/tasks/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index e79a892c8..d9b6fd3c0 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -72,7 +72,7 @@ def _get_model(model): model_content = get_asset_content( traintuple_metadata['outModel']['storageAddress'], - traintuple_metadata['creator'], + traintuple_metadata['dataset']['worker'], traintuple_metadata['outModel']['hash'], salt=traintuple_hash, ) From a2ea91b133e7853afa3f8da6445ac6dd552c61d4 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Thu, 26 Sep 2019 15:27:44 +0200 Subject: [PATCH 290/457] add register node invoke --- substrabac/node/apps.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/substrabac/node/apps.py b/substrabac/node/apps.py index ffb6c1d7d..396976f08 100644 --- a/substrabac/node/apps.py +++ b/substrabac/node/apps.py @@ -1,5 +1,10 @@ from django.apps import AppConfig +from substrapp.ledger_utils import invoke_ledger class NodeConfig(AppConfig): name = 'node' + + def ready(self): + # args is set to empty because fabric-sdk-py doesn't allow None args for invoke operations + invoke_ledger(fcn='registerNode', args=[''], sync=True) From 053124d6c2d4e360132778d0cbb0d0328fe31431 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Thu, 26 Sep 2019 16:27:33 +0200 Subject: [PATCH 291/457] fix tests --- substrabac/node/apps.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/substrabac/node/apps.py b/substrabac/node/apps.py index 396976f08..aa2d62bcb 100644 --- a/substrabac/node/apps.py +++ b/substrabac/node/apps.py @@ -1,10 +1,13 @@ from django.apps import AppConfig from substrapp.ledger_utils import invoke_ledger +from django.conf import settings + class NodeConfig(AppConfig): name = 'node' def ready(self): - # args is set to empty because fabric-sdk-py doesn't allow None args for invoke operations - invoke_ledger(fcn='registerNode', args=[''], sync=True) + if hasattr(settings, 'LEDGER'): + # args is set to empty because fabric-sdk-py doesn't allow None args for invoke operations + invoke_ledger(fcn='registerNode', args=[''], sync=True) From 5205bafda00e73bd01f8c4dbe3cfc1e44bd20fa9 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 26 Sep 2019 18:43:50 +0200 Subject: [PATCH 292/457] Update populate against last cli version --- populate.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/populate.py b/populate.py index e1ffebf4b..7e23fd9b4 100644 --- a/populate.py +++ b/populate.py @@ -82,7 +82,9 @@ def get_or_create(data, profile, asset, dryrun=False, local=True): else: print(colored(json.dumps(r, indent=2), 'green')) - key_or_keys = [x['pkhash'] for x in r] if isinstance(r, list) else r['pkhash'] + + key_or_keys = [x.get('pkhash', x.get('key')) + for x in r] if isinstance(r, list) else r.get('pkhash', r.get('key')) return key_or_keys From 5e57f2cc2e1661e7ce160a181db6f7d1cd293695 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 27 Sep 2019 09:59:25 +0200 Subject: [PATCH 293/457] Fix node setup to be compatible with skaffold. --- README.md | 16 ++++++++-------- .../substrabac/templates/deployment-backend.yaml | 4 ++-- docker/start.py | 4 ++-- substrabac/node/apps.py | 2 +- substrabac/substrabac/settings/common.py | 2 +- substrabac/substrabac/settings/prod.py | 1 - .../settings/{events => server}/__init__.py | 0 .../settings/{events => server}/dev.py | 2 ++ .../{events => server}/nobasicauth/__init__.py | 0 .../{events => server}/nobasicauth/dev.py | 0 .../{events => server}/nobasicauth/prod.py | 0 .../settings/{events => server}/prod.py | 2 ++ 12 files changed, 18 insertions(+), 15 deletions(-) rename substrabac/substrabac/settings/{events => server}/__init__.py (100%) rename substrabac/substrabac/settings/{events => server}/dev.py (69%) rename substrabac/substrabac/settings/{events => server}/nobasicauth/__init__.py (100%) rename substrabac/substrabac/settings/{events => server}/nobasicauth/dev.py (100%) rename substrabac/substrabac/settings/{events => server}/nobasicauth/prod.py (100%) rename substrabac/substrabac/settings/{events => server}/prod.py (69%) diff --git a/README.md b/README.md index 19bfe68aa..7ba8bd14e 100644 --- a/README.md +++ b/README.md @@ -152,17 +152,17 @@ DJANGO_SETTINGS_MODULE=substrabac.settings.common celery -A substrabac beat -l i ## Launch the servers Go in the `substrabac` folder and run the server locally: -:warning:

    Be very careful, --settings is different here, `events` is needed.

    +:warning:

    Be very careful, --settings is different here, `server` is needed.

    ``` - SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.events.dev - SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.events.dev + SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.server.dev + SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.server.dev ``` If you want to bypass the basic authentication when you browse the server on localhost:8000 or localhost:8001, you can use the `nobasicauth` settings. - Simply replace `events.dev` by `nobasicauth`, like: + Simply replace `server.dev` by `nobasicauth`, like: ``` - SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.events.nobasicauth - SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.events.nobasicauth + SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.server.nobasicauth + SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.server.nobasicauth ``` It allows the substrafront project to work correctly too. @@ -170,8 +170,8 @@ Go in the `substrabac` folder and run the server locally: For working with node to node authentication, you need load some extra fixtures ``` -SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py loaddata nodes-owkin.yaml --settings=substrabac.settings.events.dev -SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py loaddata nodes-chunantes.yaml --settings=substrabac.settings.events.dev +SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py loaddata nodes-owkin.yaml --settings=substrabac.settings.server.dev +SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py loaddata nodes-chunantes.yaml --settings=substrabac.settings.server.dev ``` ## Test with unit and functional tests diff --git a/charts/substrabac/templates/deployment-backend.yaml b/charts/substrabac/templates/deployment-backend.yaml index a82c0218c..73fd41acb 100644 --- a/charts/substrabac/templates/deployment-backend.yaml +++ b/charts/substrabac/templates/deployment-backend.yaml @@ -34,9 +34,9 @@ spec: {{- end }} command: ["/bin/bash"] {{- if eq .Values.backend.settings "prod" }} - args: ["-c", "python manage.py migrate; python3 manage.py collectstatic --noinput; uwsgi --http :8000 --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} "] + args: ["-c", "python manage.py migrate; python3 manage.py collectstatic --noinput; uwsgi --http :8000 --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=substrabac.settings.server.{{ .Values.backend.settings }} "] {{- else }} - args: ["-c", "python manage.py migrate; DJANGO_SETTINGS_MODULE=substrabac.settings.events.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] + args: ["-c", "python manage.py migrate; DJANGO_SETTINGS_MODULE=substrabac.settings.server.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] {{- end }} env: - name: ORG diff --git a/docker/start.py b/docker/start.py index 57157e630..4cd10e22e 100644 --- a/docker/start.py +++ b/docker/start.py @@ -125,11 +125,11 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): django_server = f'python3 manage.py collectstatic --noinput; '\ f'--module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics ' \ f'--master --processes {processes} --threads 2 --need-app' \ - f'--env DJANGO_SETTINGS_MODULE=substrabac.settings.events.prod uwsgi --http :{port} ' + f'--env DJANGO_SETTINGS_MODULE=substrabac.settings.server.prod uwsgi --http :{port} ' else: print('nobasicauth: ', nobasicauth, flush=True) extra_settings = '.nobasicauth' if nobasicauth is True else '' - django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.events{extra_settings}.dev ' \ + django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.server{extra_settings}.dev ' \ f'python3 manage.py runserver --noreload 0.0.0.0:{port}' backend_global_env = [ diff --git a/substrabac/node/apps.py b/substrabac/node/apps.py index aa2d62bcb..81dec1537 100644 --- a/substrabac/node/apps.py +++ b/substrabac/node/apps.py @@ -8,6 +8,6 @@ class NodeConfig(AppConfig): name = 'node' def ready(self): - if hasattr(settings, 'LEDGER'): + if hasattr(settings, 'REGISTER_NODE') and getattr(settings, 'REGISTER_NODE'): # args is set to empty because fabric-sdk-py doesn't allow None args for invoke operations invoke_ledger(fcn='registerNode', args=[''], sync=True) diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 245254358..9e84497fe 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -59,7 +59,7 @@ 'rest_framework_swagger', 'rest_framework', 'substrapp', - 'node', + 'node' ] AUTHENTICATION_BACKENDS = [ diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 53322f546..10be12ae7 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -40,7 +40,6 @@ SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') - LOGGING = { 'version': 1, 'disable_existing_loggers': False, diff --git a/substrabac/substrabac/settings/events/__init__.py b/substrabac/substrabac/settings/server/__init__.py similarity index 100% rename from substrabac/substrabac/settings/events/__init__.py rename to substrabac/substrabac/settings/server/__init__.py diff --git a/substrabac/substrabac/settings/events/dev.py b/substrabac/substrabac/settings/server/dev.py similarity index 69% rename from substrabac/substrabac/settings/events/dev.py rename to substrabac/substrabac/settings/server/dev.py index 1035c6381..79e01fb17 100644 --- a/substrabac/substrabac/settings/events/dev.py +++ b/substrabac/substrabac/settings/server/dev.py @@ -1,3 +1,5 @@ from ..dev import * INSTALLED_APPS += ['events'] + +REGISTER_NODE = True diff --git a/substrabac/substrabac/settings/events/nobasicauth/__init__.py b/substrabac/substrabac/settings/server/nobasicauth/__init__.py similarity index 100% rename from substrabac/substrabac/settings/events/nobasicauth/__init__.py rename to substrabac/substrabac/settings/server/nobasicauth/__init__.py diff --git a/substrabac/substrabac/settings/events/nobasicauth/dev.py b/substrabac/substrabac/settings/server/nobasicauth/dev.py similarity index 100% rename from substrabac/substrabac/settings/events/nobasicauth/dev.py rename to substrabac/substrabac/settings/server/nobasicauth/dev.py diff --git a/substrabac/substrabac/settings/events/nobasicauth/prod.py b/substrabac/substrabac/settings/server/nobasicauth/prod.py similarity index 100% rename from substrabac/substrabac/settings/events/nobasicauth/prod.py rename to substrabac/substrabac/settings/server/nobasicauth/prod.py diff --git a/substrabac/substrabac/settings/events/prod.py b/substrabac/substrabac/settings/server/prod.py similarity index 69% rename from substrabac/substrabac/settings/events/prod.py rename to substrabac/substrabac/settings/server/prod.py index 5c54afdd7..aa5e441de 100644 --- a/substrabac/substrabac/settings/events/prod.py +++ b/substrabac/substrabac/settings/server/prod.py @@ -1,3 +1,5 @@ from ..prod import * INSTALLED_APPS += ['events'] + +REGISTER_NODE = True From 755d2c08b07a8b906f4e0a85d0b710c3c5728f78 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 27 Sep 2019 10:28:11 +0200 Subject: [PATCH 294/457] Check that channel exists before discovery. --- substrabac/substrabac/settings/deps/ledger.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index f22b8f301..434d8486a 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -40,7 +40,6 @@ def get_hfc_client(): asyncio.set_event_loop(loop) client = Client() - channel = client.new_channel(LEDGER['channel_name']) # Add peer from substrabac ledger config file peer = Peer(name=LEDGER['peer']['name']) @@ -53,6 +52,23 @@ def get_hfc_client(): }) client._peers[LEDGER['peer']['name']] = peer + # Check peer has joined channel + + response = loop.run_until_complete( + client.query_channels( + requestor=LEDGER['requestor'], + peers=[peer], + decode=True + ) + ) + + channels = [ch.channel_id for ch in response.channels] + + if not LEDGER['channel_name'] in channels: + raise Exception(f'Peer has not joined channel: {LEDGER["channel_name"]}') + + channel = client.new_channel(LEDGER['channel_name']) + # Discover orderers and peers from channel discovery results = loop.run_until_complete( channel._discovery( @@ -78,6 +94,7 @@ def update_client_with_discovery(client, discovery_results): # Get all msp tls root cert files tls_root_certs = {} + for mspid, msp_info in discovery_results['config']['msps'].items(): tls_root_certs[mspid] = base64.decodebytes( msp_info['tls_root_certs'].pop().encode() From 654b18109b34069e97d5a0805dc481df9db6f3ef Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 10:01:43 +0200 Subject: [PATCH 295/457] Separate node registering from node app --- substrabac/node-register/__init__.py | 0 substrabac/node-register/apps.py | 13 +++++++++++++ substrabac/node/apps.py | 8 -------- substrabac/substrabac/settings/server/dev.py | 4 +--- substrabac/substrabac/settings/server/prod.py | 4 +--- 5 files changed, 15 insertions(+), 14 deletions(-) create mode 100644 substrabac/node-register/__init__.py create mode 100644 substrabac/node-register/apps.py diff --git a/substrabac/node-register/__init__.py b/substrabac/node-register/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/node-register/apps.py b/substrabac/node-register/apps.py new file mode 100644 index 000000000..46be522bc --- /dev/null +++ b/substrabac/node-register/apps.py @@ -0,0 +1,13 @@ +from django.apps import AppConfig +from substrapp.ledger_utils import invoke_ledger + +from django.conf import settings + + +class NodeRegisterConfig(AppConfig): + name = 'node-register' + + def ready(self): + if hasattr(settings, 'LEDGER'): + # args is set to empty because fabric-sdk-py doesn't allow None args for invoke operations + invoke_ledger(fcn='registerNode', args=[''], sync=True) diff --git a/substrabac/node/apps.py b/substrabac/node/apps.py index 81dec1537..ffb6c1d7d 100644 --- a/substrabac/node/apps.py +++ b/substrabac/node/apps.py @@ -1,13 +1,5 @@ from django.apps import AppConfig -from substrapp.ledger_utils import invoke_ledger - -from django.conf import settings class NodeConfig(AppConfig): name = 'node' - - def ready(self): - if hasattr(settings, 'REGISTER_NODE') and getattr(settings, 'REGISTER_NODE'): - # args is set to empty because fabric-sdk-py doesn't allow None args for invoke operations - invoke_ledger(fcn='registerNode', args=[''], sync=True) diff --git a/substrabac/substrabac/settings/server/dev.py b/substrabac/substrabac/settings/server/dev.py index 79e01fb17..e6b079217 100644 --- a/substrabac/substrabac/settings/server/dev.py +++ b/substrabac/substrabac/settings/server/dev.py @@ -1,5 +1,3 @@ from ..dev import * -INSTALLED_APPS += ['events'] - -REGISTER_NODE = True +INSTALLED_APPS += ['events', 'node-register'] diff --git a/substrabac/substrabac/settings/server/prod.py b/substrabac/substrabac/settings/server/prod.py index aa5e441de..1b18b4cee 100644 --- a/substrabac/substrabac/settings/server/prod.py +++ b/substrabac/substrabac/settings/server/prod.py @@ -1,5 +1,3 @@ from ..prod import * -INSTALLED_APPS += ['events'] - -REGISTER_NODE = True +INSTALLED_APPS += ['events', 'node-register'] From dda334534edfd5477f69806665636bd64c603825 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 10:05:24 +0200 Subject: [PATCH 296/457] Add missing files --- substrabac/node-register/apps.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/substrabac/node-register/apps.py b/substrabac/node-register/apps.py index 46be522bc..40875adf7 100644 --- a/substrabac/node-register/apps.py +++ b/substrabac/node-register/apps.py @@ -1,13 +1,10 @@ from django.apps import AppConfig from substrapp.ledger_utils import invoke_ledger -from django.conf import settings - class NodeRegisterConfig(AppConfig): name = 'node-register' def ready(self): - if hasattr(settings, 'LEDGER'): - # args is set to empty because fabric-sdk-py doesn't allow None args for invoke operations - invoke_ledger(fcn='registerNode', args=[''], sync=True) + # args is set to empty because fabric-sdk-py doesn't allow None args for invoke operations + invoke_ledger(fcn='registerNode', args=[''], sync=True) From e0ba8431fd9f99a39c0ad27d4bff1b57e01eab50 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 27 Sep 2019 10:48:29 +0200 Subject: [PATCH 297/457] Add node-register in dockerfile. --- docker/substrabac/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/substrabac/Dockerfile b/docker/substrabac/Dockerfile index e2d82f0d7..b09ed78de 100644 --- a/docker/substrabac/Dockerfile +++ b/docker/substrabac/Dockerfile @@ -17,3 +17,4 @@ COPY ./substrabac/substrapp /usr/src/app/substrapp COPY ./substrabac/events /usr/src/app/events COPY ./substrabac/substrabac /usr/src/app/substrabac COPY ./substrabac/node /usr/src/app/node +COPY ./substrabac/node-register /usr/src/app/node-register From 5af7f53425bdc02e579a61a87f862fb635df7246 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 25 Sep 2019 10:11:34 +0200 Subject: [PATCH 298/457] Add retry decorator to ledger calls. Add worker task settings for debug (logs, clean). --- docker/start.py | 4 +++ substrabac/substrabac/settings/deps/ledger.py | 2 +- substrabac/substrabac/settings/dev.py | 5 +++ substrabac/substrabac/settings/prod.py | 5 +++ substrabac/substrapp/ledger_utils.py | 18 ++++++---- .../serializers/ledger/testtuple/util.py | 4 +-- .../serializers/ledger/traintuple/util.py | 4 +-- substrabac/substrapp/tasks/tasks.py | 35 +++++++++++-------- substrabac/substrapp/tasks/utils.py | 19 ++++++++-- 9 files changed, 68 insertions(+), 28 deletions(-) diff --git a/docker/start.py b/docker/start.py index 4cd10e22e..1edcf195f 100644 --- a/docker/start.py +++ b/docker/start.py @@ -143,6 +143,9 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'PYTHONUNBUFFERED=1', 'DATABASE_HOST=postgresql', + f"TASK_LOGS=True", + f"TASK_CLEAN=True", + f'CELERY_BROKER_URL={CELERY_BROKER_URL}', f'DJANGO_SETTINGS_MODULE=substrabac.settings.{launch_settings}', @@ -151,6 +154,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', 'admin')}", f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", + ] hlf_volumes = [ diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 434d8486a..bd32f345e 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -20,7 +20,7 @@ LEDGER = json.load(open(LEDGER_CONFIG_FILE, 'r')) LEDGER_SYNC_ENABLED = True -LEDGER_MVCC_RETRY = True +LEDGER_CALL_RETRY = True PEER_PORT = LEDGER['peer']['port'][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 39e9ad652..73082613e 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -11,6 +11,11 @@ BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', 'dev') DEBUG = True +TASK_CONFIG = { + 'LOGS': bool(os.environ.get('TASK_LOGS', True)), + 'CLEAN': bool(os.environ.get('TASK_CLEAN', True)) +} + # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 10be12ae7..ceb8ba2f5 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -9,6 +9,11 @@ DEBUG = False +TASK_CONFIG = { + 'LOGS': bool(os.environ.get('TASK_LOGS', True)), + 'CLEAN': bool(os.environ.get('TASK_CLEAN', True)) +} + BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD') diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index edb7cb049..ef3dcdaec 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -81,11 +81,11 @@ class LedgerStatusError(LedgerError): } -def retry_on_mvcc_error(delay=1, nbtries=5, backoff=2): +def retry_on_error(delay=1, nbtries=5, backoff=2): def _retry(fn): @functools.wraps(fn) def _wrapper(*args, **kwargs): - if not getattr(settings, 'LEDGER_MVCC_RETRY', False): + if not getattr(settings, 'LEDGER_CALL_RETRY', False): return fn(*args, **kwargs) _delay = delay @@ -95,7 +95,9 @@ def _wrapper(*args, **kwargs): while True: try: return fn(*args, **kwargs) - except LedgerMVCCError as e: + except (LedgerMVCCError, LedgerTimeout, LedgerBadResponse, + LedgerResponseError, LedgerStatusError) as e: + _nbtries -= 1 if not nbtries: raise @@ -185,11 +187,13 @@ def call_ledger(call_type, fcn, args=None, kwargs=None): return response +@retry_on_error() def query_ledger(fcn, args=None): # careful, passing invoke parameters to query_ledger will NOT fail return call_ledger('query', fcn=fcn, args=args) +@retry_on_error() def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False, only_pkhash=True): params = { 'wait_for_event': sync, @@ -209,11 +213,12 @@ def invoke_ledger(fcn, args=None, cc_pattern=None, sync=False, only_pkhash=True) return response +@retry_on_error() def get_object_from_ledger(pk, query): return query_ledger(fcn=query, args={'key': pk}) -@retry_on_mvcc_error() +@retry_on_error() def log_fail_tuple(tuple_type, tuple_key, err_msg): err_msg = str(err_msg).replace('"', "'").replace('\\', "").replace('\\n', "")[:200] @@ -228,7 +233,7 @@ def log_fail_tuple(tuple_type, tuple_key, err_msg): sync=True) -@retry_on_mvcc_error() +@retry_on_error() def log_success_tuple(tuple_type, tuple_key, res): if tuple_type == 'traintuple': invoke_fcn = 'logSuccessTrain' @@ -256,7 +261,7 @@ def log_success_tuple(tuple_type, tuple_key, res): return invoke_ledger(fcn=invoke_fcn, args=invoke_args, sync=True) -@retry_on_mvcc_error() +@retry_on_error() def log_start_tuple(tuple_type, tuple_key): start_type = None @@ -276,6 +281,7 @@ def log_start_tuple(tuple_type, tuple_key): pass +@retry_on_error() def query_tuples(tuple_type, data_owner): data = query_ledger( fcn="queryFilter", diff --git a/substrabac/substrapp/serializers/ledger/testtuple/util.py b/substrabac/substrapp/serializers/ledger/testtuple/util.py index c21f8fec5..bed664783 100644 --- a/substrabac/substrapp/serializers/ledger/testtuple/util.py +++ b/substrabac/substrapp/serializers/ledger/testtuple/util.py @@ -1,9 +1,9 @@ from __future__ import absolute_import, unicode_literals -from substrapp.ledger_utils import invoke_ledger, retry_on_mvcc_error +from substrapp.ledger_utils import invoke_ledger, retry_on_error -@retry_on_mvcc_error(nbtries=3) +@retry_on_error(nbtries=3) def createLedgerTesttuple(args, sync=False): return invoke_ledger(fcn='createTesttuple', args=args, sync=sync) diff --git a/substrabac/substrapp/serializers/ledger/traintuple/util.py b/substrabac/substrapp/serializers/ledger/traintuple/util.py index 505d7530a..124f6d54a 100644 --- a/substrabac/substrapp/serializers/ledger/traintuple/util.py +++ b/substrabac/substrapp/serializers/ledger/traintuple/util.py @@ -1,9 +1,9 @@ from __future__ import absolute_import, unicode_literals -from substrapp.ledger_utils import invoke_ledger, retry_on_mvcc_error +from substrapp.ledger_utils import invoke_ledger, retry_on_error -@retry_on_mvcc_error(nbtries=3) +@retry_on_error(nbtries=3) def createLedgerTraintuple(args, sync=False): return invoke_ledger(fcn='createTraintuple', args=args, sync=sync) diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index d9b6fd3c0..b00b36b18 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -361,16 +361,17 @@ def do_task(subtuple, tuple_type): raise e finally: # Clean subtuple materials - remove_subtuple_materials(subtuple_directory) - - # Rank == -1 -> Last fl subtuple or fl throws an exception - if flrank == -1: - flvolume = f'local-{compute_plan_id}-{org_name}' - local_volume = client.volumes.get(volume_id=flvolume) - try: - local_volume.remove(force=True) - except Exception: - logging.error(f'Cannot remove local volume {flvolume}', exc_info=True) + if settings.TASK_CONFIG['CLEAN']: + remove_subtuple_materials(subtuple_directory) + + # Rank == -1 -> Last fl subtuple or fl throws an exception + if flrank == -1: + flvolume = f'local-{compute_plan_id}-{org_name}' + local_volume = client.volumes.get(volume_id=flvolume) + try: + local_volume.remove(force=True) + except Exception: + logging.error(f'Cannot remove local volume {flvolume}', exc_info=True) return result @@ -408,10 +409,10 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, algo_docker_name = f'{algo_docker}_{subtuple["key"]}' model_volume = {model_path: {'bind': '/sandbox/model', 'mode': 'rw'}} - if compute_plan_id is not None and flrank != -1: - remove_image = False + if (compute_plan_id is not None and flrank != -1) or settings.TASK_CONFIG['CLEAN']: + REMOVE_IMAGE = False else: - remove_image = True + REMOVE_IMAGE = True # create the command option for algo if tuple_type == 'traintuple': @@ -450,7 +451,9 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, container_name=algo_docker_name, volumes={**volumes, **model_volume, **symlinks_volume}, command=algo_command, - remove_image=remove_image + remove_image=REMOVE_IMAGE, + remove_container=settings.TASK_CONFIG['CLEAN'], + logs=settings.TASK_CONFIG['LOGS'] ) # save model in database @@ -477,7 +480,9 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, container_name=metrics_docker_name, volumes={**volumes, **symlinks_volume}, command=None, - remove_image=remove_image + remove_image=REMOVE_IMAGE, + remove_container=settings.TASK_CONFIG['CLEAN'], + logs=settings.TASK_CONFIG['LOGS'] ) # load performance diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index e53335c63..00b19ed4f 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -211,8 +211,14 @@ def monitoring_task(client, task_args): t._result += f" GB - GPU:{t._stats['gpu']['max']:.2f} % - GPU Mem:{t._stats['gpu_memory']['max']:.2f} GB" +def container_format_log(container_name, container_logs): + logs = [f'[{container_name}] {log}' for log in container_logs.decode().split('\n')] + for log in logs: + logger.info(log) + + def compute_docker(client, resources_manager, dockerfile_path, image_name, container_name, volumes, command, - remove_image=True): + remove_image=True, remove_container=True, logs=True): dockerfile_fullpath = os.path.join(dockerfile_path, 'Dockerfile') if not os.path.exists(dockerfile_fullpath): @@ -244,6 +250,8 @@ def compute_docker(client, resources_manager, dockerfile_path, image_name, conta 'shm_size': '8G', 'labels': [DOCKER_LABEL], 'detach': False, + 'stdout': logs, + 'stderr': logs, 'auto_remove': False, 'remove': False, 'network_disabled': True, @@ -271,7 +279,14 @@ def compute_docker(client, resources_manager, dockerfile_path, image_name, conta # We already get the excetion and we need to remove the containers to be able to remove the local # volume in case of fl task. container = client.containers.get(container_name) - container.remove() + if logs: + container_format_log( + container_name, + container.logs() + ) + + if remove_container: + container.remove() # Remove images if remove_image or hasattr(task, "_exception"): From ded603553d2796b7047cf9a4b296a7943bd39590 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 26 Sep 2019 11:52:55 +0200 Subject: [PATCH 299/457] Improve settings definition --- docker/start.py | 6 +++--- substrabac/substrabac/settings/dev.py | 8 +++----- substrabac/substrabac/settings/prod.py | 7 +++---- substrabac/substrapp/ledger_utils.py | 3 +-- substrabac/substrapp/tasks/tasks.py | 20 ++++++++++---------- substrabac/substrapp/tasks/utils.py | 8 ++++---- 6 files changed, 24 insertions(+), 28 deletions(-) diff --git a/docker/start.py b/docker/start.py index 1edcf195f..081ac4335 100644 --- a/docker/start.py +++ b/docker/start.py @@ -143,8 +143,9 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'PYTHONUNBUFFERED=1', 'DATABASE_HOST=postgresql', - f"TASK_LOGS=True", - f"TASK_CLEAN=True", + f"TASK_CAPTURE_LOGS=True", + f"TASK_CLEAN_EXECUTION_ENVIRONMENT=True", + f"TASK_CACHE_DOCKER_IMAGES=False", f'CELERY_BROKER_URL={CELERY_BROKER_URL}', f'DJANGO_SETTINGS_MODULE=substrabac.settings.{launch_settings}', @@ -154,7 +155,6 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', 'admin')}", f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", - ] hlf_volumes = [ diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 73082613e..0f4e12a41 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -11,11 +11,9 @@ BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', 'dev') DEBUG = True -TASK_CONFIG = { - 'LOGS': bool(os.environ.get('TASK_LOGS', True)), - 'CLEAN': bool(os.environ.get('TASK_CLEAN', True)) -} - +TASK_CAPTURE_LOGS = bool(os.environ.get('TASK_CAPTURE_LOGS', True)), +TASK_CLEAN_EXECUTION_ENVIRONMENT = bool(os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', True)) +TASK_CACHE_DOCKER_IMAGES = bool(os.environ.get('TASK_CACHE_DOCKER_IMAGES', False)) # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index ceb8ba2f5..4fad2a5f5 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -9,10 +9,9 @@ DEBUG = False -TASK_CONFIG = { - 'LOGS': bool(os.environ.get('TASK_LOGS', True)), - 'CLEAN': bool(os.environ.get('TASK_CLEAN', True)) -} +TASK_CAPTURE_LOGS = bool(os.environ.get('TASK_CAPTURE_LOGS', True)), +TASK_CLEAN_EXECUTION_ENVIRONMENT = bool(os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', True)) +TASK_CACHE_DOCKER_IMAGES = bool(os.environ.get('TASK_CACHE_DOCKER_IMAGES', False)) BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index ef3dcdaec..5615fd930 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -95,8 +95,7 @@ def _wrapper(*args, **kwargs): while True: try: return fn(*args, **kwargs) - except (LedgerMVCCError, LedgerTimeout, LedgerBadResponse, - LedgerResponseError, LedgerStatusError) as e: + except (LedgerMVCCError, LedgerTimeout, LedgerBadResponse) as e: _nbtries -= 1 if not nbtries: diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index b00b36b18..bdc61f1a5 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -361,7 +361,7 @@ def do_task(subtuple, tuple_type): raise e finally: # Clean subtuple materials - if settings.TASK_CONFIG['CLEAN']: + if settings.TASK_CLEAN_EXECUTION_ENVIRONMENT: remove_subtuple_materials(subtuple_directory) # Rank == -1 -> Last fl subtuple or fl throws an exception @@ -409,10 +409,10 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, algo_docker_name = f'{algo_docker}_{subtuple["key"]}' model_volume = {model_path: {'bind': '/sandbox/model', 'mode': 'rw'}} - if (compute_plan_id is not None and flrank != -1) or settings.TASK_CONFIG['CLEAN']: - REMOVE_IMAGE = False + if (compute_plan_id is not None and flrank != -1) or settings.TASK_CACHE_DOCKER_IMAGES: + remove_image = False else: - REMOVE_IMAGE = True + remove_image = True # create the command option for algo if tuple_type == 'traintuple': @@ -451,9 +451,9 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, container_name=algo_docker_name, volumes={**volumes, **model_volume, **symlinks_volume}, command=algo_command, - remove_image=REMOVE_IMAGE, - remove_container=settings.TASK_CONFIG['CLEAN'], - logs=settings.TASK_CONFIG['LOGS'] + remove_image=remove_image, + remove_container=settings.TASK_CLEAN_EXECUTION_ENVIRONMENT, + capture_logs=settings.TASK_CAPTURE_LOGS ) # save model in database @@ -480,9 +480,9 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, container_name=metrics_docker_name, volumes={**volumes, **symlinks_volume}, command=None, - remove_image=REMOVE_IMAGE, - remove_container=settings.TASK_CONFIG['CLEAN'], - logs=settings.TASK_CONFIG['LOGS'] + remove_image=remove_image, + remove_container=settings.TASK_CLEAN_EXECUTION_ENVIRONMENT, + capture_logs=settings.TASK_CAPTURE_LOGS ) # load performance diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index 00b19ed4f..1eaeeb1f9 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -218,7 +218,7 @@ def container_format_log(container_name, container_logs): def compute_docker(client, resources_manager, dockerfile_path, image_name, container_name, volumes, command, - remove_image=True, remove_container=True, logs=True): + remove_image=True, remove_container=True, capture_logs=True): dockerfile_fullpath = os.path.join(dockerfile_path, 'Dockerfile') if not os.path.exists(dockerfile_fullpath): @@ -250,8 +250,8 @@ def compute_docker(client, resources_manager, dockerfile_path, image_name, conta 'shm_size': '8G', 'labels': [DOCKER_LABEL], 'detach': False, - 'stdout': logs, - 'stderr': logs, + 'stdout': capture_logs, + 'stderr': capture_logs, 'auto_remove': False, 'remove': False, 'network_disabled': True, @@ -279,7 +279,7 @@ def compute_docker(client, resources_manager, dockerfile_path, image_name, conta # We already get the excetion and we need to remove the containers to be able to remove the local # volume in case of fl task. container = client.containers.get(container_name) - if logs: + if capture_logs: container_format_log( container_name, container.logs() From 7355853e9069b46c636f05b2881f77e45b709fb4 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 26 Sep 2019 14:34:06 +0200 Subject: [PATCH 300/457] Fix boolean evaluation --- substrabac/substrabac/settings/dev.py | 6 +++--- substrabac/substrabac/settings/prod.py | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index 0f4e12a41..f0bd9d016 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -11,9 +11,9 @@ BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', 'dev') DEBUG = True -TASK_CAPTURE_LOGS = bool(os.environ.get('TASK_CAPTURE_LOGS', True)), -TASK_CLEAN_EXECUTION_ENVIRONMENT = bool(os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', True)) -TASK_CACHE_DOCKER_IMAGES = bool(os.environ.get('TASK_CACHE_DOCKER_IMAGES', False)) +TASK_CAPTURE_LOGS = os.environ.get('TASK_CAPTURE_LOGS', 'true').lower() == 'true' +TASK_CLEAN_EXECUTION_ENVIRONMENT = os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', 'true').lower() == 'true' +TASK_CACHE_DOCKER_IMAGES = os.environ.get('TASK_CACHE_DOCKER_IMAGES', 'false').lower() == 'true' # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 4fad2a5f5..733408a7b 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -9,10 +9,9 @@ DEBUG = False -TASK_CAPTURE_LOGS = bool(os.environ.get('TASK_CAPTURE_LOGS', True)), -TASK_CLEAN_EXECUTION_ENVIRONMENT = bool(os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', True)) -TASK_CACHE_DOCKER_IMAGES = bool(os.environ.get('TASK_CACHE_DOCKER_IMAGES', False)) - +TASK_CAPTURE_LOGS = os.environ.get('TASK_CAPTURE_LOGS', 'true').lower() == 'true' +TASK_CLEAN_EXECUTION_ENVIRONMENT = os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', 'true').lower() == 'true' +TASK_CACHE_DOCKER_IMAGES = os.environ.get('TASK_CACHE_DOCKER_IMAGES', 'false').lower() == 'true' BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD') From 69e423fa31496f428a44b02f9c0dbd0f706e7767 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 26 Sep 2019 17:04:09 +0200 Subject: [PATCH 301/457] Improve settings --- substrabac/substrabac/settings/common.py | 14 ++++++++++++++ substrabac/substrabac/settings/dev.py | 11 ++++++++--- substrabac/substrabac/settings/prod.py | 9 ++++++--- substrabac/substrapp/tasks/tasks.py | 12 ++++++------ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/substrabac/substrabac/settings/common.py b/substrabac/substrabac/settings/common.py index 9e84497fe..799aca2b7 100644 --- a/substrabac/substrabac/settings/common.py +++ b/substrabac/substrabac/settings/common.py @@ -163,3 +163,17 @@ BASIC_AUTHENTICATION_MODULE = 'rest_framework.authentication' + + +TRUE_VALUES = { + 't', 'T', + 'y', 'Y', 'yes', 'YES', + 'true', 'True', 'TRUE', + 'on', 'On', 'ON', + '1', 1, + True +} + + +def to_bool(value): + return value in TRUE_VALUES diff --git a/substrabac/substrabac/settings/dev.py b/substrabac/substrabac/settings/dev.py index f0bd9d016..61ffd3840 100644 --- a/substrabac/substrabac/settings/dev.py +++ b/substrabac/substrabac/settings/dev.py @@ -11,9 +11,14 @@ BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD', 'dev') DEBUG = True -TASK_CAPTURE_LOGS = os.environ.get('TASK_CAPTURE_LOGS', 'true').lower() == 'true' -TASK_CLEAN_EXECUTION_ENVIRONMENT = os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', 'true').lower() == 'true' -TASK_CACHE_DOCKER_IMAGES = os.environ.get('TASK_CACHE_DOCKER_IMAGES', 'false').lower() == 'true' + +TASK = { + 'CAPTURE_LOGS': to_bool(os.environ.get('TASK_CAPTURE_LOGS', True)), + 'CLEAN_EXECUTION_ENVIRONMENT': to_bool(os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', True)), + 'CACHE_DOCKER_IMAGES': to_bool(os.environ.get('TASK_CACHE_DOCKER_IMAGES', False)), +} + +LEDGER_CALL_RETRY = False # Overwrite the ledger setting value # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases diff --git a/substrabac/substrabac/settings/prod.py b/substrabac/substrabac/settings/prod.py index 733408a7b..17b3f2973 100644 --- a/substrabac/substrabac/settings/prod.py +++ b/substrabac/substrabac/settings/prod.py @@ -9,9 +9,12 @@ DEBUG = False -TASK_CAPTURE_LOGS = os.environ.get('TASK_CAPTURE_LOGS', 'true').lower() == 'true' -TASK_CLEAN_EXECUTION_ENVIRONMENT = os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', 'true').lower() == 'true' -TASK_CACHE_DOCKER_IMAGES = os.environ.get('TASK_CACHE_DOCKER_IMAGES', 'false').lower() == 'true' + +TASK = { + 'CAPTURE_LOGS': to_bool(os.environ.get('TASK_CAPTURE_LOGS', True)), + 'CLEAN_EXECUTION_ENVIRONMENT': to_bool(os.environ.get('TASK_CLEAN_EXECUTION_ENVIRONMENT', True)), + 'CACHE_DOCKER_IMAGES': to_bool(os.environ.get('TASK_CACHE_DOCKER_IMAGES', False)), +} BASICAUTH_USERNAME = os.environ.get('BACK_AUTH_USER') BASICAUTH_PASSWORD = os.environ.get('BACK_AUTH_PASSWORD') diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index bdc61f1a5..8e68bfd3a 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -361,7 +361,7 @@ def do_task(subtuple, tuple_type): raise e finally: # Clean subtuple materials - if settings.TASK_CLEAN_EXECUTION_ENVIRONMENT: + if settings.TASK['CLEAN_EXECUTION_ENVIRONMENT']: remove_subtuple_materials(subtuple_directory) # Rank == -1 -> Last fl subtuple or fl throws an exception @@ -409,7 +409,7 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, algo_docker_name = f'{algo_docker}_{subtuple["key"]}' model_volume = {model_path: {'bind': '/sandbox/model', 'mode': 'rw'}} - if (compute_plan_id is not None and flrank != -1) or settings.TASK_CACHE_DOCKER_IMAGES: + if (compute_plan_id is not None and flrank != -1) or settings.TASK['CACHE_DOCKER_IMAGES']: remove_image = False else: remove_image = True @@ -452,8 +452,8 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, volumes={**volumes, **model_volume, **symlinks_volume}, command=algo_command, remove_image=remove_image, - remove_container=settings.TASK_CLEAN_EXECUTION_ENVIRONMENT, - capture_logs=settings.TASK_CAPTURE_LOGS + remove_container=settings.TASK['CLEAN_EXECUTION_ENVIRONMENT'], + capture_logs=settings.TASK['CAPTURE_LOGS'] ) # save model in database @@ -481,8 +481,8 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, volumes={**volumes, **symlinks_volume}, command=None, remove_image=remove_image, - remove_container=settings.TASK_CLEAN_EXECUTION_ENVIRONMENT, - capture_logs=settings.TASK_CAPTURE_LOGS + remove_container=settings.TASK['CLEAN_EXECUTION_ENVIRONMENT'], + capture_logs=settings.TASK['CAPTURE_LOGS'] ) # load performance From 806e01afd56d0d07f6a5eb37f2a350c48ad9a1ce Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 26 Sep 2019 16:37:02 +0200 Subject: [PATCH 302/457] Remove monitoring and refacto compute. --- substrabac/substrapp/ledger_utils.py | 4 +- substrabac/substrapp/tasks/tasks.py | 146 ++++++++-------- substrabac/substrapp/tasks/utils.py | 203 ++++------------------ substrabac/substrapp/tests/common.py | 119 ------------- substrabac/substrapp/tests/tests_misc.py | 42 +---- substrabac/substrapp/tests/tests_tasks.py | 27 +-- 6 files changed, 110 insertions(+), 431 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index 5615fd930..b533d5ac1 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -243,7 +243,7 @@ def log_success_tuple(tuple_type, tuple_key, res): 'storageAddress': res["end_model_file"], }, 'perf': float(res["global_perf"]), - 'log': f'Train - {res["job_task_log"]};', + 'log': 'success', } elif tuple_type == 'testtuple': @@ -251,7 +251,7 @@ def log_success_tuple(tuple_type, tuple_key, res): invoke_args = { 'key': tuple_key, 'perf': float(res["global_perf"]), - 'log': f'Test - {res["job_task_log"]};', + 'log': 'success', } else: diff --git a/substrabac/substrapp/tasks/tasks.py b/substrabac/substrapp/tasks/tasks.py index 8e68bfd3a..8415cde9a 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substrabac/substrapp/tasks/tasks.py @@ -334,13 +334,13 @@ def do_task(subtuple, tuple_type): subtuple_directory = path.join(getattr(settings, 'MEDIA_ROOT'), 'subtuple', subtuple['key']) org_name = getattr(settings, 'ORG_NAME') - # Federated learning variables + # compute plan / federated learning variables compute_plan_id = None - flrank = None + rank = None if 'computePlanID' in subtuple and subtuple['computePlanID']: compute_plan_id = subtuple['computePlanID'] - flrank = int(subtuple['rank']) + rank = int(subtuple['rank']) client = docker.from_env() @@ -351,106 +351,93 @@ def do_task(subtuple, tuple_type): tuple_type, subtuple, compute_plan_id, - flrank, + rank, org_name ) except Exception as e: - # If an exception is thrown set flrank == -1 (we stop the fl training) if compute_plan_id is not None: - flrank = -1 + rank = -1 # -1 means last subtuple in the compute plan raise e finally: # Clean subtuple materials if settings.TASK['CLEAN_EXECUTION_ENVIRONMENT']: remove_subtuple_materials(subtuple_directory) - - # Rank == -1 -> Last fl subtuple or fl throws an exception - if flrank == -1: - flvolume = f'local-{compute_plan_id}-{org_name}' - local_volume = client.volumes.get(volume_id=flvolume) + if rank == -1: + volume_id = f'local-{compute_plan_id}-{org_name}' + local_volume = client.volumes.get(volume_id=volume_id) try: local_volume.remove(force=True) except Exception: - logging.error(f'Cannot remove local volume {flvolume}', exc_info=True) + logging.error(f'Cannot remove local volume {volume_id}', exc_info=True) return result -def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, flrank, org_name): - # Job log - job_task_log = '' +def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, rank, org_name): - # subtuple setup model_path = path.join(subtuple_directory, 'model') data_path = path.join(subtuple_directory, 'data') + pred_path = path.join(subtuple_directory, 'pred') + opener_file = path.join(subtuple_directory, 'opener/opener.py') + algo_path = path.join(subtuple_directory) + + algo_docker = f'substra/algo_{subtuple["key"][0:8]}'.lower() # tag must be lowercase for docker + algo_docker_name = f'{tuple_type}_{subtuple["key"][0:8]}' + + remove_image = not((compute_plan_id is not None and rank != -1) or settings.TASK['CACHE_DOCKER_IMAGES']) + + # VOLUMES - ########################################## - # RESOLVE SYMLINKS - # TO DO: - # - Verify that real paths are safe - # - Try to see if it's clean to do that - ########################################## symlinks_volume = {} for subfolder in os.listdir(data_path): real_path = os.path.realpath(os.path.join(data_path, subfolder)) symlinks_volume[real_path] = {'bind': f'{real_path}', 'mode': 'ro'} - ########################################## + volumes = { + data_path: {'bind': '/sandbox/data', 'mode': 'ro'}, + pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, + opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'} + } - pred_path = path.join(subtuple_directory, 'pred') - opener_file = path.join(subtuple_directory, 'opener/opener.py') - volumes = {data_path: {'bind': '/sandbox/data', 'mode': 'ro'}, - pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, - opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}} - - # compute algo task - algo_path = path.join(subtuple_directory) - algo_docker = f'algo_{tuple_type}'.lower() # tag must be lowercase for docker - algo_docker_name = f'{algo_docker}_{subtuple["key"]}' - model_volume = {model_path: {'bind': '/sandbox/model', 'mode': 'rw'}} + model_volume = { + model_path: {'bind': '/sandbox/model', 'mode': 'rw'} + } - if (compute_plan_id is not None and flrank != -1) or settings.TASK['CACHE_DOCKER_IMAGES']: - remove_image = False - else: - remove_image = True + # local volume for training subtuple in compute plan + if compute_plan_id is not None and tuple_type == 'traintuple': + volume_id = f'local-{compute_plan_id}-{org_name}' + if rank == 0: + client.volumes.create(name=volume_id) + else: + client.volumes.get(volume_id=volume_id) + model_volume[volume_id] = {'bind': '/sandbox/local', 'mode': 'rw'} - # create the command option for algo + # generate command if tuple_type == 'traintuple': - algo_command = 'train' # main command + command = 'train' + algo_docker_name = f'{algo_docker_name}_{command}' - # add list of inmodels if subtuple['inModels'] is not None: inmodels = [subtuple_model["traintupleKey"] for subtuple_model in subtuple['inModels']] - algo_command = f"{algo_command} {' '.join(inmodels)}" + command = f"{command} {' '.join(inmodels)}" - # add compute_plan_id rank for training - if flrank is not None: - algo_command = f"{algo_command} --rank {flrank}" + if rank is not None: + command = f"{command} --rank {rank}" elif tuple_type == 'testtuple': - algo_command = 'predict' # main command - + command = 'predict' + algo_docker_name = f'{algo_docker_name}_{command}' inmodels = subtuple['model']["traintupleKey"] - algo_command = f'{algo_command} {inmodels}' - - # local volume for compute_plan_id - if compute_plan_id is not None and tuple_type == 'traintuple': - flvolume = f'local-{compute_plan_id}-{org_name}' - if flrank == 0: - client.volumes.create(name=flvolume) - else: - client.volumes.get(volume_id=flvolume) + command = f'{command} {inmodels}' - model_volume[flvolume] = {'bind': '/sandbox/local', 'mode': 'rw'} - - job_task_log = compute_docker( + compute_docker( client=client, resources_manager=resources_manager, dockerfile_path=algo_path, image_name=algo_docker, container_name=algo_docker_name, volumes={**volumes, **model_volume, **symlinks_volume}, - command=algo_command, + command=command, remove_image=remove_image, remove_container=settings.TASK['CLEAN_EXECUTION_ENVIRONMENT'], capture_logs=settings.TASK['CAPTURE_LOGS'] @@ -458,26 +445,19 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, # save model in database if tuple_type == 'traintuple': - from substrapp.models import Model - end_model_path = path.join(subtuple_directory, 'model/model') - end_model_file_hash = get_hash(end_model_path, subtuple['key']) - instance = Model.objects.create(pkhash=end_model_file_hash, validated=True) - - with open(end_model_path, 'rb') as f: - instance.file.save('model', f) - current_site = getattr(settings, "DEFAULT_DOMAIN") - end_model_file = f'{current_site}{reverse("substrapp:model-file", args=[end_model_file_hash])}' + end_model_file, end_model_file_hash = save_model(subtuple_directory, subtuple['key']) - # compute metric task + # evaluation metrics_path = f'{subtuple_directory}/metrics' - metrics_docker = f'metrics_{tuple_type}'.lower() # tag must be lowercase for docker - metrics_docker_name = f'{metrics_docker}_{subtuple["key"]}' + eval_docker = f'substra/metrics_{subtuple["key"][0:8]}'.lower() # tag must be lowercase for docker + eval_docker_name = f'{tuple_type}_{subtuple["key"][0:8]}_eval' + compute_docker( client=client, resources_manager=resources_manager, dockerfile_path=metrics_path, - image_name=metrics_docker, - container_name=metrics_docker_name, + image_name=eval_docker, + container_name=eval_docker_name, volumes={**volumes, **symlinks_volume}, command=None, remove_image=remove_image, @@ -488,14 +468,26 @@ def _do_task(client, subtuple_directory, tuple_type, subtuple, compute_plan_id, # load performance with open(path.join(pred_path, 'perf.json'), 'r') as perf_file: perf = json.load(perf_file) - global_perf = perf['all'] - result = {'global_perf': global_perf, - 'job_task_log': job_task_log} + result = {'global_perf': global_perf} if tuple_type == 'traintuple': result['end_model_file_hash'] = end_model_file_hash result['end_model_file'] = end_model_file return result + + +def save_model(subtuple_directory, subtuple_key): + from substrapp.models import Model + end_model_path = path.join(subtuple_directory, 'model/model') + end_model_file_hash = get_hash(end_model_path, subtuple_key) + instance = Model.objects.create(pkhash=end_model_file_hash, validated=True) + + with open(end_model_path, 'rb') as f: + instance.file.save('model', f) + current_site = getattr(settings, "DEFAULT_DOMAIN") + end_model_file = f'{current_site}{reverse("substrapp:model-file", args=[end_model_file_hash])}' + + return end_model_file, end_model_file_hash diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index 1eaeeb1f9..fd9977881 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -2,7 +2,6 @@ import docker import GPUtil as gputil import threading -import time import logging @@ -114,103 +113,6 @@ def filter_gpu_sets(used_gpu_sets, gpu_sets): return filter_resources_sets(used_gpu_sets, gpu_sets, expand_gpu_set, reduce_gpu_set) -def update_statistics(task_statistics, stats, gpu_stats): - - # CPU - - if stats is not None: - - if 'cpu_stats' in stats and stats['cpu_stats']['cpu_usage'].get('total_usage', None): - # Compute CPU usage in % - delta_total_usage = (stats['cpu_stats']['cpu_usage']['total_usage'] - - stats['precpu_stats']['cpu_usage']['total_usage']) - delta_system_usage = (stats['cpu_stats']['system_cpu_usage'] - stats['precpu_stats']['system_cpu_usage']) - total_usage = (delta_total_usage / delta_system_usage) * stats['cpu_stats']['online_cpus'] * 100.0 - - task_statistics['cpu']['current'].append(total_usage) - task_statistics['cpu']['max'] = max(task_statistics['cpu']['max'], - max(task_statistics['cpu']['current'])) - - # MEMORY in GB - if 'memory_stats' in stats: - current_usage = stats['memory_stats'].get('usage', None) - max_usage = stats['memory_stats'].get('max_usage', None) - - if current_usage: - task_statistics['memory']['current'].append(current_usage / 1024**3) - if max_usage: - task_statistics['memory']['max'] = max(task_statistics['memory']['max'], - max_usage / 1024**3, - max(task_statistics['memory']['current'])) - - # Network in kB - if 'networks' in stats: - task_statistics['netio']['rx'] = stats['networks']['eth0'].get('rx_bytes', 0) - task_statistics['netio']['tx'] = stats['networks']['eth0'].get('tx_bytes', 0) - - # GPU - - if gpu_stats is not None: - total_usage = sum([100 * gpu.load for gpu in gpu_stats]) - task_statistics['gpu']['current'].append(total_usage) - task_statistics['gpu']['max'] = max(task_statistics['gpu']['max'], - max(task_statistics['gpu']['current'])) - - total_usage = sum([gpu.memoryUsed for gpu in gpu_stats]) / 1024 - task_statistics['gpu_memory']['current'].append(total_usage) - task_statistics['gpu_memory']['max'] = max(task_statistics['gpu_memory']['max'], - max(task_statistics['gpu_memory']['current'])) - - -def monitoring_task(client, task_args): - """thread worker function""" - - task_name = task_args['name'] - - gpu_set = None - if 'environment' in task_args: - gpu_set = task_args['environment']['NVIDIA_VISIBLE_DEVICES'] - - start = time.time() - t = threading.currentThread() - - # Statistics - task_statistics = {'memory': {'max': 0, - 'current': [0]}, - 'gpu_memory': {'max': 0, - 'current': [0]}, - 'cpu': {'max': 0, - 'current': [0]}, - 'gpu': {'max': 0, - 'current': []}, - 'io': {'max': 0, - 'current': []}, - 'netio': {'rx': 0, - 'tx': 0}, - 'time': 0} - - while not t.stopthread.isSet(): - stats = None - try: - container = client.containers.get(task_name) - stats = container.stats(decode=True, stream=False) - except (docker.errors.NotFound, docker.errors.APIError): - pass - - gpu_stats = None - if gpu_set is not None: - gpu_stats = [gpu for gpu in gputil.getGPUs() if str(gpu.id) in gpu_set] - - update_statistics(task_statistics, stats, gpu_stats) - - task_statistics['time'] = time.time() - start - - t._stats = task_statistics - - t._result = f"CPU:{t._stats['cpu']['max']:.2f} % - Mem:{t._stats['memory']['max']:.2f}" - t._result += f" GB - GPU:{t._stats['gpu']['max']:.2f} % - GPU Mem:{t._stats['gpu_memory']['max']:.2f} GB" - - def container_format_log(container_name, container_logs): logs = [f'[{container_name}] {log}' for log in container_logs.decode().split('\n')] for log in logs: @@ -224,7 +126,6 @@ def compute_docker(client, resources_manager, dockerfile_path, image_name, conta if not os.path.exists(dockerfile_fullpath): raise Exception(f'Dockerfile does not exist : {dockerfile_fullpath}') - # Build metrics try: client.images.build(path=dockerfile_path, tag=image_name, @@ -241,84 +142,46 @@ def compute_docker(client, resources_manager, dockerfile_path, image_name, conta memory_limit_mb = f'{resources_manager.memory_limit_mb()}M' cpu_set, gpu_set = resources_manager.get_cpu_gpu_sets() # blocking call - task_args = {'image': image_name, - 'name': container_name, - 'cpuset_cpus': cpu_set, - 'mem_limit': memory_limit_mb, - 'command': command, - 'volumes': volumes, - 'shm_size': '8G', - 'labels': [DOCKER_LABEL], - 'detach': False, - 'stdout': capture_logs, - 'stderr': capture_logs, - 'auto_remove': False, - 'remove': False, - 'network_disabled': True, - 'network_mode': 'none', - 'privileged': False, - 'cap_drop': ['ALL']} + task_args = { + 'image': image_name, + 'name': container_name, + 'cpuset_cpus': cpu_set, + 'mem_limit': memory_limit_mb, + 'command': command, + 'volumes': volumes, + 'shm_size': '8G', + 'labels': [DOCKER_LABEL], + 'detach': False, + 'stdout': capture_logs, + 'stderr': capture_logs, + 'auto_remove': False, + 'remove': False, + 'network_disabled': True, + 'network_mode': 'none', + 'privileged': False, + 'cap_drop': ['ALL'] + } if gpu_set is not None: task_args['environment'] = {'NVIDIA_VISIBLE_DEVICES': gpu_set} task_args['runtime'] = 'nvidia' - task = ExceptionThread(target=client.containers.run, - kwargs=task_args) - - monitoring = ExceptionThread(target=monitoring_task, - args=(client, task_args)) - - task.start() - monitoring.start() - - task.join() - monitoring.join() - - # Remove container in all case (exception thrown or not) - # We already get the excetion and we need to remove the containers to be able to remove the local - # volume in case of fl task. - container = client.containers.get(container_name) - if capture_logs: - container_format_log( - container_name, - container.logs() - ) - - if remove_container: + try: + client.containers.run(**task_args) + finally: + # we need to remove the containers to be able to remove the local + # volume in case of compute plan + container = client.containers.get(container_name) + if capture_logs: + container_format_log( + container_name, + container.logs() + ) container.remove() - # Remove images - if remove_image or hasattr(task, "_exception"): - client.images.remove(image_name, force=True) - - if hasattr(task, "_exception"): - raise task._exception - - return monitoring._result - - -class ExceptionThread(threading.Thread): - - def __init__(self, *args, **kwargs): - super(ExceptionThread, self).__init__(*args, **kwargs) - self.stopthread = threading.Event() - - def run(self): - try: - if self._target: - self._target(*self._args, **self._kwargs) - except BaseException as e: - self._exception = e - raise e - finally: - # Avoid a refcycle if the thread is running a function with - # an argument that has a member that points to the thread. - del self._target, self._args, self._kwargs - - def join(self, timeout=None): - self.stopthread.set() - super(ExceptionThread, self).join(timeout) + # Remove images + if remove_image: + client.images.remove(image_name, force=True) class ResourcesManager(): diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 8dad5fbab..847e83586 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -26,112 +26,6 @@ def request(self, **kwargs): return super().request(**kwargs) -class gpu(): - """Fake gpu""" - - def __init__(self): - self.load = 0.8 - self.memoryUsed = 1024 - - -class Stats(): - @classmethod - def get_stats(cls): - """ Docker stats""" - return {"read": "2018-11-05T13:44:07.1782391Z", - "preread": "2018-11-05T13:44:06.1746531Z", - "pids_stats": { - "current": 8 - }, - "num_procs": 0, - "storage_stats": {}, - "cpu_stats": { - "cpu_usage": { - "total_usage": 22900421851, - "percpu_usage": [ - 4944824970, - 4964929089, - 8163433379, - 4827234413, - 0, - 0, - 0, - 0 - ], - "usage_in_kernelmode": 5520000000, - "usage_in_usermode": 17350000000 - }, - "system_cpu_usage": 185691120000000, - "online_cpus": 8, - "throttling_data": { - "periods": 0, - "throttled_periods": 0, - "throttled_time": 0 - }}, - "precpu_stats": { - "cpu_usage": { - "total_usage": 18898246805, - "percpu_usage": [ - 3938977859, - 3966955357, - 7165817747, - 3826495842, - 0, - 0, - 0, - 0 - ], - "usage_in_kernelmode": 5470000000, - "usage_in_usermode": 13390000000 - }, - "system_cpu_usage": 185683050000000, - "online_cpus": 8, - "throttling_data": { - "periods": 0, - "throttled_periods": 0, - "throttled_time": 0 - } - }, - "memory_stats": { - "usage": 1404354560, - "max_usage": 1404616704, - "limit": 8589934592 - }, - "name": "/job_c9868", - "id": "60fa7ab1c6dafdaa08ec3e2b95b16120757ac5cb7ebd512b3526b2d521623776", - "networks": { - "eth0": { - "rx_bytes": 758, - "rx_packets": 9, - "rx_errors": 0, - "rx_dropped": 0, - "tx_bytes": 0, - "tx_packets": 0, - "tx_errors": 0, - "tx_dropped": 0 - } - }} - - -class JobStats(): - - @classmethod - def get_new_stats(cls): - return {'memory': {'max': 0, - 'current': [0]}, - 'gpu_memory': {'max': 0, - 'current': [0]}, - 'cpu': {'max': 0, - 'current': [0]}, - 'gpu': {'max': 0, - 'current': []}, - 'io': {'max': 0, - 'current': []}, - 'netio': {'rx': 0, - 'tx': 0}, - 'time': 0} - - def get_temporary_text_file(contents, filename): """ Creates a temporary text file @@ -308,19 +202,6 @@ def get_sample_objective_metadata(): } -class FakeContainer(object): - def __init__(self): - self.c_stats = Stats.get_stats() - - def stats(self, decode, stream): - return self.c_stats - - -class FakeClient(object): - def __init__(self): - self.containers = {'job': FakeContainer()} - - class FakeMetrics(object): def __init__(self, filepath='path'): self.path = filepath diff --git a/substrabac/substrapp/tests/tests_misc.py b/substrabac/substrapp/tests/tests_misc.py index 77767fa2f..cae6b809a 100644 --- a/substrabac/substrapp/tests/tests_misc.py +++ b/substrabac/substrapp/tests/tests_misc.py @@ -1,10 +1,7 @@ from django.test import TestCase from mock import patch -from substrapp.tasks.utils import get_cpu_sets, get_gpu_sets, ExceptionThread, \ - update_statistics - -from substrapp.tests.common import JobStats, Stats, gpu +from substrapp.tasks.utils import get_cpu_sets, get_gpu_sets from substrapp.ledger_utils import LedgerNotFound, LedgerBadResponse @@ -38,43 +35,6 @@ def test_gpu_sets(self): self.assertFalse(get_gpu_sets([], concurrency)) - def test_exception_thread(self): - - training = ExceptionThread(target=lambda x, y: x / y, - args=(3, 0), - daemon=True) - - with patch('sys.stderr', new=MockDevice()): - training.start() - training.join() - - self.assertTrue(hasattr(training, '_exception')) - with self.assertRaises(ZeroDivisionError): - raise training._exception - - def test_update_statistics(self): - - # Statistics - - job_statistics = JobStats.get_new_stats() - tmp_statistics = JobStats.get_new_stats() - - update_statistics(job_statistics, None, None) - self.assertEqual(tmp_statistics, job_statistics) - - update_statistics(job_statistics, None, [gpu()]) - self.assertNotEqual(tmp_statistics, job_statistics) - self.assertEqual(job_statistics['gpu']['max'], 80) - self.assertEqual(job_statistics['gpu_memory']['max'], 1) - - job_statistics = JobStats.get_new_stats() - tmp_statistics = JobStats.get_new_stats() - update_statistics(job_statistics, Stats.get_stats(), None) - self.assertNotEqual(tmp_statistics, job_statistics) - self.assertNotEqual(job_statistics['memory']['max'], 0) - self.assertNotEqual(job_statistics['cpu']['max'], 0) - self.assertNotEqual(job_statistics['netio']['rx'], 0) - def test_get_object_from_ledger(self): with patch('substrapp.ledger_utils.query_ledger') as mquery_ledger: mquery_ledger.side_effect = LedgerNotFound('Not Found') diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 6bd00401d..7d22ce110 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -1,7 +1,6 @@ import os import shutil import mock -import time import uuid from unittest.mock import MagicMock @@ -14,14 +13,14 @@ from substrapp.ledger_utils import LedgerStatusError from substrapp.utils import store_datasamples_archive from substrapp.utils import compute_hash, get_remote_file, get_hash, create_directory -from substrapp.tasks.utils import ResourcesManager, monitoring_task, compute_docker, ExceptionThread +from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, put_model, put_models, put_algo, put_metric, put_data_sample, prepare_task, do_task, compute_task, remove_subtuple_materials, prepare_materials) from .common import (get_sample_algo, get_sample_script, get_sample_zip_data_sample, get_sample_tar_data_sample, get_sample_model) -from .common import FakeClient, FakeObjective, FakeDataManager, FakeModel, FakeRequest +from .common import FakeObjective, FakeDataManager, FakeModel, FakeRequest from . import assets from node.models import OutgoingNode @@ -105,17 +104,6 @@ def test_Ressource_Manager(self): if gpu_set is not None: self.assertIn(gpu_set, self.ResourcesManager._ResourcesManager__gpu_sets) - def test_monitoring_task(self): - - monitoring = ExceptionThread(target=monitoring_task, args=(FakeClient(), {'name': 'job'})) - monitoring.start() - time.sleep(0.1) - monitoring.join() - - self.assertNotEqual(monitoring._stats['memory']['max'], 0) - self.assertNotEqual(monitoring._stats['cpu']['max'], 0) - self.assertNotEqual(monitoring._stats['netio']['rx'], 0) - def test_put_algo_tar(self): algo_content = self.algo.read() subtuple_key = get_hash(self.algo) @@ -495,18 +483,13 @@ def test_compute_docker(self): f.write('FROM library/hello-world') hash_docker = uuid.uuid4().hex - result = compute_docker(client, self.ResourcesManager, - self.subtuple_path, 'test_compute_docker_' + hash_docker, - 'test_compute_docker_name_' + hash_docker, None, None) + compute_docker(client, self.ResourcesManager, + self.subtuple_path, 'test_compute_docker_' + hash_docker, + 'test_compute_docker_name_' + hash_docker, None, None) self.assertIsNone(cpu_set) self.assertIsNone(gpu_set) - self.assertIn('CPU', result) - self.assertIn('GPU', result) - self.assertIn('Mem', result) - self.assertIn('GPU Mem', result) - def test_build_subtuple_folders(self): with mock.patch('substrapp.tasks.tasks.getattr') as getattr: getattr.return_value = self.subtuple_path From 122a0809371fcb19204ab919849df973ed16f4a4 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 26 Sep 2019 17:17:10 +0200 Subject: [PATCH 303/457] Remove useless log. --- substrabac/substrapp/ledger_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index b533d5ac1..bb5a61bdb 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -243,7 +243,7 @@ def log_success_tuple(tuple_type, tuple_key, res): 'storageAddress': res["end_model_file"], }, 'perf': float(res["global_perf"]), - 'log': 'success', + 'log': '', } elif tuple_type == 'testtuple': @@ -251,7 +251,7 @@ def log_success_tuple(tuple_type, tuple_key, res): invoke_args = { 'key': tuple_key, 'perf': float(res["global_perf"]), - 'log': 'success', + 'log': '', } else: From a950e926b6fa61872c9c16a7837f3623127037da Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 23 Sep 2019 18:11:14 +0200 Subject: [PATCH 304/457] Update to new chaincode --- .../substrapp/management/commands/createdataset.py | 8 +++++--- .../management/commands/createobjective.py | 14 ++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/substrabac/substrapp/management/commands/createdataset.py b/substrabac/substrapp/management/commands/createdataset.py index 71db99bc7..23e3edbd6 100644 --- a/substrabac/substrapp/management/commands/createdataset.py +++ b/substrabac/substrapp/management/commands/createdataset.py @@ -21,11 +21,11 @@ def path_leaf(path): class Command(BaseCommand): help = ''' # noqa create dataset - python ./manage.py createdataset '{"data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo", "objective_keys": []}, "data_samples": {"paths": ["./data.zip", "./train/data"], "test_only": false}}' + python ./manage.py createdataset '{"data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo", "objective_keys": [], "permissions": {"public": True, "authorized_ids": []}}, "data_samples": {"paths": ["./data.zip", "./train/data"], "test_only": false}}' python ./manage.py createdataset dataset.json # datamanager.json: # objective_keys are optional - # {"data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo", "objective_keys": []}, "data_samples": {"paths": ["./data.zip", "./train/data"], "test_only": false}} + # {"data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo", "objective_keys": [], "permissions": {"public": True, "authorized_ids": []}}, "data_samples": {"paths": ["./data.zip", "./train/data"], "test_only": false}} ''' def add_arguments(self, parser): @@ -58,6 +58,8 @@ def handle(self, *args, **options): return self.stderr.write('Please provide a data_opener to your data_manager') if 'description' not in data_manager: return self.stderr.write('Please provide a description to your data_manager') + if 'permissions' not in data_manager: + return self.stderr.write('Please provide permissions to your data_manager') data_samples = data_input.get('data_samples', None) if data_samples is None: @@ -98,7 +100,7 @@ def handle(self, *args, **options): # init ledger serializer ledger_serializer = LedgerDataManagerSerializer( data={'name': data_manager['name'], - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': data_manager['permissions'], 'type': data_manager['type'], 'objective_keys': data_manager.get('objective_keys', []), 'instance': instance}, diff --git a/substrabac/substrapp/management/commands/createobjective.py b/substrabac/substrapp/management/commands/createobjective.py index 24649de4b..4835d5433 100644 --- a/substrabac/substrapp/management/commands/createobjective.py +++ b/substrabac/substrapp/management/commands/createobjective.py @@ -21,10 +21,10 @@ def path_leaf(path): class Command(BaseCommand): help = ''' # noqa create objective - python ./manage.py createobjective '{"objective": {"name": "foo", "metrics_name": "accuracy", "metrics": "./metrics.py", "description": "./description.md"}, "data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo"}, "data_samples": {"paths": ["./data.zip", "./train/data"]}}' + python ./manage.py createobjective '{"objective": {"name": "foo", "metrics_name": "accuracy", "metrics": "./metrics.py", "description": "./description.md", "permissions": {"public": True, "authorized_ids": []}}, "data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo", "permissions": {"public": True, "authorized_ids": []}, "data_samples": {"paths": ["./data.zip", "./train/data"]}}' python ./manage.py createobjective objective.json # objective.json: - # {"objective": {"name": "foo", "metrics_name": "accuracy", "metrics": "./metrics.py", "description": "./description.md"}, "data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo"}, "data_samples": {"paths": ["./data.zip", "./train/data"]}} + # {"objective": {"name": "foo", "metrics_name": "accuracy", "metrics": "./metrics.py", "description": "./description.md", "permissions": {"public": True, "authorized_ids": []}, "data_manager": {"name": "foo", "data_opener": "./opener.py", "description": "./description.md", "type": "foo", "permissions": {"public": True, "authorized_ids": []}, "data_samples": {"paths": ["./data.zip", "./train/data"]}} ''' def add_arguments(self, parser): @@ -61,6 +61,9 @@ def handle(self, *args, **options): if 'description' not in data_manager: return self.stderr.write( 'Please provide a description to your data_manager') + if 'permissions' not in data_manager: + return self.stderr.write( + 'Please provide permissions to your data_manager') # get data and check data_samples = data_input.get('data_samples', None) @@ -84,6 +87,9 @@ def handle(self, *args, **options): if 'description' not in objective: return self.stderr.write( 'Please provide a description to your objective') + if 'permissions' not in objective: + return self.stderr.write( + 'Please provide permissions to your objective') # by default data need to be test_only data_samples['test_only'] = True @@ -119,7 +125,7 @@ def handle(self, *args, **options): # init ledger serializer ledger_serializer = LedgerDataManagerSerializer( data={'name': data_manager['name'], - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': data_manager['permissions'], 'type': data_manager['type'], 'instance': instance}, context={'request': LocalRequest()}) @@ -203,7 +209,7 @@ def handle(self, *args, **options): # init ledger serializer ledger_serializer = LedgerObjectiveSerializer( data={'name': objective['name'], - 'permissions': {'public': True, 'authorized_ids': []}, + 'permissions': objective['permissions'], 'metrics_name': objective['metrics_name'], 'test_data_sample_keys': objective.get('test_data_sample_keys', []), 'test_data_manager_key': objective.get('test_data_manager_key', ''), From d5115239434642847dfae1b0443d55b2cbdb4abb Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 23 Sep 2019 14:09:41 +0200 Subject: [PATCH 305/457] No download for user on model file view --- substrabac/substrapp/views/model.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index 7175155ee..ca2428e5c 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -7,6 +7,7 @@ from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet +from node.authentication import NodeUser from substrapp.models import Model from substrapp.serializers import ModelSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError @@ -116,6 +117,11 @@ class ModelPermissionViewSet(PermissionMixin, @action(detail=True) def file(self, request, *args, **kwargs): + + # user cannot download model, only node can + if not isinstance(request.user, NodeUser): + return Response({}, status=status.HTTP_403_FORBIDDEN) + model_object = self.get_object() data = getattr(model_object, 'file') return CustomFileResponse(open(data.path, 'rb'), as_attachment=True, filename=os.path.basename(data.path)) From 7d6aaf370773c0806a2c02c9856bf886edee821b Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 26 Sep 2019 11:26:07 +0200 Subject: [PATCH 306/457] Add missing migrations --- substrabac/node/migrations/0002_nodeuser.py | 32 +++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 substrabac/node/migrations/0002_nodeuser.py diff --git a/substrabac/node/migrations/0002_nodeuser.py b/substrabac/node/migrations/0002_nodeuser.py new file mode 100644 index 000000000..9eaca568a --- /dev/null +++ b/substrabac/node/migrations/0002_nodeuser.py @@ -0,0 +1,32 @@ +# Generated by Django 2.1.2 on 2019-09-26 09:25 + +from django.conf import settings +import django.contrib.auth.models +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0009_alter_user_last_name_max_length'), + ('node', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='NodeUser', + fields=[ + ('user_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'abstract': False, + }, + bases=('auth.user',), + managers=[ + ('objects', django.contrib.auth.models.UserManager()), + ], + ), + ] From ac457a168427612083039b2454d74898ef6c246b Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 26 Sep 2019 12:15:12 +0200 Subject: [PATCH 307/457] Update flake8 --- .flake8 | 1 + 1 file changed, 1 insertion(+) diff --git a/.flake8 b/.flake8 index 63caeb3d6..36cc911aa 100644 --- a/.flake8 +++ b/.flake8 @@ -4,4 +4,5 @@ ignore = E402, W504, F403, F405 exclude = substrabac/substrapp/migrations/*, substrabac/substrapp/tests/assets.py, substrabac/substrabac/settings/*, + substrabac/node/migrations/*, .env, .venv From d2fa2b07ff9ae6be4c188b5b75b30d45286804f3 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 26 Sep 2019 17:56:40 +0200 Subject: [PATCH 308/457] Make IncomingNodes secret hashed and salted --- substrabac/node/apps.py | 7 +++++++ substrabac/node/authentication.py | 19 +++++++++++-------- substrabac/node/models.py | 17 +++++++++++++++++ substrabac/node/signals/__init__.py | 0 substrabac/node/signals/node/__init__.py | 0 substrabac/node/signals/node/pre_save.py | 2 ++ 6 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 substrabac/node/signals/__init__.py create mode 100644 substrabac/node/signals/node/__init__.py create mode 100644 substrabac/node/signals/node/pre_save.py diff --git a/substrabac/node/apps.py b/substrabac/node/apps.py index ffb6c1d7d..311682ad9 100644 --- a/substrabac/node/apps.py +++ b/substrabac/node/apps.py @@ -1,5 +1,12 @@ from django.apps import AppConfig +from django.db.models.signals import pre_save class NodeConfig(AppConfig): name = 'node' + + def ready(self): + from node.models import IncomingNode + from node.signals.node.pre_save import node_pre_save + + pre_save.connect(node_pre_save, sender=IncomingNode) diff --git a/substrabac/node/authentication.py b/substrabac/node/authentication.py index af2578de7..2466e9894 100644 --- a/substrabac/node/authentication.py +++ b/substrabac/node/authentication.py @@ -1,4 +1,6 @@ from django.contrib.auth.models import User +from django.core.exceptions import ObjectDoesNotExist + from .models import IncomingNode @@ -12,17 +14,18 @@ class NodeBackend: def authenticate(self, request, username=None, password=None): """Check the username/password and return a user.""" - node_id = username - secret = password - - if not node_id or not secret: + if not username or not password: return None - incoming_node_exists = IncomingNode.objects.filter(node_id=node_id, secret=secret).exists() - if incoming_node_exists: - return NodeUser(username=node_id) + try: + node = IncomingNode.objects.get(node_id=username) + except ObjectDoesNotExist: + return None + else: + if node.check_password(password): + return NodeUser(username=username) - return None + return None def get_user(self, user_id): # required for session diff --git a/substrabac/node/models.py b/substrabac/node/models.py index 73c5f7a19..084673d40 100644 --- a/substrabac/node/models.py +++ b/substrabac/node/models.py @@ -1,3 +1,4 @@ +from django.contrib.auth.hashers import make_password, check_password, is_password_usable from django.db import models import secrets @@ -11,6 +12,22 @@ class Node(models.Model): def generate_secret(): return secrets.token_hex(64) + def set_password(self, raw_secret): + self.secret = make_password(raw_secret) + self._secret = raw_secret + + def check_password(self, raw_secret): + """ + Return a boolean of whether the raw_password was correct. Handles + hashing formats behind the scenes. + """ + def setter(raw_secret): + self.set_password(raw_secret) + # Password hash upgrades shouldn't be considered password changes. + self._secret = None + self.save(update_fields=["secret"]) + return check_password(raw_secret, self.secret, setter) + class Meta: abstract = True diff --git a/substrabac/node/signals/__init__.py b/substrabac/node/signals/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/node/signals/node/__init__.py b/substrabac/node/signals/node/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/node/signals/node/pre_save.py b/substrabac/node/signals/node/pre_save.py new file mode 100644 index 000000000..254cd664d --- /dev/null +++ b/substrabac/node/signals/node/pre_save.py @@ -0,0 +1,2 @@ +def node_pre_save(sender, instance, **kwargs): + instance.set_password(instance.secret) From 4079078f70160c9a3ee0e7c2143dda930fd611d2 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 26 Sep 2019 18:00:44 +0200 Subject: [PATCH 309/457] flake8 --- substrabac/node/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/node/models.py b/substrabac/node/models.py index 084673d40..16deceb02 100644 --- a/substrabac/node/models.py +++ b/substrabac/node/models.py @@ -1,4 +1,4 @@ -from django.contrib.auth.hashers import make_password, check_password, is_password_usable +from django.contrib.auth.hashers import make_password, check_password from django.db import models import secrets From cfbb25bb658fb6250cc848cdc20e4b6ead1486be Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 20:29:50 +0200 Subject: [PATCH 310/457] Hot fix- missing declaration --- substrabac/node-register/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/substrabac/node-register/__init__.py b/substrabac/node-register/__init__.py index e69de29bb..39b356278 100644 --- a/substrabac/node-register/__init__.py +++ b/substrabac/node-register/__init__.py @@ -0,0 +1 @@ +default_app_config = 'node-register.apps.NodeRegisterConfig' From 824f8dfa46c25ab5bc24c959672f9767982a30b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 16 Sep 2019 17:14:56 +0200 Subject: [PATCH 311/457] nodes list: added endpoint --- .../tests/views/tests_views_permissionnode.py | 55 +++++++++++++++++++ substrabac/substrapp/urls.py | 3 +- substrabac/substrapp/views/__init__.py | 4 +- substrabac/substrapp/views/permissionnode.py | 15 +++++ 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 substrabac/substrapp/tests/views/tests_views_permissionnode.py create mode 100644 substrabac/substrapp/views/permissionnode.py diff --git a/substrabac/substrapp/tests/views/tests_views_permissionnode.py b/substrabac/substrapp/tests/views/tests_views_permissionnode.py new file mode 100644 index 000000000..5b8b3030c --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_permissionnode.py @@ -0,0 +1,55 @@ +import os +import logging +import shutil + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework.test import APITestCase + +from ..common import AuthenticatedClient + +MEDIA_ROOT = "/tmp/unittests_views/" + + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +class ModelViewTests(APITestCase): + client_class = AuthenticatedClient + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_model_list_empty(self): + url = reverse('substrapp:permission_node-list') + with mock.patch('substrapp.views.permissionnode.query_ledger') as mquery_ledger: + mquery_ledger.return_value = {'node_ids': []} + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, {'node_ids': []}) + + def test_model_list_success(self): + url = reverse('substrapp:permission_node-list') + with mock.patch('substrapp.views.permissionnode.query_ledger') as mquery_ledger: + mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, {'node_ids': ['foo', 'bar']}) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index 0a892f0e0..f9aade66c 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -8,7 +8,7 @@ from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet, \ - ModelPermissionViewSet + ModelPermissionViewSet, PermissionNodeViewSet # Create a router and register our viewsets with it. @@ -26,6 +26,7 @@ router.register(r'testtuple', TestTupleViewSet, base_name='testtuple') router.register(r'task', TaskViewSet, base_name='task') router.register(r'compute_plan', ComputePlanViewSet, base_name='compute_plan') +router.register(r'permission_node', PermissionNodeViewSet, base_name='permission_node') urlpatterns = [ url(r'^', include(router.urls)), diff --git a/substrabac/substrapp/views/__init__.py b/substrabac/substrapp/views/__init__.py index 54a7b8a79..53adde639 100644 --- a/substrabac/substrapp/views/__init__.py +++ b/substrabac/substrapp/views/__init__.py @@ -9,7 +9,9 @@ from .testtuple import TestTupleViewSet from .task import TaskViewSet from .computeplan import ComputePlanViewSet +from .permissionnode import PermissionNodeViewSet __all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'DataManagerPermissionViewSet', 'ObjectiveViewSet', 'ObjectivePermissionViewSet', 'ModelViewSet', 'ModelPermissionViewSet', 'AlgoViewSet', - 'AlgoPermissionViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet'] + 'AlgoPermissionViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet', + 'PermissionNodeViewSet'] diff --git a/substrabac/substrapp/views/permissionnode.py b/substrabac/substrapp/views/permissionnode.py new file mode 100644 index 000000000..bea4ef33e --- /dev/null +++ b/substrabac/substrapp/views/permissionnode.py @@ -0,0 +1,15 @@ +from rest_framework import status +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet + +from substrapp.ledger_utils import query_ledger, LedgerError + + +class PermissionNodeViewSet(GenericViewSet): + def list(self, request, *args, **kwargs): + try: + permission_nodes = query_ledger(fcn='queryPermissionNodes') + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + + return Response(permission_nodes, status=status.HTTP_200_OK) From 16d4f6eed714484514f2500706f6baebd416fad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 18 Sep 2019 16:40:07 +0200 Subject: [PATCH 312/457] add current node view --- ..._permissionnode.py => tests_views_node.py} | 25 +++++++++++----- substrabac/substrapp/urls.py | 4 +-- substrabac/substrapp/views/__init__.py | 4 +-- substrabac/substrapp/views/node.py | 30 +++++++++++++++++++ substrabac/substrapp/views/permissionnode.py | 15 ---------- 5 files changed, 51 insertions(+), 27 deletions(-) rename substrabac/substrapp/tests/views/{tests_views_permissionnode.py => tests_views_node.py} (61%) create mode 100644 substrabac/substrapp/views/node.py delete mode 100644 substrabac/substrapp/views/permissionnode.py diff --git a/substrabac/substrapp/tests/views/tests_views_permissionnode.py b/substrabac/substrapp/tests/views/tests_views_node.py similarity index 61% rename from substrabac/substrapp/tests/views/tests_views_permissionnode.py rename to substrabac/substrapp/tests/views/tests_views_node.py index 5b8b3030c..4139304ce 100644 --- a/substrabac/substrapp/tests/views/tests_views_permissionnode.py +++ b/substrabac/substrapp/tests/views/tests_views_node.py @@ -36,20 +36,29 @@ def tearDown(self): self.logger.setLevel(self.previous_level) - def test_model_list_empty(self): - url = reverse('substrapp:permission_node-list') - with mock.patch('substrapp.views.permissionnode.query_ledger') as mquery_ledger: + def test_node_list_empty(self): + url = reverse('substrapp:node-list') + with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: mquery_ledger.return_value = {'node_ids': []} response = self.client.get(url, **self.extra) r = response.json() - self.assertEqual(r, {'node_ids': []}) + self.assertEqual(r, []) - def test_model_list_success(self): - url = reverse('substrapp:permission_node-list') - with mock.patch('substrapp.views.permissionnode.query_ledger') as mquery_ledger: + def test_node_list_success(self): + url = reverse('substrapp:node-list') + with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} response = self.client.get(url, **self.extra) r = response.json() - self.assertEqual(r, {'node_ids': ['foo', 'bar']}) + self.assertEqual(r, [{'node_id': 'foo'}, {'node_id': 'bar'}]) + + def test_current_node(self): + url = reverse('substrapp:node-current') + with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: + mquery_ledger.return_value = 'foo' + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, {'node_id': 'foo'}) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index f9aade66c..58de4467e 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -8,7 +8,7 @@ from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet, \ - ModelPermissionViewSet, PermissionNodeViewSet + ModelPermissionViewSet, NodeViewSet # Create a router and register our viewsets with it. @@ -26,7 +26,7 @@ router.register(r'testtuple', TestTupleViewSet, base_name='testtuple') router.register(r'task', TaskViewSet, base_name='task') router.register(r'compute_plan', ComputePlanViewSet, base_name='compute_plan') -router.register(r'permission_node', PermissionNodeViewSet, base_name='permission_node') +router.register(r'node', NodeViewSet, base_name='node') urlpatterns = [ url(r'^', include(router.urls)), diff --git a/substrabac/substrapp/views/__init__.py b/substrabac/substrapp/views/__init__.py index 53adde639..989d5a8a8 100644 --- a/substrabac/substrapp/views/__init__.py +++ b/substrabac/substrapp/views/__init__.py @@ -9,9 +9,9 @@ from .testtuple import TestTupleViewSet from .task import TaskViewSet from .computeplan import ComputePlanViewSet -from .permissionnode import PermissionNodeViewSet +from .node import NodeViewSet __all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'DataManagerPermissionViewSet', 'ObjectiveViewSet', 'ObjectivePermissionViewSet', 'ModelViewSet', 'ModelPermissionViewSet', 'AlgoViewSet', 'AlgoPermissionViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet', - 'PermissionNodeViewSet'] + 'NodeViewSet'] diff --git a/substrabac/substrapp/views/node.py b/substrabac/substrapp/views/node.py new file mode 100644 index 000000000..35cf36450 --- /dev/null +++ b/substrabac/substrapp/views/node.py @@ -0,0 +1,30 @@ +from rest_framework import status +from rest_framework.decorators import action +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet + +from substrapp.ledger_utils import query_ledger, LedgerError + + +class NodeViewSet(GenericViewSet): + def list(self, request, *args, **kwargs): + try: + res = query_ledger(fcn='queryPermissionNodes') + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + + nodes = [ + {'node_id': node_id} + for node_id in res['node_ids'] + ] + + return Response(nodes, status=status.HTTP_200_OK) + + @action(detail=False, methods=['GET']) + def current(self, request): + try: + res = query_ledger(fcn='queryCurrentPermissionNode') + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + + return Response({'node_id': res}, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/permissionnode.py b/substrabac/substrapp/views/permissionnode.py deleted file mode 100644 index bea4ef33e..000000000 --- a/substrabac/substrapp/views/permissionnode.py +++ /dev/null @@ -1,15 +0,0 @@ -from rest_framework import status -from rest_framework.response import Response -from rest_framework.viewsets import GenericViewSet - -from substrapp.ledger_utils import query_ledger, LedgerError - - -class PermissionNodeViewSet(GenericViewSet): - def list(self, request, *args, **kwargs): - try: - permission_nodes = query_ledger(fcn='queryPermissionNodes') - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) - - return Response(permission_nodes, status=status.HTTP_200_OK) From ec0db9d268588a094e918f3131a5ceae2115bfa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Thu, 19 Sep 2019 14:24:43 +0200 Subject: [PATCH 313/457] remove current view --- substrabac/substrapp/tests/views/tests_views_node.py | 9 --------- substrabac/substrapp/views/node.py | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_node.py b/substrabac/substrapp/tests/views/tests_views_node.py index 4139304ce..a07a89866 100644 --- a/substrabac/substrapp/tests/views/tests_views_node.py +++ b/substrabac/substrapp/tests/views/tests_views_node.py @@ -53,12 +53,3 @@ def test_node_list_success(self): response = self.client.get(url, **self.extra) r = response.json() self.assertEqual(r, [{'node_id': 'foo'}, {'node_id': 'bar'}]) - - def test_current_node(self): - url = reverse('substrapp:node-current') - with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = 'foo' - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, {'node_id': 'foo'}) diff --git a/substrabac/substrapp/views/node.py b/substrabac/substrapp/views/node.py index 35cf36450..67018f5a7 100644 --- a/substrabac/substrapp/views/node.py +++ b/substrabac/substrapp/views/node.py @@ -1,5 +1,4 @@ from rest_framework import status -from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet @@ -19,12 +18,3 @@ def list(self, request, *args, **kwargs): ] return Response(nodes, status=status.HTTP_200_OK) - - @action(detail=False, methods=['GET']) - def current(self, request): - try: - res = query_ledger(fcn='queryCurrentPermissionNode') - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) - - return Response({'node_id': res}, status=status.HTTP_200_OK) From 5544aef8d4f5da8eac7010e68e20635450a81d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Fri, 20 Sep 2019 11:27:46 +0200 Subject: [PATCH 314/457] add node.isCurrent prop + camlcase --- .../substrapp/tests/views/tests_views_node.py | 22 ++++++++----------- substrabac/substrapp/views/node.py | 8 +++++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_node.py b/substrabac/substrapp/tests/views/tests_views_node.py index a07a89866..7082df55f 100644 --- a/substrabac/substrapp/tests/views/tests_views_node.py +++ b/substrabac/substrapp/tests/views/tests_views_node.py @@ -36,20 +36,16 @@ def tearDown(self): self.logger.setLevel(self.previous_level) - def test_node_list_empty(self): - url = reverse('substrapp:node-list') - with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'node_ids': []} - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, []) - def test_node_list_success(self): url = reverse('substrapp:node-list') with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [{'node_id': 'foo'}, {'node_id': 'bar'}]) + with mock.patch('substrapp.views.node.get_owner') as mget_owner: + mget_owner.return_value = 'foo' + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [ + {'nodeID': 'foo', 'isCurrent': True}, + {'nodeID': 'bar', 'isCurrent': False} + ]) diff --git a/substrabac/substrapp/views/node.py b/substrabac/substrapp/views/node.py index 67018f5a7..4deae184e 100644 --- a/substrabac/substrapp/views/node.py +++ b/substrabac/substrapp/views/node.py @@ -3,6 +3,7 @@ from rest_framework.viewsets import GenericViewSet from substrapp.ledger_utils import query_ledger, LedgerError +from substrapp.utils import get_owner class NodeViewSet(GenericViewSet): @@ -12,9 +13,12 @@ def list(self, request, *args, **kwargs): except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) + current_node_id = get_owner() nodes = [ - {'node_id': node_id} + { + 'nodeID': node_id, + 'isCurrent': node_id == current_node_id, + } for node_id in res['node_ids'] ] - return Response(nodes, status=status.HTTP_200_OK) From 3f8406b58daef9a432e60554b977ab98a77dc434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Fri, 20 Sep 2019 16:28:31 +0200 Subject: [PATCH 315/457] fix use of camelcase in ledger response --- substrabac/substrapp/tests/views/tests_views_node.py | 2 +- substrabac/substrapp/views/node.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_node.py b/substrabac/substrapp/tests/views/tests_views_node.py index 7082df55f..bfe00f877 100644 --- a/substrabac/substrapp/tests/views/tests_views_node.py +++ b/substrabac/substrapp/tests/views/tests_views_node.py @@ -39,7 +39,7 @@ def tearDown(self): def test_node_list_success(self): url = reverse('substrapp:node-list') with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} + mquery_ledger.return_value = {'nodeIDs': ['foo', 'bar']} with mock.patch('substrapp.views.node.get_owner') as mget_owner: mget_owner.return_value = 'foo' diff --git a/substrabac/substrapp/views/node.py b/substrabac/substrapp/views/node.py index 4deae184e..e7d08433d 100644 --- a/substrabac/substrapp/views/node.py +++ b/substrabac/substrapp/views/node.py @@ -19,6 +19,6 @@ def list(self, request, *args, **kwargs): 'nodeID': node_id, 'isCurrent': node_id == current_node_id, } - for node_id in res['node_ids'] + for node_id in res['nodeIDs'] ] return Response(nodes, status=status.HTTP_200_OK) From 571a08e6139345b0951673643ec19bbad126a2b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Thu, 26 Sep 2019 16:07:01 +0200 Subject: [PATCH 316/457] follow new chaincode return format --- .../substrapp/tests/views/tests_views_node.py | 6 +++--- substrabac/substrapp/views/node.py | 13 +++++-------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_node.py b/substrabac/substrapp/tests/views/tests_views_node.py index bfe00f877..173a09e67 100644 --- a/substrabac/substrapp/tests/views/tests_views_node.py +++ b/substrabac/substrapp/tests/views/tests_views_node.py @@ -39,13 +39,13 @@ def tearDown(self): def test_node_list_success(self): url = reverse('substrapp:node-list') with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'nodeIDs': ['foo', 'bar']} + mquery_ledger.return_value = [{'ID': 'foo'}, {'ID': 'bar'}] with mock.patch('substrapp.views.node.get_owner') as mget_owner: mget_owner.return_value = 'foo' response = self.client.get(url, **self.extra) r = response.json() self.assertEqual(r, [ - {'nodeID': 'foo', 'isCurrent': True}, - {'nodeID': 'bar', 'isCurrent': False} + {'ID': 'foo', 'isCurrent': True}, + {'ID': 'bar', 'isCurrent': False} ]) diff --git a/substrabac/substrapp/views/node.py b/substrabac/substrapp/views/node.py index e7d08433d..7a86731b5 100644 --- a/substrabac/substrapp/views/node.py +++ b/substrabac/substrapp/views/node.py @@ -9,16 +9,13 @@ class NodeViewSet(GenericViewSet): def list(self, request, *args, **kwargs): try: - res = query_ledger(fcn='queryPermissionNodes') + nodes = query_ledger(fcn='queryPermissionNodes') except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) current_node_id = get_owner() - nodes = [ - { - 'nodeID': node_id, - 'isCurrent': node_id == current_node_id, - } - for node_id in res['nodeIDs'] - ] + for node in nodes: + node.update({ + 'isCurrent': node['ID'] == current_node_id, + }) return Response(nodes, status=status.HTTP_200_OK) From 00a0e44edc27a4182b7d831b759dead12248e856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Thu, 26 Sep 2019 17:03:40 +0200 Subject: [PATCH 317/457] fix ledger method --- substrabac/substrapp/tests/views/tests_views_node.py | 6 +++--- substrabac/substrapp/views/node.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_node.py b/substrabac/substrapp/tests/views/tests_views_node.py index 173a09e67..dba6ef3ab 100644 --- a/substrabac/substrapp/tests/views/tests_views_node.py +++ b/substrabac/substrapp/tests/views/tests_views_node.py @@ -39,13 +39,13 @@ def tearDown(self): def test_node_list_success(self): url = reverse('substrapp:node-list') with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = [{'ID': 'foo'}, {'ID': 'bar'}] + mquery_ledger.return_value = [{'id': 'foo'}, {'id': 'bar'}] with mock.patch('substrapp.views.node.get_owner') as mget_owner: mget_owner.return_value = 'foo' response = self.client.get(url, **self.extra) r = response.json() self.assertEqual(r, [ - {'ID': 'foo', 'isCurrent': True}, - {'ID': 'bar', 'isCurrent': False} + {'id': 'foo', 'isCurrent': True}, + {'id': 'bar', 'isCurrent': False} ]) diff --git a/substrabac/substrapp/views/node.py b/substrabac/substrapp/views/node.py index 7a86731b5..245ac8be1 100644 --- a/substrabac/substrapp/views/node.py +++ b/substrabac/substrapp/views/node.py @@ -9,13 +9,13 @@ class NodeViewSet(GenericViewSet): def list(self, request, *args, **kwargs): try: - nodes = query_ledger(fcn='queryPermissionNodes') + nodes = query_ledger(fcn='queryNodes') except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) current_node_id = get_owner() for node in nodes: node.update({ - 'isCurrent': node['ID'] == current_node_id, + 'isCurrent': node['id'] == current_node_id, }) return Response(nodes, status=status.HTTP_200_OK) From 963b9f45fa60894465584c0764826e474c61d410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Fri, 27 Sep 2019 10:42:55 +0200 Subject: [PATCH 318/457] explicit override of list method in nodeviewset --- substrabac/substrapp/views/node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/views/node.py b/substrabac/substrapp/views/node.py index 245ac8be1..3a0e7c8fa 100644 --- a/substrabac/substrapp/views/node.py +++ b/substrabac/substrapp/views/node.py @@ -1,4 +1,4 @@ -from rest_framework import status +from rest_framework import status, mixins from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet @@ -6,7 +6,7 @@ from substrapp.utils import get_owner -class NodeViewSet(GenericViewSet): +class NodeViewSet(mixins.ListModelMixin, GenericViewSet): def list(self, request, *args, **kwargs): try: nodes = query_ledger(fcn='queryNodes') From 6f44bb1003ba3745ae3aa1ae705f3bd2009ad97d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 16 Sep 2019 17:14:56 +0200 Subject: [PATCH 319/457] nodes list: added endpoint --- .../tests/views/tests_views_permissionnode.py | 55 +++++++++++++++++++ substrabac/substrapp/urls.py | 3 +- substrabac/substrapp/views/__init__.py | 3 +- substrabac/substrapp/views/permissionnode.py | 15 +++++ 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 substrabac/substrapp/tests/views/tests_views_permissionnode.py create mode 100644 substrabac/substrapp/views/permissionnode.py diff --git a/substrabac/substrapp/tests/views/tests_views_permissionnode.py b/substrabac/substrapp/tests/views/tests_views_permissionnode.py new file mode 100644 index 000000000..5b8b3030c --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_views_permissionnode.py @@ -0,0 +1,55 @@ +import os +import logging +import shutil + +import mock + +from django.urls import reverse +from django.test import override_settings + +from rest_framework.test import APITestCase + +from ..common import AuthenticatedClient + +MEDIA_ROOT = "/tmp/unittests_views/" + + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) +@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) +class ModelViewTests(APITestCase): + client_class = AuthenticatedClient + + def setUp(self): + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + + self.extra = { + 'HTTP_ACCEPT': 'application/json;version=0.0' + } + + self.logger = logging.getLogger('django.request') + self.previous_level = self.logger.getEffectiveLevel() + self.logger.setLevel(logging.ERROR) + + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + + self.logger.setLevel(self.previous_level) + + def test_model_list_empty(self): + url = reverse('substrapp:permission_node-list') + with mock.patch('substrapp.views.permissionnode.query_ledger') as mquery_ledger: + mquery_ledger.return_value = {'node_ids': []} + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, {'node_ids': []}) + + def test_model_list_success(self): + url = reverse('substrapp:permission_node-list') + with mock.patch('substrapp.views.permissionnode.query_ledger') as mquery_ledger: + mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, {'node_ids': ['foo', 'bar']}) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index 58de4467e..39a6e30f9 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -8,7 +8,7 @@ from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet, \ - ModelPermissionViewSet, NodeViewSet + ModelPermissionViewSet, NodeViewSet, PermissionNodeViewSet # Create a router and register our viewsets with it. @@ -27,6 +27,7 @@ router.register(r'task', TaskViewSet, base_name='task') router.register(r'compute_plan', ComputePlanViewSet, base_name='compute_plan') router.register(r'node', NodeViewSet, base_name='node') +router.register(r'permission_node', PermissionNodeViewSet, base_name='permission_node') urlpatterns = [ url(r'^', include(router.urls)), diff --git a/substrabac/substrapp/views/__init__.py b/substrabac/substrapp/views/__init__.py index 989d5a8a8..af13c3bab 100644 --- a/substrabac/substrapp/views/__init__.py +++ b/substrabac/substrapp/views/__init__.py @@ -10,8 +10,9 @@ from .task import TaskViewSet from .computeplan import ComputePlanViewSet from .node import NodeViewSet +from .permissionnode import PermissionNodeViewSet __all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'DataManagerPermissionViewSet', 'ObjectiveViewSet', 'ObjectivePermissionViewSet', 'ModelViewSet', 'ModelPermissionViewSet', 'AlgoViewSet', 'AlgoPermissionViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet', - 'NodeViewSet'] + 'NodeViewSet', 'PermissionNodeViewSet'] diff --git a/substrabac/substrapp/views/permissionnode.py b/substrabac/substrapp/views/permissionnode.py new file mode 100644 index 000000000..bea4ef33e --- /dev/null +++ b/substrabac/substrapp/views/permissionnode.py @@ -0,0 +1,15 @@ +from rest_framework import status +from rest_framework.response import Response +from rest_framework.viewsets import GenericViewSet + +from substrapp.ledger_utils import query_ledger, LedgerError + + +class PermissionNodeViewSet(GenericViewSet): + def list(self, request, *args, **kwargs): + try: + permission_nodes = query_ledger(fcn='queryPermissionNodes') + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + + return Response(permission_nodes, status=status.HTTP_200_OK) From b52bc8b2918f9c73700965f34fabd00215e4c4d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 18 Sep 2019 16:40:07 +0200 Subject: [PATCH 320/457] add current node view --- .../substrapp/tests/views/tests_views_node.py | 33 +++++++---- .../tests/views/tests_views_permissionnode.py | 55 ------------------- substrabac/substrapp/urls.py | 7 +++ substrabac/substrapp/views/__init__.py | 3 +- substrabac/substrapp/views/permissionnode.py | 15 ----- 5 files changed, 31 insertions(+), 82 deletions(-) delete mode 100644 substrabac/substrapp/tests/views/tests_views_permissionnode.py delete mode 100644 substrabac/substrapp/views/permissionnode.py diff --git a/substrabac/substrapp/tests/views/tests_views_node.py b/substrabac/substrapp/tests/views/tests_views_node.py index dba6ef3ab..4139304ce 100644 --- a/substrabac/substrapp/tests/views/tests_views_node.py +++ b/substrabac/substrapp/tests/views/tests_views_node.py @@ -36,16 +36,29 @@ def tearDown(self): self.logger.setLevel(self.previous_level) + def test_node_list_empty(self): + url = reverse('substrapp:node-list') + with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: + mquery_ledger.return_value = {'node_ids': []} + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, []) + def test_node_list_success(self): url = reverse('substrapp:node-list') with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = [{'id': 'foo'}, {'id': 'bar'}] - with mock.patch('substrapp.views.node.get_owner') as mget_owner: - mget_owner.return_value = 'foo' - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [ - {'id': 'foo', 'isCurrent': True}, - {'id': 'bar', 'isCurrent': False} - ]) + mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [{'node_id': 'foo'}, {'node_id': 'bar'}]) + + def test_current_node(self): + url = reverse('substrapp:node-current') + with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: + mquery_ledger.return_value = 'foo' + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, {'node_id': 'foo'}) diff --git a/substrabac/substrapp/tests/views/tests_views_permissionnode.py b/substrabac/substrapp/tests/views/tests_views_permissionnode.py deleted file mode 100644 index 5b8b3030c..000000000 --- a/substrabac/substrapp/tests/views/tests_views_permissionnode.py +++ /dev/null @@ -1,55 +0,0 @@ -import os -import logging -import shutil - -import mock - -from django.urls import reverse -from django.test import override_settings - -from rest_framework.test import APITestCase - -from ..common import AuthenticatedClient - -MEDIA_ROOT = "/tmp/unittests_views/" - - -@override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) -class ModelViewTests(APITestCase): - client_class = AuthenticatedClient - - def setUp(self): - if not os.path.exists(MEDIA_ROOT): - os.makedirs(MEDIA_ROOT) - - self.extra = { - 'HTTP_ACCEPT': 'application/json;version=0.0' - } - - self.logger = logging.getLogger('django.request') - self.previous_level = self.logger.getEffectiveLevel() - self.logger.setLevel(logging.ERROR) - - def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_model_list_empty(self): - url = reverse('substrapp:permission_node-list') - with mock.patch('substrapp.views.permissionnode.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'node_ids': []} - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, {'node_ids': []}) - - def test_model_list_success(self): - url = reverse('substrapp:permission_node-list') - with mock.patch('substrapp.views.permissionnode.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, {'node_ids': ['foo', 'bar']}) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index 39a6e30f9..ba17c95d7 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -8,7 +8,11 @@ from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet, \ +<<<<<<< HEAD ModelPermissionViewSet, NodeViewSet, PermissionNodeViewSet +======= + NodeViewSet +>>>>>>> add current node view # Create a router and register our viewsets with it. @@ -27,7 +31,10 @@ router.register(r'task', TaskViewSet, base_name='task') router.register(r'compute_plan', ComputePlanViewSet, base_name='compute_plan') router.register(r'node', NodeViewSet, base_name='node') +<<<<<<< HEAD router.register(r'permission_node', PermissionNodeViewSet, base_name='permission_node') +======= +>>>>>>> add current node view urlpatterns = [ url(r'^', include(router.urls)), diff --git a/substrabac/substrapp/views/__init__.py b/substrabac/substrapp/views/__init__.py index af13c3bab..989d5a8a8 100644 --- a/substrabac/substrapp/views/__init__.py +++ b/substrabac/substrapp/views/__init__.py @@ -10,9 +10,8 @@ from .task import TaskViewSet from .computeplan import ComputePlanViewSet from .node import NodeViewSet -from .permissionnode import PermissionNodeViewSet __all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'DataManagerPermissionViewSet', 'ObjectiveViewSet', 'ObjectivePermissionViewSet', 'ModelViewSet', 'ModelPermissionViewSet', 'AlgoViewSet', 'AlgoPermissionViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet', - 'NodeViewSet', 'PermissionNodeViewSet'] + 'NodeViewSet'] diff --git a/substrabac/substrapp/views/permissionnode.py b/substrabac/substrapp/views/permissionnode.py deleted file mode 100644 index bea4ef33e..000000000 --- a/substrabac/substrapp/views/permissionnode.py +++ /dev/null @@ -1,15 +0,0 @@ -from rest_framework import status -from rest_framework.response import Response -from rest_framework.viewsets import GenericViewSet - -from substrapp.ledger_utils import query_ledger, LedgerError - - -class PermissionNodeViewSet(GenericViewSet): - def list(self, request, *args, **kwargs): - try: - permission_nodes = query_ledger(fcn='queryPermissionNodes') - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) - - return Response(permission_nodes, status=status.HTTP_200_OK) From 9117bae3f0e1676f86f7747cfcec0ccd70b3ac56 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 11:58:37 +0200 Subject: [PATCH 321/457] Place node view in its own app --- substrabac/node/tests/__init__.py | 0 substrabac/node/tests/views/__init__.py | 0 .../tests/views/tests_views_node.py | 14 +++++++------- substrabac/node/urls.py | 17 +++++++++++++++++ substrabac/node/views/__init__.py | 5 +++++ substrabac/{substrapp => node}/views/node.py | 3 ++- substrabac/substrabac/urls.py | 2 ++ substrabac/substrapp/urls.py | 7 +++++++ substrabac/substrapp/views/__init__.py | 5 ++--- 9 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 substrabac/node/tests/__init__.py create mode 100644 substrabac/node/tests/views/__init__.py rename substrabac/{substrapp => node}/tests/views/tests_views_node.py (79%) create mode 100644 substrabac/node/urls.py create mode 100644 substrabac/node/views/__init__.py rename substrabac/{substrapp => node}/views/node.py (89%) diff --git a/substrabac/node/tests/__init__.py b/substrabac/node/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/node/tests/views/__init__.py b/substrabac/node/tests/views/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/substrapp/tests/views/tests_views_node.py b/substrabac/node/tests/views/tests_views_node.py similarity index 79% rename from substrabac/substrapp/tests/views/tests_views_node.py rename to substrabac/node/tests/views/tests_views_node.py index 4139304ce..6c9dacb38 100644 --- a/substrabac/substrapp/tests/views/tests_views_node.py +++ b/substrabac/node/tests/views/tests_views_node.py @@ -9,7 +9,7 @@ from rest_framework.test import APITestCase -from ..common import AuthenticatedClient +from substrapp.tests.common import AuthenticatedClient MEDIA_ROOT = "/tmp/unittests_views/" @@ -37,8 +37,8 @@ def tearDown(self): self.logger.setLevel(self.previous_level) def test_node_list_empty(self): - url = reverse('substrapp:node-list') - with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: + url = reverse('node:node-list') + with mock.patch('node.views.node.query_ledger') as mquery_ledger: mquery_ledger.return_value = {'node_ids': []} response = self.client.get(url, **self.extra) @@ -46,8 +46,8 @@ def test_node_list_empty(self): self.assertEqual(r, []) def test_node_list_success(self): - url = reverse('substrapp:node-list') - with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: + url = reverse('node:node-list') + with mock.patch('node.views.node.query_ledger') as mquery_ledger: mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} response = self.client.get(url, **self.extra) @@ -55,8 +55,8 @@ def test_node_list_success(self): self.assertEqual(r, [{'node_id': 'foo'}, {'node_id': 'bar'}]) def test_current_node(self): - url = reverse('substrapp:node-current') - with mock.patch('substrapp.views.node.query_ledger') as mquery_ledger: + url = reverse('node:node-current') + with mock.patch('node.views.node.query_ledger') as mquery_ledger: mquery_ledger.return_value = 'foo' response = self.client.get(url, **self.extra) diff --git a/substrabac/node/urls.py b/substrabac/node/urls.py new file mode 100644 index 000000000..45c060f7a --- /dev/null +++ b/substrabac/node/urls.py @@ -0,0 +1,17 @@ +""" +node URL +""" + +from django.conf.urls import url, include +from rest_framework.routers import DefaultRouter + +from node.views import NodeViewSet + +# Create a router and register our viewsets with it. + +router = DefaultRouter() +router.register(r'node', NodeViewSet, base_name='node') + +urlpatterns = [ + url(r'^', include(router.urls)), +] diff --git a/substrabac/node/views/__init__.py b/substrabac/node/views/__init__.py new file mode 100644 index 000000000..35ac42ad6 --- /dev/null +++ b/substrabac/node/views/__init__.py @@ -0,0 +1,5 @@ +# encoding: utf-8 + +from .node import NodeViewSet + +__all__ = ['NodeViewSet'] diff --git a/substrabac/substrapp/views/node.py b/substrabac/node/views/node.py similarity index 89% rename from substrabac/substrapp/views/node.py rename to substrabac/node/views/node.py index 3a0e7c8fa..cb61f3d95 100644 --- a/substrabac/substrapp/views/node.py +++ b/substrabac/node/views/node.py @@ -6,7 +6,8 @@ from substrapp.utils import get_owner -class NodeViewSet(mixins.ListModelMixin, GenericViewSet): +class NodeViewSet(mixins.ListModelMixin, + GenericViewSet): def list(self, request, *args, **kwargs): try: nodes = query_ledger(fcn='queryNodes') diff --git a/substrabac/substrabac/urls.py b/substrabac/substrabac/urls.py index 1395fbc0d..d72a8cc3a 100644 --- a/substrabac/substrabac/urls.py +++ b/substrabac/substrabac/urls.py @@ -21,6 +21,7 @@ from substrabac.views import schema_view from substrapp.urls import router +from node.urls import router as nodeRouter urlpatterns = [ @@ -28,6 +29,7 @@ url(r'^admin/', admin.site.urls), url(r'^doc/', schema_view), url(r'^', include((router.urls, 'substrapp'))), + url(r'^', include((nodeRouter.urls, 'node'))), ])), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index ba17c95d7..c52117475 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -7,12 +7,16 @@ from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ +<<<<<<< HEAD ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet, \ <<<<<<< HEAD ModelPermissionViewSet, NodeViewSet, PermissionNodeViewSet ======= NodeViewSet >>>>>>> add current node view +======= + ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet +>>>>>>> Place node view in its own app # Create a router and register our viewsets with it. @@ -30,11 +34,14 @@ router.register(r'testtuple', TestTupleViewSet, base_name='testtuple') router.register(r'task', TaskViewSet, base_name='task') router.register(r'compute_plan', ComputePlanViewSet, base_name='compute_plan') +<<<<<<< HEAD router.register(r'node', NodeViewSet, base_name='node') <<<<<<< HEAD router.register(r'permission_node', PermissionNodeViewSet, base_name='permission_node') ======= >>>>>>> add current node view +======= +>>>>>>> Place node view in its own app urlpatterns = [ url(r'^', include(router.urls)), diff --git a/substrabac/substrapp/views/__init__.py b/substrabac/substrapp/views/__init__.py index 989d5a8a8..eb377cd2d 100644 --- a/substrabac/substrapp/views/__init__.py +++ b/substrabac/substrapp/views/__init__.py @@ -9,9 +9,8 @@ from .testtuple import TestTupleViewSet from .task import TaskViewSet from .computeplan import ComputePlanViewSet -from .node import NodeViewSet __all__ = ['DataSampleViewSet', 'DataManagerViewSet', 'DataManagerPermissionViewSet', 'ObjectiveViewSet', 'ObjectivePermissionViewSet', 'ModelViewSet', 'ModelPermissionViewSet', 'AlgoViewSet', - 'AlgoPermissionViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet', - 'NodeViewSet'] + 'AlgoPermissionViewSet', 'TrainTupleViewSet', 'TestTupleViewSet', 'TaskViewSet', 'ComputePlanViewSet' + ] From 7633e01d45bd9caa2b182908c2f1519ea58c73a6 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 12:14:29 +0200 Subject: [PATCH 322/457] rebase --- .../node/tests/views/tests_views_node.py | 37 ++++++------------- substrabac/substrapp/urls.py | 19 +--------- 2 files changed, 13 insertions(+), 43 deletions(-) diff --git a/substrabac/node/tests/views/tests_views_node.py b/substrabac/node/tests/views/tests_views_node.py index 6c9dacb38..1b1f0fa82 100644 --- a/substrabac/node/tests/views/tests_views_node.py +++ b/substrabac/node/tests/views/tests_views_node.py @@ -32,33 +32,18 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - shutil.rmtree(MEDIA_ROOT, ignore_errors=True) - - self.logger.setLevel(self.previous_level) - - def test_node_list_empty(self): - url = reverse('node:node-list') - with mock.patch('node.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'node_ids': []} - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, []) + self.logger.setLevel(self.previous_level) def test_node_list_success(self): url = reverse('node:node-list') with mock.patch('node.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = {'node_ids': ['foo', 'bar']} - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, [{'node_id': 'foo'}, {'node_id': 'bar'}]) - - def test_current_node(self): - url = reverse('node:node-current') - with mock.patch('node.views.node.query_ledger') as mquery_ledger: - mquery_ledger.return_value = 'foo' - - response = self.client.get(url, **self.extra) - r = response.json() - self.assertEqual(r, {'node_id': 'foo'}) + mquery_ledger.return_value = [{'id': 'foo'}, {'id': 'bar'}] + with mock.patch('node.views.node.get_owner') as mget_owner: + mget_owner.return_value = 'foo' + + response = self.client.get(url, **self.extra) + r = response.json() + self.assertEqual(r, [ + {'id': 'foo', 'isCurrent': True}, + {'id': 'bar', 'isCurrent': False} + ]) diff --git a/substrabac/substrapp/urls.py b/substrabac/substrapp/urls.py index c52117475..96436fa2a 100644 --- a/substrabac/substrapp/urls.py +++ b/substrabac/substrapp/urls.py @@ -7,16 +7,9 @@ from substrapp.views import ObjectiveViewSet, DataSampleViewSet, DataManagerViewSet, \ AlgoViewSet, TrainTupleViewSet, TestTupleViewSet, ModelViewSet, TaskViewSet, \ -<<<<<<< HEAD ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet, \ -<<<<<<< HEAD - ModelPermissionViewSet, NodeViewSet, PermissionNodeViewSet -======= - NodeViewSet ->>>>>>> add current node view -======= - ComputePlanViewSet, ObjectivePermissionViewSet, AlgoPermissionViewSet, DataManagerPermissionViewSet ->>>>>>> Place node view in its own app + ModelPermissionViewSet + # Create a router and register our viewsets with it. @@ -34,14 +27,6 @@ router.register(r'testtuple', TestTupleViewSet, base_name='testtuple') router.register(r'task', TaskViewSet, base_name='task') router.register(r'compute_plan', ComputePlanViewSet, base_name='compute_plan') -<<<<<<< HEAD -router.register(r'node', NodeViewSet, base_name='node') -<<<<<<< HEAD -router.register(r'permission_node', PermissionNodeViewSet, base_name='permission_node') -======= ->>>>>>> add current node view -======= ->>>>>>> Place node view in its own app urlpatterns = [ url(r'^', include(router.urls)), From e3e7a1acfc96010ae3a5d8947c7073b346d5e227 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 14:28:28 +0200 Subject: [PATCH 323/457] flake8 --- substrabac/node/tests/views/tests_views_node.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substrabac/node/tests/views/tests_views_node.py b/substrabac/node/tests/views/tests_views_node.py index 1b1f0fa82..aeb3d111c 100644 --- a/substrabac/node/tests/views/tests_views_node.py +++ b/substrabac/node/tests/views/tests_views_node.py @@ -1,6 +1,5 @@ import os import logging -import shutil import mock @@ -32,7 +31,7 @@ def setUp(self): self.logger.setLevel(logging.ERROR) def tearDown(self): - self.logger.setLevel(self.previous_level) + self.logger.setLevel(self.previous_level) def test_node_list_success(self): url = reverse('node:node-list') From 641df54960aff465abbf78c2c70080996277a6b6 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 18:00:44 +0200 Subject: [PATCH 324/457] add missing queryset --- substrabac/node/views/node.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substrabac/node/views/node.py b/substrabac/node/views/node.py index cb61f3d95..9f59da2f6 100644 --- a/substrabac/node/views/node.py +++ b/substrabac/node/views/node.py @@ -2,15 +2,19 @@ from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet +from node.models import IncomingNode from substrapp.ledger_utils import query_ledger, LedgerError from substrapp.utils import get_owner class NodeViewSet(mixins.ListModelMixin, GenericViewSet): + queryset = IncomingNode.objects.all() + ledger_query_call = 'queryNodes' + def list(self, request, *args, **kwargs): try: - nodes = query_ledger(fcn='queryNodes') + nodes = query_ledger(fcn=self.ledger_query_call) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) From 7bea1a47df102bf61456cbc8e60dbc311294138d Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 30 Sep 2019 10:46:10 +0200 Subject: [PATCH 325/457] Use dumb get_queryset --- substrabac/node/views/node.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/substrabac/node/views/node.py b/substrabac/node/views/node.py index 9f59da2f6..dc53a629b 100644 --- a/substrabac/node/views/node.py +++ b/substrabac/node/views/node.py @@ -9,9 +9,11 @@ class NodeViewSet(mixins.ListModelMixin, GenericViewSet): - queryset = IncomingNode.objects.all() ledger_query_call = 'queryNodes' + def get_queryset(self): + return [] + def list(self, request, *args, **kwargs): try: nodes = query_ledger(fcn=self.ledger_query_call) From d9d9b5068a9f175794c6c67b612a5047d2df8e81 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 30 Sep 2019 10:58:22 +0200 Subject: [PATCH 326/457] Remove useless import --- substrabac/node/views/node.py | 1 - 1 file changed, 1 deletion(-) diff --git a/substrabac/node/views/node.py b/substrabac/node/views/node.py index dc53a629b..efd1275ca 100644 --- a/substrabac/node/views/node.py +++ b/substrabac/node/views/node.py @@ -2,7 +2,6 @@ from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet -from node.models import IncomingNode from substrapp.ledger_utils import query_ledger, LedgerError from substrapp.utils import get_owner From 335e3d4416cddce6b26c81b8bbabfaa39f825408 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 30 Sep 2019 14:03:24 +0200 Subject: [PATCH 327/457] Details should not be under permissionsMixin --- substrabac/substrapp/views/model.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/substrabac/substrapp/views/model.py b/substrabac/substrapp/views/model.py index ca2428e5c..171a31e99 100644 --- a/substrabac/substrapp/views/model.py +++ b/substrabac/substrapp/views/model.py @@ -107,6 +107,18 @@ def list(self, request, *args, **kwargs): return Response(models_list, status=status.HTTP_200_OK) + @action(detail=True) + def details(self, request, *args, **kwargs): + lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field + pk = self.kwargs[lookup_url_kwarg] + + try: + data = get_object_from_ledger(pk, self.ledger_query_call) + except LedgerError as e: + return Response({'message': str(e.msg)}, status=e.status) + + return Response(data, status=status.HTTP_200_OK) + class ModelPermissionViewSet(PermissionMixin, GenericViewSet): @@ -125,15 +137,3 @@ def file(self, request, *args, **kwargs): model_object = self.get_object() data = getattr(model_object, 'file') return CustomFileResponse(open(data.path, 'rb'), as_attachment=True, filename=os.path.basename(data.path)) - - @action(detail=True) - def details(self, request, *args, **kwargs): - lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field - pk = self.kwargs[lookup_url_kwarg] - - try: - data = get_object_from_ledger(pk, self.ledger_query_call) - except LedgerError as e: - return Response({'message': str(e.msg)}, status=e.status) - - return Response(data, status=status.HTTP_200_OK) From 498a3d2d6cf3aeb1a0adef744b634de56fbc16da Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 30 Sep 2019 16:31:14 +0200 Subject: [PATCH 328/457] Improve substrabac startup for k8s deployment strategy --- substrabac/events/apps.py | 13 +++++++++++-- substrabac/substrabac/settings/deps/ledger.py | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/substrabac/events/apps.py b/substrabac/events/apps.py index 1f775866c..97d2acf37 100644 --- a/substrabac/events/apps.py +++ b/substrabac/events/apps.py @@ -3,6 +3,7 @@ import logging import multiprocessing import os +import time import contextlib from django.apps import AppConfig @@ -134,8 +135,16 @@ def ready(self): # We try to connect a client first, if it fails the backend will not start # It avoid potential issue when we launch the channel event hub in a subprocess - with get_hfc() as (loop, client): - logger.info('Start the event application.') + while True: + try: + with get_hfc() as (loop, client): + logger.info('Start the event application.') + except Exception as e: + logger.exception(e) + time.sleep(5) + logger.info('Retry to connect the event application to the ledger') + else: + break p1 = multiprocessing.Process(target=wait) p1.start() diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index bd32f345e..363bdbc4a 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -69,6 +69,25 @@ def get_hfc_client(): channel = client.new_channel(LEDGER['channel_name']) + # Check chaincode is instantiated in the channel + + responses = loop.run_until_complete( + client.query_instantiated_chaincodes( + requestor=LEDGER['requestor'], + channel_name=LEDGER['channel_name'], + peers=[peer], + decode=True + ) + ) + + chaincodes = [(cc.name, cc.version) + for resp in responses + for cc in resp.chaincodes] + + if not (LEDGER['chaincode_name'], LEDGER['chaincode_version']) in chaincodes: + raise Exception(f'Chaincode : {LEDGER["chaincode_name"], LEDGER["chaincode_version"]}' + f' is not instantiated in the channel : {LEDGER["channel_name"]}') + # Discover orderers and peers from channel discovery results = loop.run_until_complete( channel._discovery( From 9eb49b5031ca104a7a314423a5fdcc43967d6f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Gasser?= Date: Mon, 30 Sep 2019 14:17:27 -0400 Subject: [PATCH 329/457] add .vscode/ to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fab7f44d5..7f89fbe3d 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,4 @@ benin_malin # file for testing data creation with django command data.json +.vscode/ From 934c0e751f6a7ccae6ba798ce8e0c1cd70cbbe24 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 1 Oct 2019 16:17:07 +0200 Subject: [PATCH 330/457] Fix for version bumping --- substrabac/substrabac/settings/deps/ledger.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substrabac/substrabac/settings/deps/ledger.py index 363bdbc4a..dfe8f2b74 100644 --- a/substrabac/substrabac/settings/deps/ledger.py +++ b/substrabac/substrabac/settings/deps/ledger.py @@ -80,12 +80,12 @@ def get_hfc_client(): ) ) - chaincodes = [(cc.name, cc.version) + chaincodes = [cc.name for resp in responses for cc in resp.chaincodes] - if not (LEDGER['chaincode_name'], LEDGER['chaincode_version']) in chaincodes: - raise Exception(f'Chaincode : {LEDGER["chaincode_name"], LEDGER["chaincode_version"]}' + if not LEDGER['chaincode_name'] in chaincodes: + raise Exception(f'Chaincode : {LEDGER["chaincode_name"]}' f' is not instantiated in the channel : {LEDGER["channel_name"]}') # Discover orderers and peers from channel discovery From a757bd5f3d118eac4da9b19c287a4364fc126fb6 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Wed, 2 Oct 2019 09:06:29 +0200 Subject: [PATCH 331/457] Fix downloads asset issue --- substrabac/node/fixtures/nodes-chunantes.yaml | 16 ++++++++++++---- substrabac/node/fixtures/nodes-clb.yaml | 16 ++++++++++++---- substrabac/node/fixtures/nodes-owkin.yaml | 16 ++++++++++++---- substrabac/substrapp/tasks/utils.py | 17 +++++------------ substrabac/substrapp/tests/tests_tasks.py | 5 +++++ 5 files changed, 46 insertions(+), 24 deletions(-) diff --git a/substrabac/node/fixtures/nodes-chunantes.yaml b/substrabac/node/fixtures/nodes-chunantes.yaml index 97626a47f..cbc6a9ff4 100644 --- a/substrabac/node/fixtures/nodes-chunantes.yaml +++ b/substrabac/node/fixtures/nodes-chunantes.yaml @@ -1,16 +1,24 @@ - fields: - secret: 22a5fa0c3e8d681fba881f745baad652fc05a04abedd02a202fce47243482d25a752277159689e3b944ee61c4938c3919878aad79dad28a2cedbd949a55d5792 + secret: 5136ebe4f3ef6cc7fa1dd87d8eceb761e4a0a9ba0724f2a71455a926c2953ba37124b1636c6591cf92aa416672431d991141139d98f337d45767cfc908275488 + model: node.outgoingnode + pk: chu-nantesMSP +- fields: + secret: 7ba4b3e3cb54d977978fd577ac5a97349d0b4b88a5d16fb9f2e9d9c0183d28905878e3233b55da2807e33b59eb7c8032748b2c621f1ef9151cdc689af232c7dc model: node.outgoingnode pk: owkinMSP - fields: - secret: 7f37ca057ce8631ea5cce999697026701f47ffbc9c43fb88f7bf107856615fbeb1dbca6b7a5ae4c4415b0bfd141fa267661eb270a1e79e4a77502cf125ade021 + secret: 6978256d3ed5e458ce74c33e1362d5acb43160a20ca8f7b0dbf19324816d9de3a3bd798382244fd5125d82d030982b4adc9a189987c5bd165c5143f68827683d model: node.outgoingnode pk: clbMSP - fields: - secret: 2df765d2aecc51c844dda3017d7b21ff79ffaf68ea11f3273639b462c70e0a5820e96ff15aa2511a539f33ac5cfd5954b7a5087ae4007d2e9837749de77d23dd + secret: 5136ebe4f3ef6cc7fa1dd87d8eceb761e4a0a9ba0724f2a71455a926c2953ba37124b1636c6591cf92aa416672431d991141139d98f337d45767cfc908275488 + model: node.incomingnode + pk: chu-nantesMSP +- fields: + secret: 8af85ad336b9be224449c6e8d194898fbc23f7cd4f77b742ee03af4c3fb1f5999494504e8edde5e74ee8740ce76c542402f75b68a9d49f32b83d9e3910556a46 model: node.incomingnode pk: owkinMSP - fields: - secret: e804ffc806ed55ef546b0a2395b9a2de53ebedf533e84ef68f7a311b9f480213b98d88c22df1a2f0cb2adcd0436ad0dbf86846d936ebb7dd8156e56c06f8116c + secret: ef34f894f4c6d709d81af8e2b57886e92381f4019c2df77b49a54834dc5c53be865d773ed0106ae8bccc039d2b1514e9c0445ba4d3872db1958a2e0d8630329b model: node.incomingnode pk: clbMSP diff --git a/substrabac/node/fixtures/nodes-clb.yaml b/substrabac/node/fixtures/nodes-clb.yaml index 60b99d274..0baa5b3c8 100644 --- a/substrabac/node/fixtures/nodes-clb.yaml +++ b/substrabac/node/fixtures/nodes-clb.yaml @@ -1,16 +1,24 @@ - fields: - secret: e804ffc806ed55ef546b0a2395b9a2de53ebedf533e84ef68f7a311b9f480213b98d88c22df1a2f0cb2adcd0436ad0dbf86846d936ebb7dd8156e56c06f8116c + secret: ef34f894f4c6d709d81af8e2b57886e92381f4019c2df77b49a54834dc5c53be865d773ed0106ae8bccc039d2b1514e9c0445ba4d3872db1958a2e0d8630329b model: node.outgoingnode pk: chu-nantesMSP - fields: - secret: fb3cd57a6e7c688a61021388b1ef7b321640e600b0fd187d6faf4ebbd5ac59d9bc8e286f6177e206576435ab1a7fb7a470dfedb2e6152958980e6e17eb783031 + secret: 640a45ade3a35b767c890b2bff0d5b5b2ce41bb86f12c2826e4a325aca30e9cc11090dadc49874d9bd60faf6dffe4a994e2bb0c0a8ff051165f6ecf52c6797f7 model: node.outgoingnode pk: owkinMSP - fields: - secret: 7f37ca057ce8631ea5cce999697026701f47ffbc9c43fb88f7bf107856615fbeb1dbca6b7a5ae4c4415b0bfd141fa267661eb270a1e79e4a77502cf125ade021 + secret: 43b6422d9332e476ebabe1586bb98f71ffd00dcbfa6cb23ce7faaf13f5c8c5312f44faea409d09b29d1c5cdf066b5048ccf302de20a955c78774eb2b88b6fde5 + model: node.outgoingnode + pk: clbMSP +- fields: + secret: 6978256d3ed5e458ce74c33e1362d5acb43160a20ca8f7b0dbf19324816d9de3a3bd798382244fd5125d82d030982b4adc9a189987c5bd165c5143f68827683d model: node.incomingnode pk: chu-nantesMSP - fields: - secret: 3e3e02045cf47fc37c6e0c7d5440fa17889c106a865254a0eeae3ccda60a8f0b90a2de218aa39ed074d71b0a1674cd5bdd0bf74ffc7fc385d8b9c9b63a7675c0 + secret: 7a4c73e3fc43ec6a64768d31e8493c2aac9c214117457a7d1b08dbe54d8ab08e3b32dda657c77b2d2ca10cc5014bc4d4233bbe732c8e7c1cc37491cd6e17efbc model: node.incomingnode pk: owkinMSP +- fields: + secret: 43b6422d9332e476ebabe1586bb98f71ffd00dcbfa6cb23ce7faaf13f5c8c5312f44faea409d09b29d1c5cdf066b5048ccf302de20a955c78774eb2b88b6fde5 + model: node.incomingnode + pk: clbMSP diff --git a/substrabac/node/fixtures/nodes-owkin.yaml b/substrabac/node/fixtures/nodes-owkin.yaml index 5578f9790..9c4324d53 100644 --- a/substrabac/node/fixtures/nodes-owkin.yaml +++ b/substrabac/node/fixtures/nodes-owkin.yaml @@ -1,16 +1,24 @@ - fields: - secret: 2df765d2aecc51c844dda3017d7b21ff79ffaf68ea11f3273639b462c70e0a5820e96ff15aa2511a539f33ac5cfd5954b7a5087ae4007d2e9837749de77d23dd + secret: 8af85ad336b9be224449c6e8d194898fbc23f7cd4f77b742ee03af4c3fb1f5999494504e8edde5e74ee8740ce76c542402f75b68a9d49f32b83d9e3910556a46 model: node.outgoingnode pk: chu-nantesMSP - fields: - secret: 3e3e02045cf47fc37c6e0c7d5440fa17889c106a865254a0eeae3ccda60a8f0b90a2de218aa39ed074d71b0a1674cd5bdd0bf74ffc7fc385d8b9c9b63a7675c0 + secret: c420b2dd0552241b21932a81001f9ef6682c22b8d427649f3e15e8ace817c06ed069bac647a3f62a6d81c6ace4c469d549d7f76c9f6adc8c2646d5af7ca4dfa3 + model: node.outgoingnode + pk: owkinMSP +- fields: + secret: 7a4c73e3fc43ec6a64768d31e8493c2aac9c214117457a7d1b08dbe54d8ab08e3b32dda657c77b2d2ca10cc5014bc4d4233bbe732c8e7c1cc37491cd6e17efbc model: node.outgoingnode pk: clbMSP - fields: - secret: 22a5fa0c3e8d681fba881f745baad652fc05a04abedd02a202fce47243482d25a752277159689e3b944ee61c4938c3919878aad79dad28a2cedbd949a55d5792 + secret: 7ba4b3e3cb54d977978fd577ac5a97349d0b4b88a5d16fb9f2e9d9c0183d28905878e3233b55da2807e33b59eb7c8032748b2c621f1ef9151cdc689af232c7dc model: node.incomingnode pk: chu-nantesMSP - fields: - secret: fb3cd57a6e7c688a61021388b1ef7b321640e600b0fd187d6faf4ebbd5ac59d9bc8e286f6177e206576435ab1a7fb7a470dfedb2e6152958980e6e17eb783031 + secret: c420b2dd0552241b21932a81001f9ef6682c22b8d427649f3e15e8ace817c06ed069bac647a3f62a6d81c6ace4c469d549d7f76c9f6adc8c2646d5af7ca4dfa3 + model: node.incomingnode + pk: owkinMSP +- fields: + secret: 640a45ade3a35b767c890b2bff0d5b5b2ce41bb86f12c2826e4a325aca30e9cc11090dadc49874d9bd60faf6dffe4a994e2bb0c0a8ff051165f6ecf52c6797f7 model: node.incomingnode pk: clbMSP diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index fd9977881..328a82f8a 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -21,19 +21,12 @@ def authenticate_worker(node_id): owner = get_owner() - # This handle worker node authentication - # WARN: This should use a different authentication - # Backend (WorkerBackend for example) to be able - # to differentiate regular node users from workers - if node_id == owner: - auth = HTTPBasicAuth(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) - else: - try: - outgoing = OutgoingNode.objects.get(node_id=node_id) - except OutgoingNode.DoesNotExist: - raise NodeError(f'Unauthorized to call node_id: {node_id}') + try: + outgoing = OutgoingNode.objects.get(node_id=node_id) + except OutgoingNode.DoesNotExist: + raise NodeError(f'Unauthorized to call node_id: {node_id}') - auth = HTTPBasicAuth(owner, outgoing.secret) + auth = HTTPBasicAuth(owner, outgoing.secret) return auth diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 7d22ce110..80ae1a16d 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -54,6 +54,11 @@ def setUp(self): def setUpTestData(cls): cls.outgoing_node = OutgoingNode.objects.create(node_id="external_node_id", secret="s3cr37") + cls.outgoing_node_traintuple = OutgoingNode.objects.create(node_id=assets.traintuple[1]['creator'], + secret="s3cr37") + if assets.traintuple[1]['creator'] != assets.algo[0]['owner']: + cls.outgoing_node_algo = OutgoingNode.objects.create(node_id=assets.algo[0]['owner'], secret="s3cr37") + def tearDown(self): shutil.rmtree(MEDIA_ROOT, ignore_errors=True) From 3419fe252f4601d06bdc38f8cc89428a8224dad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Tue, 1 Oct 2019 16:10:02 +0200 Subject: [PATCH 332/457] wip proxy for download objective description --- .../tests/views/tests_views_objective.py | 97 ++++++++++++++++++- substrabac/substrapp/views/objective.py | 7 +- substrabac/substrapp/views/utils.py | 27 ++++-- 3 files changed, 121 insertions(+), 10 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 7903ad79b..71c963406 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -2,8 +2,10 @@ import shutil import logging import zipfile +import copy import mock +import requests from django.urls import reverse from django.test import override_settings @@ -11,7 +13,7 @@ from rest_framework import status from rest_framework.test import APITestCase - +from substrapp.models import Objective from substrapp.serializers import LedgerObjectiveSerializer from substrapp.ledger_utils import LedgerError @@ -326,3 +328,96 @@ def test_objective_leaderboard_sort(self): response = self.client.get(url, data={'sort': 'foo'}, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + + def test_objective_url_rewrite_list(self): + # todo + # todo: also handle metrics rewrite + pass + + def test_objective_url_rewrite_retrieve(self): + url = reverse('substrapp:objective-detail', args=[objective[0]['key']]) + with mock.patch('substrapp.views.objective.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.objective.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_objective = copy.deepcopy(objective[0]) + ledger_objective['description']['storageAddress'] = \ + ledger_objective['description']['storageAddress'].replace('http://testserver', + 'http://remotetestserver') + mquery_ledger.return_value = ledger_objective + + # actual test + res = self.client.get(url, **self.extra) + self.assertEqual(res.data['description']['storageAddress'], + objective[0]['description']['storageAddress']) + + def test_objective_url_rewrite_download_local(self): + description_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + '../../../../fixtures/owkin/objectives/objective0/description.md') + + with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.utils.get_owner') as mget_owner, \ + mock.patch('substrapp.views.objective.ObjectivePermissionViewSet.get_object') \ + as mget_object: + + # mock content + mquery_ledger.return_value = objective[0] + mget_owner.return_value = objective[0]['owner'] + with open(description_path, 'rb') as f: + description_content = f.read() + + class MockDescription: + path = description_path + mock_objective = Objective(pkhash="toto", description=MockDescription) + mget_object.return_value = mock_objective + + # test + url = objective[0]['description']['storageAddress'] + res = self.client.get(url, **self.extra) + res_content = b''.join(list(res.streaming_content)) + self.assertEqual(res_content, description_content) + + def test_objective_url_rewrite_download_remote_allowed(self): + description_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + '../../../../fixtures/owkin/objectives/objective0/description.md') + with open(description_path, 'rb') as f: + description_content = f.read() + + with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.utils.get_owner') as mget_owner, \ + mock.patch('substrapp.views.utils.requests.get') as mrequests_get: + # mock content + mquery_ledger.return_value = objective[0] + mget_owner.return_value = 'not-OwkinMSP' + + requests_response = requests.Response() + requests_response.raw = open(description_path, 'rb') + requests_response.status_code = status.HTTP_200_OK + mrequests_get.return_value = requests_response + + # test + url = objective[0]['description']['storageAddress'] + res = self.client.get(url, **self.extra) + res_content = b''.join(list(res.streaming_content)) + self.assertEqual(res_content, description_content) + + def test_objective_url_rewrite_download_remote_denied(self): + with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.utils.get_owner') as mget_owner, \ + mock.patch('substrapp.views.utils.requests.get') as mrequests_get: + # mock content + mquery_ledger.return_value = objective[0] + mget_owner.return_value = 'not-OwkinMSP' + + requests_response = requests.Response() + requests_response.status_code = status.HTTP_401_UNAUTHORIZED + requests_response._content = b'{"message": "nope"}' + mrequests_get.return_value = requests_response + + # test + url = objective[0]['description']['storageAddress'] + res = self.client.get(url, **self.extra) + self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 400221d99..8b4c82646 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -186,7 +186,7 @@ def create_or_update_objective(self, objective, pk): return instance - def _retrieve(self, pk): + def _retrieve(self, request, pk): validate_pk(pk) # get instance from remote node data = get_object_from_ledger(pk, self.ledger_query_call) @@ -206,6 +206,9 @@ def _retrieve(self, pk): serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) data.update(serializer.data) + data['description']['storageAddress'] = request.build_absolute_uri( + reverse('substrapp:objective-description', args=[pk])) + return data def retrieve(self, request, *args, **kwargs): @@ -213,7 +216,7 @@ def retrieve(self, request, *args, **kwargs): pk = self.kwargs[lookup_url_kwarg] try: - data = self._retrieve(pk) + data = self._retrieve(request, pk) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) except Exception as e: diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 623aac3c8..2253776d7 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -4,6 +4,7 @@ import binascii from importlib import import_module +import requests from django.http import FileResponse from rest_framework.authentication import SessionAuthentication, BasicAuthentication, get_authorization_header from rest_framework.permissions import IsAuthenticated @@ -125,13 +126,25 @@ def download_file(self, request, field): return Response({'message': 'Unauthorized'}, status=status.HTTP_401_UNAUTHORIZED) - obj = self.get_object() - data = getattr(obj, field) - response = CustomFileResponse( - open(data.path, 'rb'), - as_attachment=True, - filename=os.path.basename(data.path) - ) + if get_owner() == asset['owner']: + obj = self.get_object() + data = getattr(obj, field) + response = CustomFileResponse( + open(data.path, 'rb'), + as_attachment=True, + filename=os.path.basename(data.path) + ) + else: + r = requests.get(asset[field]['storageAddress'], stream=True) + if not r.ok: + return Response({'message': str(r.text)}, status=r.status_code) + response = CustomFileResponse( + streaming_content=r.raw, + as_attachment=True, + filename='dummydummydummy.md', # todo: proper filename + status=r.status_code + ) + return response From d13a6b79eaedd754872ecfb97f87253438e8ca63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Tue, 1 Oct 2019 16:38:25 +0200 Subject: [PATCH 333/457] add check on filename --- substrabac/substrapp/tests/views/tests_views_objective.py | 2 ++ substrabac/substrapp/views/utils.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 71c963406..c8ae5196d 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -378,6 +378,7 @@ class MockDescription: res = self.client.get(url, **self.extra) res_content = b''.join(list(res.streaming_content)) self.assertEqual(res_content, description_content) + self.assertEqual(res['Content-Disposition'], 'attachment; filename="description.md"') def test_objective_url_rewrite_download_remote_allowed(self): description_path = os.path.join( @@ -403,6 +404,7 @@ def test_objective_url_rewrite_download_remote_allowed(self): res = self.client.get(url, **self.extra) res_content = b''.join(list(res.streaming_content)) self.assertEqual(res_content, description_content) + self.assertEqual(res['Content-Disposition'], 'attachment; filename="description.md"') def test_objective_url_rewrite_download_remote_denied(self): with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 2253776d7..caeac05f2 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -141,7 +141,6 @@ def download_file(self, request, field): response = CustomFileResponse( streaming_content=r.raw, as_attachment=True, - filename='dummydummydummy.md', # todo: proper filename status=r.status_code ) From 3d7c9486d05b2a463ea1a570f53d350fbe3bf8ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Tue, 1 Oct 2019 17:04:52 +0200 Subject: [PATCH 334/457] rewrite storageAddress in objective list --- .../tests/views/tests_views_objective.py | 31 ++++++++++++++++--- substrabac/substrapp/views/objective.py | 12 +++++-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index c8ae5196d..3cef10996 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -74,15 +74,20 @@ def tearDown(self): def test_objective_list_empty(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [[], ['ISIC']] + mquery_ledger.return_value = [] response = self.client.get(url, **self.extra) r = response.json() self.assertEqual(r, [[]]) + def test_objective_list_success(self): + url = reverse('substrapp:objective-list') + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: + mquery_ledger.return_value = objective + response = self.client.get(url, **self.extra) r = response.json() - self.assertEqual(r, [['ISIC']]) + self.assertEqual(r, [objective]) def test_objective_list_filter_fail(self): url = reverse('substrapp:objective-list') @@ -330,9 +335,25 @@ def test_objective_leaderboard_sort(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) def test_objective_url_rewrite_list(self): - # todo - # todo: also handle metrics rewrite - pass + url = reverse('substrapp:objective-list') + with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.objective.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_objectives = copy.deepcopy(objective) + for ledger_objective in ledger_objectives: + ledger_objective['description']['storageAddress'] = \ + ledger_objective['description']['storageAddress'] \ + .replace('http://testserver', 'http://remotetestserver') + mquery_ledger.return_value = ledger_objectives + + # actual test + res = self.client.get(url, **self.extra) + self.assertEqual(res.data[0][0]['description']['storageAddress'], + objective[0]['description']['storageAddress']) + self.assertEqual(res.data[0][1]['description']['storageAddress'], + objective[1]['description']['storageAddress']) def test_objective_url_rewrite_retrieve(self): url = reverse('substrapp:objective-detail', args=[objective[0]['key']]) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 8b4c82646..54da31f11 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -30,6 +30,11 @@ from substrapp.views.filters_utils import filter_list +def rewrite_storage_addresses(request, objective): + objective['description']['storageAddress'] = request.build_absolute_uri( + reverse('substrapp:objective-description', args=[objective['key']])) + + class ObjectiveViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, @@ -206,8 +211,7 @@ def _retrieve(self, request, pk): serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) data.update(serializer.data) - data['description']['storageAddress'] = request.build_absolute_uri( - reverse('substrapp:objective-description', args=[pk])) + rewrite_storage_addresses(request, data) return data @@ -247,6 +251,10 @@ def list(self, request, *args, **kwargs): {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) + for group in objectives_list: + for objective in group: + rewrite_storage_addresses(request, objective) + return Response(objectives_list, status=status.HTTP_200_OK) @action(detail=True) From dbf3696b400381b1f6fb16099fe456c7e7e96442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 2 Oct 2019 10:49:06 +0200 Subject: [PATCH 335/457] refactor call to remote node --- substrabac/substrapp/tasks/utils.py | 4 ++-- substrabac/substrapp/tests/tests_tasks.py | 9 +++++---- .../tests/views/tests_views_objective.py | 13 +++++++++--- substrabac/substrapp/utils.py | 20 ++++++++++++------- substrabac/substrapp/views/objective.py | 6 +++--- substrabac/substrapp/views/utils.py | 13 +++++++----- 6 files changed, 41 insertions(+), 24 deletions(-) diff --git a/substrabac/substrapp/tasks/utils.py b/substrabac/substrapp/tasks/utils.py index 328a82f8a..a8e540cc1 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substrabac/substrapp/tasks/utils.py @@ -8,7 +8,7 @@ from subprocess import check_output from django.conf import settings from requests.auth import HTTPBasicAuth -from substrapp.utils import get_owner, get_remote_file, NodeError +from substrapp.utils import get_owner, get_remote_file_content, NodeError DOCKER_LABEL = 'substra_task' @@ -32,7 +32,7 @@ def authenticate_worker(node_id): def get_asset_content(url, node_id, content_hash, salt=None): - return get_remote_file(url, authenticate_worker(node_id), content_hash, salt=salt) + return get_remote_file_content(url, authenticate_worker(node_id), content_hash, salt=salt) def get_cpu_sets(cpu_count, concurrency): diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index 80ae1a16d..faa4d2eeb 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -12,7 +12,7 @@ from substrapp.models import DataSample from substrapp.ledger_utils import LedgerStatusError from substrapp.utils import store_datasamples_archive -from substrapp.utils import compute_hash, get_remote_file, get_hash, create_directory +from substrapp.utils import compute_hash, get_remote_file_content, get_hash, create_directory from substrapp.tasks.utils import ResourcesManager, compute_docker from substrapp.tasks.tasks import (build_subtuple_folders, get_algo, get_model, get_models, get_objective, put_opener, put_model, put_models, put_algo, put_metric, put_data_sample, prepare_task, do_task, @@ -75,7 +75,7 @@ def test_create_directory(self): except Exception: self.fail('`remove_subtuple_materials` raised Exception unexpectedly!') - def test_get_remote_file(self): + def test_get_remote_file_content(self): content = str(self.script.read()) pkhash = compute_hash(content) remote_file = {'storageAddress': 'localhost', @@ -88,7 +88,7 @@ def test_get_remote_file(self): get_owner.return_value = 'external_node_id' request_get.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) - content_remote = get_remote_file(remote_file, 'external_node_id', pkhash) + content_remote = get_remote_file_content(remote_file, 'external_node_id', pkhash) self.assertEqual(content_remote, content) with mock.patch('substrapp.utils.get_owner') as get_owner,\ @@ -97,7 +97,8 @@ def test_get_remote_file(self): request_get.return_value = FakeRequest(content=content, status=status.HTTP_200_OK) with self.assertRaises(Exception): - get_remote_file(remote_file, 'external_node_id', 'fake_pkhash') # contents (by pkhash) are different + # contents (by pkhash) are different + get_remote_file_content(remote_file, 'external_node_id', 'fake_pkhash') def test_Ressource_Manager(self): diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 3cef10996..0140deed1 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -9,6 +9,7 @@ from django.urls import reverse from django.test import override_settings +from requests.auth import HTTPBasicAuth from rest_framework import status from rest_framework.test import APITestCase @@ -345,7 +346,7 @@ def test_objective_url_rewrite_list(self): for ledger_objective in ledger_objectives: ledger_objective['description']['storageAddress'] = \ ledger_objective['description']['storageAddress'] \ - .replace('http://testserver', 'http://remotetestserver') + .replace('http://testserver', 'http://remotetestserver') mquery_ledger.return_value = ledger_objectives # actual test @@ -409,10 +410,13 @@ def test_objective_url_rewrite_download_remote_allowed(self): description_content = f.read() with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.utils.authenticate_outgoing_request') \ + as mauthenticate_outgoing_request, \ mock.patch('substrapp.views.utils.get_owner') as mget_owner, \ - mock.patch('substrapp.views.utils.requests.get') as mrequests_get: + mock.patch('substrapp.utils.requests.get') as mrequests_get: # mock content mquery_ledger.return_value = objective[0] + mauthenticate_outgoing_request.return_value = HTTPBasicAuth('foo', 'bar') mget_owner.return_value = 'not-OwkinMSP' requests_response = requests.Response() @@ -429,10 +433,13 @@ def test_objective_url_rewrite_download_remote_allowed(self): def test_objective_url_rewrite_download_remote_denied(self): with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.utils.authenticate_outgoing_request') \ + as mauthenticate_outgoing_request, \ mock.patch('substrapp.views.utils.get_owner') as mget_owner, \ - mock.patch('substrapp.views.utils.requests.get') as mrequests_get: + mock.patch('substrapp.utils.requests.get') as mrequests_get: # mock content mquery_ledger.return_value = objective[0] + mauthenticate_outgoing_request.return_value = HTTPBasicAuth('foo', 'bar') mget_owner.return_value = 'not-OwkinMSP' requests_response = requests.Response() diff --git a/substrabac/substrapp/utils.py b/substrabac/substrapp/utils.py index a374cd454..c144dd7ed 100644 --- a/substrabac/substrapp/utils.py +++ b/substrabac/substrapp/utils.py @@ -156,11 +156,11 @@ class NodeError(Exception): pass -def get_remote_file(url, auth, content_hash, salt=None): - kwargs = { +def get_remote_file(url, auth, **kwargs): + kwargs.update({ 'headers': {'Accept': 'application/json;version=0.0'}, 'auth': auth - } + }) if settings.DEBUG: kwargs['verify'] = False @@ -169,10 +169,16 @@ def get_remote_file(url, auth, content_hash, salt=None): response = requests.get(url, **kwargs) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e: raise NodeError(f'Failed to fetch {url}') from e - else: - if response.status_code != status.HTTP_200_OK: - logging.error(response.text) - raise NodeError(f'Url: {url} returned status code: {response.status_code}') + + return response + + +def get_remote_file_content(url, auth, content_hash, salt=None): + response = get_remote_file(url, auth) + + if response.status_code != status.HTTP_200_OK: + logging.error(response.text) + raise NodeError(f'Url: {url} returned status code: {response.status_code}') computed_hash = compute_hash(response.content, key=salt) if computed_hash != content_hash: diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 54da31f11..e0faa5ee5 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -30,7 +30,7 @@ from substrapp.views.filters_utils import filter_list -def rewrite_storage_addresses(request, objective): +def replace_storage_addresses(request, objective): objective['description']['storageAddress'] = request.build_absolute_uri( reverse('substrapp:objective-description', args=[objective['key']])) @@ -211,7 +211,7 @@ def _retrieve(self, request, pk): serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) data.update(serializer.data) - rewrite_storage_addresses(request, data) + replace_storage_addresses(request, data) return data @@ -253,7 +253,7 @@ def list(self, request, *args, **kwargs): for group in objectives_list: for objective in group: - rewrite_storage_addresses(request, objective) + replace_storage_addresses(request, objective) return Response(objectives_list, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index caeac05f2..27c5b19d1 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -4,14 +4,13 @@ import binascii from importlib import import_module -import requests from django.http import FileResponse from rest_framework.authentication import SessionAuthentication, BasicAuthentication, get_authorization_header from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from substrapp.ledger_utils import get_object_from_ledger, LedgerError -from substrapp.utils import NodeError, get_remote_file, get_owner +from substrapp.utils import NodeError, get_remote_file, get_owner, get_remote_file_content from node.models import OutgoingNode from django.conf import settings @@ -38,7 +37,7 @@ def authenticate_outgoing_request(outgoing_node_id): def get_remote_asset(url, node_id, content_hash, salt=None): auth = authenticate_outgoing_request(node_id) - return get_remote_file(url, auth, content_hash, salt=salt) + return get_remote_file_content(url, auth, content_hash, salt=salt) class CustomFileResponse(FileResponse): @@ -135,9 +134,13 @@ def download_file(self, request, field): filename=os.path.basename(data.path) ) else: - r = requests.get(asset[field]['storageAddress'], stream=True) + node_id = asset['owner'] + auth = authenticate_outgoing_request(node_id) + r = get_remote_file(asset[field]['storageAddress'], auth, stream=True) if not r.ok: - return Response({'message': str(r.text)}, status=r.status_code) + return Response({ + 'message': f'Cannot proxify asset from node {asset["owner"]}: {str(r.text)}' + }, status=r.status_code) response = CustomFileResponse( streaming_content=r.raw, as_attachment=True, From 6bf1c8c51513ec2a398219b13cd4d2c56c3c8d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 2 Oct 2019 15:12:46 +0200 Subject: [PATCH 336/457] rewrite metrics storageAddress + tests --- .../owkin/objectives/objective0/metrics.zip | Bin 0 -> 626 bytes .../tests/views/tests_views_objective.py | 99 ++++++++++++------ substrabac/substrapp/views/objective.py | 3 + 3 files changed, 68 insertions(+), 34 deletions(-) create mode 100644 fixtures/owkin/objectives/objective0/metrics.zip diff --git a/fixtures/owkin/objectives/objective0/metrics.zip b/fixtures/owkin/objectives/objective0/metrics.zip new file mode 100644 index 0000000000000000000000000000000000000000..e309d8e734f77bab6f13919374880238ae7f2a86 GIT binary patch literal 626 zcmWIWW@Zs#U|`^22rFmx=eW`{r3J{F0mNJkG7K*H$=RtzX_+~xp&^_M%*+}dv4-=f z#FkcYGcdAzWn^Fg>n-N~^gYx=_o}zQ-lfxLuIuahYUycuT`@Jm>szT}LmrS~WGv+h;--g?Ic6UDC8+`ILZKL9=HHrBxZCtCp&;2Hg-! z?(tv3_5JR_yqxNgcWDWZ=NZlPSI;@bY8R3E$aG)JZ|5yeJN%6P^=#k0Lsin~?6hYq z?p~d{x87uLWX6MaC!Z`e$-Ak~<{+bKtW+Xv(lPT<$Bj3|-&_0Hx7ci+uXX#g%=0ti z0p5&Ea?H45PXg$F1_odNFf3^Vv5@1E6%v Date: Thu, 3 Oct 2019 09:50:14 +0200 Subject: [PATCH 337/457] permission_mixin instead of parent view --- .../substrapp/tests/views/tests_utils.py | 105 ++++++++++++++++++ .../tests/views/tests_views_objective.py | 102 ----------------- 2 files changed, 105 insertions(+), 102 deletions(-) create mode 100644 substrabac/substrapp/tests/views/tests_utils.py diff --git a/substrabac/substrapp/tests/views/tests_utils.py b/substrabac/substrapp/tests/views/tests_utils.py new file mode 100644 index 000000000..eea75b901 --- /dev/null +++ b/substrabac/substrapp/tests/views/tests_utils.py @@ -0,0 +1,105 @@ +import functools +import os +import tempfile + +import mock +import requests +from requests.auth import HTTPBasicAuth +from rest_framework import status +from rest_framework.test import APITestCase + +from substrapp.views.utils import PermissionMixin + + +class MockRequest: + user = None + + +def with_permission_mixin(remote): + def inner(f): + @functools.wraps(f) + def wrapper(self): + with mock.patch('substrapp.views.utils.get_object_from_ledger', + return_value={'owner': 'owner-foo', + 'file_property': {'storageAddress': 'foo'}}), \ + tempfile.NamedTemporaryFile() as tmp_file, \ + mock.patch('substrapp.views.utils.get_owner', + return_value='not-owner-foo' if remote else 'owner-foo'): + tmp_file_content = b'foo bar' + tmp_file.write(tmp_file_content) + tmp_file.seek(0) + + class TestFieldFile: + path = tmp_file.name + + class TestModel: + file_property = TestFieldFile() + + permission_mixin = PermissionMixin() + permission_mixin.get_object = mock.MagicMock(return_value=TestModel()) + permission_mixin._has_access = mock.MagicMock(return_value=True) + permission_mixin.lookup_url_kwarg = 'foo' + permission_mixin.kwargs = {'foo': 'bar'} + permission_mixin.ledger_query_call = 'foo' + + kwargs = { + 'tmp_file': tmp_file, + 'content': tmp_file_content, + 'filename': os.path.basename(tmp_file.name) + } + + f(self, permission_mixin, **kwargs) + return wrapper + return inner + + +def with_requests_mock(allowed): + def inner(f): + @functools.wraps(f) + def wrapper(*args, **kwargs): + tmp_file = kwargs['tmp_file'] + + requests_response = requests.Response() + if allowed: + requests_response.raw = tmp_file + requests_response.status_code = status.HTTP_200_OK + else: + requests_response._content = b'{"message": "nope"}' + requests_response.status_code = status.HTTP_401_UNAUTHORIZED + + kwargs['requests_response'] = requests_response + + with mock.patch('substrapp.views.utils.authenticate_outgoing_request', + return_value=HTTPBasicAuth('foo', 'bar')), \ + mock.patch('substrapp.utils.requests.get', return_value=requests_response): + f(*args, **kwargs) + return wrapper + return inner + + +class PermissionMixinDownloadFileTests(APITestCase): + @with_permission_mixin(remote=False) + def test_download_file_local(self, permission_mixin, content, filename, **kwargs): + res = permission_mixin.download_file(MockRequest(), 'file_property') + res_content = b''.join(list(res.streaming_content)) + self.assertEqual(res_content, content) + self.assertEqual(res['Content-Disposition'], f'attachment; filename="{filename}"') + self.assertTrue(permission_mixin.get_object.called) + + @with_permission_mixin(remote=True) + @with_requests_mock(allowed=True) + def test_download_file_remote_allowed(self, permission_mixin, content, filename, **kwargs): + res = permission_mixin.download_file(MockRequest(), 'file_property') + res_content = b''.join(list(res.streaming_content)) + self.assertEqual(res_content, content) + self.assertEqual(res['Content-Disposition'], f'attachment; filename="{filename}"') + self.assertFalse(permission_mixin.get_object.called) + + @with_permission_mixin(remote=True) + @with_requests_mock(allowed=False) + def test_download_file_remote_denied(self, permission_mixin, **kwargs): + res = permission_mixin.download_file(MockRequest(), 'file_property') + self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertFalse(permission_mixin.get_object.called) + + diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index c2753dec7..60087ee12 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -379,106 +379,4 @@ def test_objective_url_rewrite_retrieve(self): self.assertEqual(res.data[field]['storageAddress'], objective[0][field]['storageAddress']) - def test_objective_url_rewrite_download_local(self): - objective_path = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - '../../../../fixtures/owkin/objectives/objective0') - description_path = os.path.join(objective_path, 'description.md') - metrics_path = os.path.join(objective_path, 'metrics.zip') - - with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.utils.get_owner') as mget_owner, \ - mock.patch('substrapp.views.objective.ObjectivePermissionViewSet.get_object') \ - as mget_object: - # mock content - mquery_ledger.return_value = objective[0] - mget_owner.return_value = objective[0]['owner'] - with open(description_path, 'rb') as f: - description_content = f.read() - with open(metrics_path, 'rb') as f: - metrics_content = f.read() - - class MockDescription: - path = description_path - - class MockMetrics: - path = metrics_path - - mock_objective = Objective(pkhash="foo", - description=MockDescription, - metrics=MockMetrics) - mget_object.return_value = mock_objective - - # test - conf = (('description', 'description.md', description_content), - ('metrics', 'metrics.zip', metrics_content)) - for field, filename, content in conf: - url = objective[0][field]['storageAddress'] - res = self.client.get(url, **self.extra) - res_content = b''.join(list(res.streaming_content)) - self.assertEqual(res_content, content) - self.assertEqual(res['Content-Disposition'], - f'attachment; filename="{filename}"') - - def test_objective_url_rewrite_download_remote_allowed(self): - objective_path = os.path.join( - os.path.dirname(os.path.realpath(__file__)), - '../../../../fixtures/owkin/objectives/objective0') - description_path = os.path.join(objective_path, 'description.md') - metrics_path = os.path.join(objective_path, 'metrics.zip') - with open(description_path, 'rb') as f: - description_content = f.read() - with open(metrics_path, 'rb') as f: - metrics_content = f.read() - - with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.utils.authenticate_outgoing_request') \ - as mauthenticate_outgoing_request, \ - mock.patch('substrapp.views.utils.get_owner') as mget_owner, \ - mock.patch('substrapp.utils.requests.get') as mrequests_get: - # mock content - mquery_ledger.return_value = objective[0] - mauthenticate_outgoing_request.return_value = HTTPBasicAuth('foo', 'bar') - mget_owner.return_value = 'not-OwkinMSP' - - requests_responses = [] - for filepath in (description_path, metrics_path): - requests_response = requests.Response() - requests_response.raw = open(filepath, 'rb') - requests_response.status_code = status.HTTP_200_OK - requests_responses.append(requests_response) - mrequests_get.side_effect = requests_responses - - # test - conf = (('description', 'description.md', description_content), - ('metrics', 'metrics.zip', metrics_content)) - for field, filename, content in conf: - url = objective[0][field]['storageAddress'] - res = self.client.get(url, **self.extra) - res_content = b''.join(list(res.streaming_content)) - self.assertEqual(res_content, content) - self.assertEqual(res['Content-Disposition'], - f'attachment; filename="{filename}"') - - def test_objective_url_rewrite_download_remote_denied(self): - with mock.patch('substrapp.views.utils.get_object_from_ledger') as mquery_ledger, \ - mock.patch('substrapp.views.utils.authenticate_outgoing_request') \ - as mauthenticate_outgoing_request, \ - mock.patch('substrapp.views.utils.get_owner') as mget_owner, \ - mock.patch('substrapp.utils.requests.get') as mrequests_get: - # mock content - mquery_ledger.return_value = objective[0] - mauthenticate_outgoing_request.return_value = HTTPBasicAuth('foo', 'bar') - mget_owner.return_value = 'not-OwkinMSP' - - requests_response = requests.Response() - requests_response.status_code = status.HTTP_401_UNAUTHORIZED - requests_response._content = b'{"message": "nope"}' - mrequests_get.return_value = requests_response - - # test - for field in ('description', 'metrics'): - url = objective[0][field]['storageAddress'] - res = self.client.get(url, **self.extra) - self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED) From dff8de6cff2bdc173fc2e76e534af481c9c3886a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Thu, 3 Oct 2019 10:21:53 +0200 Subject: [PATCH 338/457] update storageAddresses in algo and datamanager --- .../substrapp/tests/views/tests_utils.py | 4 +- .../substrapp/tests/views/tests_views_algo.py | 54 ++++++++++++++++++- .../tests/views/tests_views_datamanager.py | 54 ++++++++++++++++++- .../tests/views/tests_views_objective.py | 9 +--- substrabac/substrapp/views/algo.py | 19 ++++++- substrabac/substrapp/views/datamanager.py | 19 ++++++- 6 files changed, 141 insertions(+), 18 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_utils.py b/substrabac/substrapp/tests/views/tests_utils.py index eea75b901..3a61ee7de 100644 --- a/substrabac/substrapp/tests/views/tests_utils.py +++ b/substrabac/substrapp/tests/views/tests_utils.py @@ -22,7 +22,7 @@ def wrapper(self): with mock.patch('substrapp.views.utils.get_object_from_ledger', return_value={'owner': 'owner-foo', 'file_property': {'storageAddress': 'foo'}}), \ - tempfile.NamedTemporaryFile() as tmp_file, \ + tempfile.NamedTemporaryFile() as tmp_file, \ mock.patch('substrapp.views.utils.get_owner', return_value='not-owner-foo' if remote else 'owner-foo'): tmp_file_content = b'foo bar' @@ -101,5 +101,3 @@ def test_download_file_remote_denied(self, permission_mixin, **kwargs): res = permission_mixin.download_file(MockRequest(), 'file_property') self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED) self.assertFalse(permission_mixin.get_object.called) - - diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index e12d1f799..9955d76dc 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -1,3 +1,4 @@ +import copy import os import shutil import logging @@ -52,15 +53,20 @@ def tearDown(self): def test_algo_list_empty(self): url = reverse('substrapp:algo-list') with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [[], ['ISIC']] + mquery_ledger.return_value = [] response = self.client.get(url, **self.extra) r = response.json() self.assertEqual(r, [[]]) + def test_algo_list_success(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: + mquery_ledger.return_value = algo + response = self.client.get(url, **self.extra) r = response.json() - self.assertEqual(r, [['ISIC']]) + self.assertEqual(r, [algo]) def test_algo_list_filter_fail(self): url = reverse('substrapp:algo-list') @@ -209,3 +215,47 @@ def test_algo_create(self): data['description'].close() data['file'].close() + + def test_algo_list_storage_addresses_update(self): + url = reverse('substrapp:algo-list') + with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.objective.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_algos = copy.deepcopy(algo) + for ledger_algo in ledger_algos: + for field in ('description', 'content'): + ledger_algo[field]['storageAddress'] = \ + ledger_algo[field]['storageAddress'].replace('http://testserver', + 'http://remotetestserver') + mquery_ledger.return_value = ledger_algos + + # actual test + res = self.client.get(url, **self.extra) + res_algos = res.data[0] + self.assertEqual(len(res_algos), len(algo)) + for i, res_algo in enumerate(res_algos): + for field in ('description', 'content'): + self.assertEqual(res_algo[field]['storageAddress'], + algo[i][field]['storageAddress']) + + def test_algo_retrieve_storage_addresses_update(self): + url = reverse('substrapp:algo-detail', args=[algo[0]['key']]) + with mock.patch('substrapp.views.algo.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.algo.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_algo = copy.deepcopy(algo[0]) + for field in ('description', 'content'): + ledger_algo[field]['storageAddress'] = \ + ledger_algo[field]['storageAddress'].replace('http://testserver', + 'http://remotetestserver') + mquery_ledger.return_value = ledger_algo + + # actual test + res = self.client.get(url, **self.extra) + for field in ('description', 'content'): + self.assertEqual(res.data[field]['storageAddress'], + algo[0][field]['storageAddress']) diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index a943d5e06..808ef7064 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -1,3 +1,4 @@ +import copy import os import shutil import logging @@ -50,15 +51,20 @@ def tearDown(self): def test_datamanager_list_empty(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: - mquery_ledger.side_effect = [[], ['ISIC']] + mquery_ledger.return_value = [] response = self.client.get(url, **self.extra) r = response.json() self.assertEqual(r, [[]]) + def test_datamanager_list_success(self): + url = reverse('substrapp:data_manager-list') + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger: + mquery_ledger.return_value = datamanager + response = self.client.get(url, **self.extra) r = response.json() - self.assertEqual(r, [['ISIC']]) + self.assertEqual(r, [datamanager]) def test_datamanager_list_filter_fail(self): url = reverse('substrapp:data_manager-list') @@ -184,3 +190,47 @@ def test_datamanager_create_dryrun(self): for x in files: files[x].close() + + def test_datamanager_list_storage_addresses_update(self): + url = reverse('substrapp:data_manager-list') + with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.datamanager.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_datamanagers = copy.deepcopy(datamanager) + for ledger_datamanager in ledger_datamanagers: + for field in ('description', 'opener'): + ledger_datamanager[field]['storageAddress'] = \ + ledger_datamanager[field]['storageAddress'] \ + .replace('http://testserver', 'http://remotetestserver') + mquery_ledger.return_value = ledger_datamanagers + + # actual test + res = self.client.get(url, **self.extra) + res_datamanagers = res.data[0] + self.assertEqual(len(res_datamanagers), len(datamanager)) + for i, res_datamanager in enumerate(res_datamanagers): + for field in ('description', 'opener'): + self.assertEqual(res_datamanager[field]['storageAddress'], + datamanager[i][field]['storageAddress']) + + def test_datamanager_retrieve_storage_addresses_update(self): + url = reverse('substrapp:data_manager-detail', args=[datamanager[0]['key']]) + with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.datamanager.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_datamanager = copy.deepcopy(datamanager[0]) + for field in ('description', 'opener'): + ledger_datamanager[field]['storageAddress'] = \ + ledger_datamanager[field]['storageAddress'].replace('http://testserver', + 'http://remotetestserver') + mquery_ledger.return_value = ledger_datamanager + + # actual test + res = self.client.get(url, **self.extra) + for field in ('description', 'opener'): + self.assertEqual(res.data[field]['storageAddress'], + datamanager[0][field]['storageAddress']) diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 60087ee12..554505d5f 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -5,16 +5,13 @@ import copy import mock -import requests from django.urls import reverse from django.test import override_settings -from requests.auth import HTTPBasicAuth from rest_framework import status from rest_framework.test import APITestCase -from substrapp.models import Objective from substrapp.serializers import LedgerObjectiveSerializer from substrapp.ledger_utils import LedgerError @@ -335,7 +332,7 @@ def test_objective_leaderboard_sort(self): response = self.client.get(url, data={'sort': 'foo'}, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - def test_objective_url_rewrite_list(self): + def test_objective_list_storage_addresses_update(self): url = reverse('substrapp:objective-list') with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger, \ mock.patch('substrapp.views.objective.get_remote_asset') as mget_remote_asset: @@ -359,7 +356,7 @@ def test_objective_url_rewrite_list(self): self.assertEqual(res_objective[field]['storageAddress'], objective[i][field]['storageAddress']) - def test_objective_url_rewrite_retrieve(self): + def test_objective_retrieve_storage_addresses_update(self): url = reverse('substrapp:objective-detail', args=[objective[0]['key']]) with mock.patch('substrapp.views.objective.get_object_from_ledger') as mquery_ledger, \ mock.patch('substrapp.views.objective.get_remote_asset') as mget_remote_asset: @@ -378,5 +375,3 @@ def test_objective_url_rewrite_retrieve(self): for field in ('description', 'metrics'): self.assertEqual(res.data[field]['storageAddress'], objective[0][field]['storageAddress']) - - diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 1270d683d..1d9a506a0 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -2,6 +2,7 @@ import logging from django.http import Http404 +from django.urls import reverse from rest_framework import status, mixins from rest_framework.decorators import action from rest_framework.exceptions import ValidationError @@ -18,6 +19,14 @@ from substrapp.views.filters_utils import filter_list +def replace_storage_addresses(request, algo): + algo['description']['storageAddress'] = request.build_absolute_uri( + reverse('substrapp:algo-description', args=[algo['key']])) + algo['content']['storageAddress'] = request.build_absolute_uri( + reverse('substrapp:algo-file', args=[algo['key']]) + ) + + class AlgoViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, @@ -124,7 +133,7 @@ def create_or_update_algo(self, algo, pk): return instance - def _retrieve(self, pk): + def _retrieve(self, request, pk): validate_pk(pk) data = get_object_from_ledger(pk, self.ledger_query_call) @@ -144,6 +153,8 @@ def _retrieve(self, pk): serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) data.update(serializer.data) + replace_storage_addresses(request, data) + return data def retrieve(self, request, *args, **kwargs): @@ -151,7 +162,7 @@ def retrieve(self, request, *args, **kwargs): pk = self.kwargs[lookup_url_kwarg] try: - data = self._retrieve(pk) + data = self._retrieve(request, pk) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) except Exception as e: @@ -184,6 +195,10 @@ def list(self, request, *args, **kwargs): {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) + for group in algos_list: + for algo in group: + replace_storage_addresses(request, algo) + return Response(algos_list, status=status.HTTP_200_OK) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 91c5679cf..e0688f29e 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -3,6 +3,7 @@ import logging from django.conf import settings from django.http import Http404 +from django.urls import reverse from rest_framework import status, mixins from rest_framework.decorators import action from rest_framework.exceptions import ValidationError @@ -23,6 +24,14 @@ from substrapp.views.filters_utils import filter_list +def replace_storage_addresses(request, data_manager): + data_manager['description']['storageAddress'] = request.build_absolute_uri( + reverse('substrapp:data_manager-description', args=[data_manager['key']])) + data_manager['opener']['storageAddress'] = request.build_absolute_uri( + reverse('substrapp:data_manager-opener', args=[data_manager['key']]) + ) + + class DataManagerViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, mixins.ListModelMixin, @@ -177,7 +186,7 @@ def create_or_update_datamanager(self, instance, datamanager, pk): return instance - def _retrieve(self, pk): + def _retrieve(self, request, pk): validate_pk(pk) # get instance from remote node data = get_object_from_ledger(pk, 'queryDataset') @@ -195,6 +204,8 @@ def _retrieve(self, pk): serializer = self.get_serializer(instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) data.update(serializer.data) + replace_storage_addresses(request, data) + return data def retrieve(self, request, *args, **kwargs): @@ -202,7 +213,7 @@ def retrieve(self, request, *args, **kwargs): pk = self.kwargs[lookup_url_kwarg] try: - data = self._retrieve(pk) + data = self._retrieve(request, pk) except LedgerError as e: return Response({'message': str(e.msg)}, status=e.status) except Exception as e: @@ -236,6 +247,10 @@ def list(self, request, *args, **kwargs): {'message': f'Malformed search filters {query_params}'}, status=status.HTTP_400_BAD_REQUEST) + for group in data_managers_list: + for data_manager in group: + replace_storage_addresses(request, data_manager) + return Response(data_managers_list, status=status.HTTP_200_OK) @action(methods=['post'], detail=True) From 09e634b3a4ddb1a3e826036ea6739d303ef241c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Thu, 3 Oct 2019 12:04:58 +0200 Subject: [PATCH 339/457] fix django/ledger prop discrepancies + forward headers with content --- .../substrapp/tests/views/tests_utils.py | 41 +++++++++++++++---- substrabac/substrapp/views/algo.py | 2 +- substrabac/substrapp/views/datamanager.py | 2 +- substrabac/substrapp/views/utils.py | 15 ++++--- 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_utils.py b/substrabac/substrapp/tests/views/tests_utils.py index 3a61ee7de..d6dda138f 100644 --- a/substrabac/substrapp/tests/views/tests_utils.py +++ b/substrabac/substrapp/tests/views/tests_utils.py @@ -15,13 +15,18 @@ class MockRequest: user = None -def with_permission_mixin(remote): +def with_permission_mixin(remote, same_file_property): def inner(f): @functools.wraps(f) def wrapper(self): + ledger_value = { + 'owner': 'owner-foo', + 'file_property' if same_file_property else 'ledger_file_property': { + 'storageAddress': 'foo' + } + } with mock.patch('substrapp.views.utils.get_object_from_ledger', - return_value={'owner': 'owner-foo', - 'file_property': {'storageAddress': 'foo'}}), \ + return_value=ledger_value), \ tempfile.NamedTemporaryFile() as tmp_file, \ mock.patch('substrapp.views.utils.get_owner', return_value='not-owner-foo' if remote else 'owner-foo'): @@ -58,10 +63,12 @@ def inner(f): @functools.wraps(f) def wrapper(*args, **kwargs): tmp_file = kwargs['tmp_file'] + filename = kwargs['filename'] requests_response = requests.Response() if allowed: requests_response.raw = tmp_file + requests_response.headers['Content-Disposition'] = f'attachment; filename="{filename}"' requests_response.status_code = status.HTTP_200_OK else: requests_response._content = b'{"message": "nope"}' @@ -78,26 +85,42 @@ def wrapper(*args, **kwargs): class PermissionMixinDownloadFileTests(APITestCase): - @with_permission_mixin(remote=False) + @with_permission_mixin(remote=False, same_file_property=False) def test_download_file_local(self, permission_mixin, content, filename, **kwargs): - res = permission_mixin.download_file(MockRequest(), 'file_property') + res = permission_mixin.download_file(MockRequest(), + 'file_property', + 'ledger_file_property') res_content = b''.join(list(res.streaming_content)) self.assertEqual(res_content, content) self.assertEqual(res['Content-Disposition'], f'attachment; filename="{filename}"') self.assertTrue(permission_mixin.get_object.called) - @with_permission_mixin(remote=True) + @with_permission_mixin(remote=True, same_file_property=False) @with_requests_mock(allowed=True) def test_download_file_remote_allowed(self, permission_mixin, content, filename, **kwargs): - res = permission_mixin.download_file(MockRequest(), 'file_property') + res = permission_mixin.download_file(MockRequest(), + 'file_property', + 'ledger_file_property') res_content = b''.join(list(res.streaming_content)) self.assertEqual(res_content, content) self.assertEqual(res['Content-Disposition'], f'attachment; filename="{filename}"') self.assertFalse(permission_mixin.get_object.called) - @with_permission_mixin(remote=True) + @with_permission_mixin(remote=True, same_file_property=False) @with_requests_mock(allowed=False) def test_download_file_remote_denied(self, permission_mixin, **kwargs): - res = permission_mixin.download_file(MockRequest(), 'file_property') + res = permission_mixin.download_file(MockRequest(), + 'file_property', + 'ledger_file_property') self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED) self.assertFalse(permission_mixin.get_object.called) + + @with_permission_mixin(remote=True, same_file_property=True) + @with_requests_mock(allowed=True) + def test_download_file_remote_same_file_property(self, permission_mixin, content, filename, + **kwargs): + res = permission_mixin.download_file(MockRequest(), 'file_property') + res_content = b''.join(list(res.streaming_content)) + self.assertEqual(res_content, content) + self.assertEqual(res['Content-Disposition'], f'attachment; filename="{filename}"') + self.assertFalse(permission_mixin.get_object.called) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 1d9a506a0..2cc7a9ae0 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -210,7 +210,7 @@ class AlgoPermissionViewSet(PermissionMixin, @action(detail=True) def file(self, request, *args, **kwargs): - return self.download_file(request, 'file') + return self.download_file(request, 'file', 'content') @action(detail=True) def description(self, request, *args, **kwargs): diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index e0688f29e..a9fef74a0 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -300,4 +300,4 @@ def description(self, request, *args, **kwargs): @action(detail=True) def opener(self, request, *args, **kwargs): - return self.download_file(request, 'data_opener') + return self.download_file(request, 'data_opener', 'opener') diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 27c5b19d1..2fc56e0f2 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -4,7 +4,7 @@ import binascii from importlib import import_module -from django.http import FileResponse +from django.http import FileResponse, StreamingHttpResponse from rest_framework.authentication import SessionAuthentication, BasicAuthentication, get_authorization_header from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -112,7 +112,7 @@ def _has_access(self, user, asset): node_id = user.username return node_id in permission['authorizedIDs'] - def download_file(self, request, field): + def download_file(self, request, django_field, ledger_field=None): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field pk = self.kwargs[lookup_url_kwarg] @@ -127,7 +127,7 @@ def download_file(self, request, field): if get_owner() == asset['owner']: obj = self.get_object() - data = getattr(obj, field) + data = getattr(obj, django_field) response = CustomFileResponse( open(data.path, 'rb'), as_attachment=True, @@ -136,16 +136,19 @@ def download_file(self, request, field): else: node_id = asset['owner'] auth = authenticate_outgoing_request(node_id) - r = get_remote_file(asset[field]['storageAddress'], auth, stream=True) + if not ledger_field: + ledger_field = django_field + r = get_remote_file(asset[ledger_field]['storageAddress'], auth, stream=True) if not r.ok: return Response({ 'message': f'Cannot proxify asset from node {asset["owner"]}: {str(r.text)}' }, status=r.status_code) - response = CustomFileResponse( + response = StreamingHttpResponse( streaming_content=r.raw, - as_attachment=True, status=r.status_code ) + for header in r.headers: + response[header] = r.headers.get(header) return response From 423645f39d9064944ce9027d32e55700ac9720c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Thu, 3 Oct 2019 16:25:15 +0200 Subject: [PATCH 340/457] fix tests --- substrabac/substrapp/tests/common.py | 2 ++ substrabac/substrapp/tests/query/tests_query_algo.py | 3 ++- substrabac/substrapp/tests/query/tests_query_objective.py | 3 ++- substrabac/substrapp/tests/tests_tasks.py | 8 ++++---- .../substrapp/tests/views/test_views_authentication.py | 6 ++++-- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/substrabac/substrapp/tests/common.py b/substrabac/substrapp/tests/common.py index 847e83586..9e41fa64e 100644 --- a/substrabac/substrapp/tests/common.py +++ b/substrabac/substrapp/tests/common.py @@ -192,12 +192,14 @@ def get_sample_model(): def get_sample_algo_metadata(): return { + 'owner': 'foo', 'permissions': DEFAULT_PERMISSIONS, } def get_sample_objective_metadata(): return { + 'owner': 'foo', 'permissions': DEFAULT_PERMISSIONS, } diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substrabac/substrapp/tests/query/tests_query_algo.py index 7580112ea..1f577096b 100644 --- a/substrabac/substrapp/tests/query/tests_query_algo.py +++ b/substrabac/substrapp/tests/query/tests_query_algo.py @@ -220,7 +220,8 @@ def test_add_algo_wrong_version(self): self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - def test_get_algo_files(self): + @mock.patch('substrapp.views.utils.get_owner', return_value='foo') + def test_get_algo_files(self, *args): algo = Algo.objects.create(file=self.algo) with mock.patch( 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: diff --git a/substrabac/substrapp/tests/query/tests_query_objective.py b/substrabac/substrapp/tests/query/tests_query_objective.py index f513a1555..8a44d2bb2 100644 --- a/substrabac/substrapp/tests/query/tests_query_objective.py +++ b/substrabac/substrapp/tests/query/tests_query_objective.py @@ -214,7 +214,8 @@ def test_add_objective_wrong_version(self): self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - def test_get_objective_metrics(self): + @mock.patch('substrapp.views.utils.get_owner', return_value='foo') + def test_get_objective_metrics(self, *args): objective = Objective.objects.create( description=self.objective_description, metrics=self.objective_metrics) diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substrabac/substrapp/tests/tests_tasks.py index faa4d2eeb..497fca61a 100644 --- a/substrabac/substrapp/tests/tests_tasks.py +++ b/substrabac/substrapp/tests/tests_tasks.py @@ -396,7 +396,7 @@ def test_get_model(self): model_type = 'model' subtuple = {model_type: {'hash': model_hash, 'traintupleKey': traintupleKey}} - with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file, \ + with mock.patch('substrapp.tasks.utils.get_remote_file_content') as mget_remote_file, \ mock.patch('substrapp.tasks.utils.get_owner') as mget_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as mget_object_from_ledger: mget_remote_file.return_value = model_content @@ -422,7 +422,7 @@ def test_get_models(self): subtuple = {model_type: [{'hash': model_hash, 'traintupleKey': traintupleKey}, {'hash': model_hash2, 'traintupleKey': traintupleKey2}]} - with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file, \ + with mock.patch('substrapp.tasks.utils.get_remote_file_content') as mget_remote_file, \ mock.patch('substrapp.tasks.utils.authenticate_worker'),\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger'): mget_remote_file.side_effect = (models_content[0], models_content[1]) @@ -443,7 +443,7 @@ def test_get_algo(self): } } - with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file,\ + with mock.patch('substrapp.tasks.utils.get_remote_file_content') as mget_remote_file,\ mock.patch('substrapp.tasks.utils.get_owner') as get_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: mget_remote_file.return_value = algo_content @@ -466,7 +466,7 @@ def test_get_objective(self): self.assertTrue(isinstance(objective, bytes)) self.assertEqual(objective, b'foo') - with mock.patch('substrapp.tasks.utils.get_remote_file') as mget_remote_file, \ + with mock.patch('substrapp.tasks.utils.get_remote_file_content') as mget_remote_file, \ mock.patch('substrapp.tasks.tasks.get_object_from_ledger'), \ mock.patch('substrapp.tasks.utils.authenticate_worker'),\ mock.patch('substrapp.models.Objective.objects.update_or_create') as mupdate_or_create: diff --git a/substrabac/substrapp/tests/views/test_views_authentication.py b/substrabac/substrapp/tests/views/test_views_authentication.py index ec8468585..a350afe79 100644 --- a/substrabac/substrapp/tests/views/test_views_authentication.py +++ b/substrabac/substrapp/tests/views/test_views_authentication.py @@ -30,7 +30,8 @@ def test_authentication_fail(self): self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) - def test_authentication_with_settings_success(self): + @mock.patch('substrapp.views.utils.get_owner', return_value='foo') + def test_authentication_with_settings_success(self, *args): authorization_header = generate_basic_auth_header(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) self.client.credentials(HTTP_AUTHORIZATION=authorization_header) @@ -49,7 +50,8 @@ def test_authentication_with_bad_settings_credentials_fail(self): self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) - def test_authentication_with_node(self): + @mock.patch('substrapp.views.utils.get_owner', return_value='foo') + def test_authentication_with_node(self, *args): authorization_header = generate_basic_auth_header('external_node_id', 's3cr37') self.client.credentials(HTTP_AUTHORIZATION=authorization_header) From 4eb37106e0ae8b72056ec796344054a710f9230f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Thu, 3 Oct 2019 17:11:12 +0200 Subject: [PATCH 341/457] harmonize mock.patch usage --- .../substrapp/tests/query/tests_query_algo.py | 8 ++++---- .../tests/query/tests_query_objective.py | 8 ++++---- .../tests/views/test_views_authentication.py | 15 +++++++++------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substrabac/substrapp/tests/query/tests_query_algo.py index 1f577096b..fa98326be 100644 --- a/substrabac/substrapp/tests/query/tests_query_algo.py +++ b/substrabac/substrapp/tests/query/tests_query_algo.py @@ -220,11 +220,11 @@ def test_add_algo_wrong_version(self): self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - @mock.patch('substrapp.views.utils.get_owner', return_value='foo') - def test_get_algo_files(self, *args): + def test_get_algo_files(self): algo = Algo.objects.create(file=self.algo) - with mock.patch( - 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + with mock.patch('substrapp.views.utils.get_owner', return_value='foo'), \ + mock.patch('substrapp.views.utils.get_object_from_ledger') \ + as mget_object_from_ledger: mget_object_from_ledger.return_value = get_sample_algo_metadata() extra = { diff --git a/substrabac/substrapp/tests/query/tests_query_objective.py b/substrabac/substrapp/tests/query/tests_query_objective.py index 8a44d2bb2..c61bdc80c 100644 --- a/substrabac/substrapp/tests/query/tests_query_objective.py +++ b/substrabac/substrapp/tests/query/tests_query_objective.py @@ -214,14 +214,14 @@ def test_add_objective_wrong_version(self): self.assertEqual(r, {'detail': 'Invalid version in "Accept" header.'}) self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - @mock.patch('substrapp.views.utils.get_owner', return_value='foo') - def test_get_objective_metrics(self, *args): + def test_get_objective_metrics(self): objective = Objective.objects.create( description=self.objective_description, metrics=self.objective_metrics) - with mock.patch( - 'substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + with mock.patch('substrapp.views.utils.get_owner', return_value='foo'), \ + mock.patch('substrapp.views.utils.get_object_from_ledger') \ + as mget_object_from_ledger: mget_object_from_ledger.return_value = get_sample_objective_metadata() extra = { 'HTTP_ACCEPT': 'application/json;version=0.0', diff --git a/substrabac/substrapp/tests/views/test_views_authentication.py b/substrabac/substrapp/tests/views/test_views_authentication.py index a350afe79..179edc986 100644 --- a/substrabac/substrapp/tests/views/test_views_authentication.py +++ b/substrabac/substrapp/tests/views/test_views_authentication.py @@ -30,13 +30,14 @@ def test_authentication_fail(self): self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) - @mock.patch('substrapp.views.utils.get_owner', return_value='foo') - def test_authentication_with_settings_success(self, *args): + def test_authentication_with_settings_success(self): authorization_header = generate_basic_auth_header(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) self.client.credentials(HTTP_AUTHORIZATION=authorization_header) - with mock.patch('substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + with mock.patch('substrapp.views.utils.get_owner', return_value='foo'), \ + mock.patch('substrapp.views.utils.get_object_from_ledger') \ + as mget_object_from_ledger: mget_object_from_ledger.return_value = get_sample_algo_metadata() response = self.client.get(self.algo_url, **self.extra) @@ -50,12 +51,14 @@ def test_authentication_with_bad_settings_credentials_fail(self): self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) - @mock.patch('substrapp.views.utils.get_owner', return_value='foo') - def test_authentication_with_node(self, *args): + def test_authentication_with_node(self): authorization_header = generate_basic_auth_header('external_node_id', 's3cr37') self.client.credentials(HTTP_AUTHORIZATION=authorization_header) - with mock.patch('substrapp.views.utils.get_object_from_ledger') as mget_object_from_ledger: + + with mock.patch('substrapp.views.utils.get_owner', return_value='foo'), \ + mock.patch('substrapp.views.utils.get_object_from_ledger') \ + as mget_object_from_ledger: mget_object_from_ledger.return_value = get_sample_algo_metadata() response = self.client.get(self.algo_url, **self.extra) From 55ab35d7abbc92b2a120260270f5af1b5190b93f Mon Sep 17 00:00:00 2001 From: Camille Marini Date: Thu, 3 Oct 2019 21:35:21 +0200 Subject: [PATCH 342/457] added Inal in codeowner --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f8ec605f1..0ecad7c26 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,4 +2,4 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @GuillaumeCisco @Kelvin-M +* @inalgnu @GuillaumeCisco @Kelvin-M From eaa6c9e6654061ed28e0fcda4e80ee96141f61d2 Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Fri, 4 Oct 2019 11:56:55 +0200 Subject: [PATCH 343/457] Blacklist hop-by-hop headers --- substrabac/substrapp/views/utils.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 2fc56e0f2..f17614373 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -143,12 +143,25 @@ def download_file(self, request, django_field, ledger_field=None): return Response({ 'message': f'Cannot proxify asset from node {asset["owner"]}: {str(r.text)}' }, status=r.status_code) - response = StreamingHttpResponse( - streaming_content=r.raw, - status=r.status_code - ) + + response = CustomFileResponse( + streaming_content=(chunk for chunk in r.iter_content(512 * 1024)), + status=r.status_code) + # List of hop-by-hop headers that are incompatible with WSGI + # therefor they need to be blacklist + hop_by_hop_headers = [ + 'Connection', + 'Keep-Alive', + 'Proxy-Authenticate', + 'Proxy-Authorization', + 'TE', + 'Trailers', + 'Transfer-Encoding', + 'Upgrade', + ] for header in r.headers: - response[header] = r.headers.get(header) + if header not in hop_by_hop_headers: + response[header] = r.headers.get(header) return response From c90d1f6fbb2e0e66aaa302dfa282f8305b235174 Mon Sep 17 00:00:00 2001 From: Thibault Robert Date: Fri, 4 Oct 2019 14:41:24 +0200 Subject: [PATCH 344/457] Use wsgiref lib to check headers --- substrabac/substrapp/views/utils.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index f17614373..94862538c 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -4,7 +4,7 @@ import binascii from importlib import import_module -from django.http import FileResponse, StreamingHttpResponse +from django.http import FileResponse from rest_framework.authentication import SessionAuthentication, BasicAuthentication, get_authorization_header from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -16,6 +16,7 @@ from django.conf import settings from rest_framework import status from requests.auth import HTTPBasicAuth +from wsgiref.util import is_hop_by_hop from django.utils.translation import ugettext_lazy as _ @@ -147,20 +148,11 @@ def download_file(self, request, django_field, ledger_field=None): response = CustomFileResponse( streaming_content=(chunk for chunk in r.iter_content(512 * 1024)), status=r.status_code) - # List of hop-by-hop headers that are incompatible with WSGI - # therefor they need to be blacklist - hop_by_hop_headers = [ - 'Connection', - 'Keep-Alive', - 'Proxy-Authenticate', - 'Proxy-Authorization', - 'TE', - 'Trailers', - 'Transfer-Encoding', - 'Upgrade', - ] + for header in r.headers: - if header not in hop_by_hop_headers: + # We don't use hop_by_hop headers since they are incompatible + # with WSGI + if not is_hop_by_hop(header): response[header] = r.headers.get(header) return response From 5a4f84c4bf49f7c1d7f2e4bf2c5409ac7f89a093 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Tue, 1 Oct 2019 15:13:54 +0200 Subject: [PATCH 345/457] Ease deployment with a set of daemonset --- charts/substrabac/Chart.yaml | 2 +- .../daemonset-nvidia-driver-cos.yaml | 99 +++++++++++++++++++ .../daemonset-nvidia-driver-ubuntu.yaml | 72 ++++++++++++++ .../templates/daemonset-nvidia-plugin.yaml | 43 ++++++++ .../daemonset-pull-docker-images.yaml | 74 ++++++++++++++ .../templates/deployment-backend.yaml | 7 +- .../templates/deployment-celerybeat.yaml | 7 +- .../templates/deployment-dryrunner.yaml | 7 +- .../templates/deployment-flower.yaml | 7 +- .../templates/deployment-scheduler.yaml | 7 +- .../templates/deployment-worker.yaml | 7 +- .../templates/job-add-incoming-nodes.yaml | 7 +- .../templates/job-add-outgoing-nodes.yaml | 7 +- charts/substrabac/templates/secret-pull.yaml | 16 +++ charts/substrabac/values.yaml | 17 ++++ 15 files changed, 362 insertions(+), 17 deletions(-) create mode 100644 charts/substrabac/templates/daemonset-nvidia-driver-cos.yaml create mode 100644 charts/substrabac/templates/daemonset-nvidia-driver-ubuntu.yaml create mode 100644 charts/substrabac/templates/daemonset-nvidia-plugin.yaml create mode 100644 charts/substrabac/templates/daemonset-pull-docker-images.yaml create mode 100644 charts/substrabac/templates/secret-pull.yaml diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml index 0b0cdb171..f2d363716 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substrabac/Chart.yaml @@ -1,6 +1,6 @@ name: substrabac home: https://substra.org/ -version: 1.0.0-alpha.4 +version: 1.0.0-alpha.6 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: diff --git a/charts/substrabac/templates/daemonset-nvidia-driver-cos.yaml b/charts/substrabac/templates/daemonset-nvidia-driver-cos.yaml new file mode 100644 index 000000000..653775a32 --- /dev/null +++ b/charts/substrabac/templates/daemonset-nvidia-driver-cos.yaml @@ -0,0 +1,99 @@ +{{- if and (.Values.gpu.enabled) (eq .Values.gpu.platform "cos") }} +# https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/nvidia-driver-installer/cos/daemonset-preloaded.yaml +# Copyright 2017 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# The Dockerfile and other source for this daemonset are in +# https://github.com/GoogleCloudPlatform/cos-gpu-installer +# +# This is the same as ../../daemonset.yaml except that it assumes that the +# docker image is present on the node instead of downloading from GCR. This +# allows easier upgrades because GKE can preload the correct image on the +# node and the daemonset can just use that image. +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: nvidia-driver-installer + namespace: kube-system + labels: + k8s-app: nvidia-driver-installer +spec: + selector: + matchLabels: + k8s-app: nvidia-driver-installer + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + name: nvidia-driver-installer + k8s-app: nvidia-driver-installer + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: cloud.google.com/gke-accelerator + operator: Exists + tolerations: + - operator: "Exists" + hostNetwork: true + hostPID: true + volumes: + - name: dev + hostPath: + path: /dev + - name: vulkan-icd-mount + hostPath: + path: /home/kubernetes/bin/nvidia/vulkan/icd.d + - name: nvidia-install-dir-host + hostPath: + path: /home/kubernetes/bin/nvidia + - name: root-mount + hostPath: + path: / + initContainers: + - image: "cos-nvidia-installer:fixed" + imagePullPolicy: Never + name: nvidia-driver-installer + resources: + requests: + cpu: 0.15 + securityContext: + privileged: true + env: + - name: NVIDIA_INSTALL_DIR_HOST + value: /home/kubernetes/bin/nvidia + - name: NVIDIA_INSTALL_DIR_CONTAINER + value: /usr/local/nvidia + - name: VULKAN_ICD_DIR_HOST + value: /home/kubernetes/bin/nvidia/vulkan/icd.d + - name: VULKAN_ICD_DIR_CONTAINER + value: /etc/vulkan/icd.d + - name: ROOT_MOUNT_DIR + value: /root + volumeMounts: + - name: nvidia-install-dir-host + mountPath: /usr/local/nvidia + - name: vulkan-icd-mount + mountPath: /etc/vulkan/icd.d + - name: dev + mountPath: /dev + - name: root-mount + mountPath: /root + containers: + - image: "gcr.io/google-containers/pause:2.0" + name: pause +{{- end }} diff --git a/charts/substrabac/templates/daemonset-nvidia-driver-ubuntu.yaml b/charts/substrabac/templates/daemonset-nvidia-driver-ubuntu.yaml new file mode 100644 index 000000000..6c24efd8b --- /dev/null +++ b/charts/substrabac/templates/daemonset-nvidia-driver-ubuntu.yaml @@ -0,0 +1,72 @@ +{{- if and (.Values.gpu.enabled) (eq .Values.gpu.platform "ubuntu") }} +# https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/nvidia-driver-installer/ubuntu/daemonset-preloaded.yaml +# Copyright 2017 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: nvidia-driver-installer + namespace: kube-system + labels: + k8s-app: nvidia-driver-installer +spec: + selector: + matchLabels: + k8s-app: nvidia-driver-installer + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + name: nvidia-driver-installer + k8s-app: nvidia-driver-installer + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: cloud.google.com/gke-accelerator + operator: Exists + tolerations: + - operator: "Exists" + volumes: + - name: dev + hostPath: + path: /dev + - name: boot + hostPath: + path: /boot + - name: root-mount + hostPath: + path: / + initContainers: + - image: gke-nvidia-installer:fixed + name: nvidia-driver-installer + resources: + requests: + cpu: 0.15 + securityContext: + privileged: true + volumeMounts: + - name: boot + mountPath: /boot + - name: dev + mountPath: /dev + - name: root-mount + mountPath: /root + containers: + - image: "gcr.io/google-containers/pause:2.0" + name: pause +{{- end }} diff --git a/charts/substrabac/templates/daemonset-nvidia-plugin.yaml b/charts/substrabac/templates/daemonset-nvidia-plugin.yaml new file mode 100644 index 000000000..cffcb0624 --- /dev/null +++ b/charts/substrabac/templates/daemonset-nvidia-plugin.yaml @@ -0,0 +1,43 @@ +{{- if .Values.gpu.enabled }} +# https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/1.0.0-beta/nvidia-device-plugin.yml +apiVersion: extensions/v1beta1 +kind: DaemonSet +metadata: + name: nvidia-device-plugin-daemonset + namespace: kube-system +spec: + updateStrategy: + type: RollingUpdate + template: + metadata: + # Mark this pod as a critical add-on; when enabled, the critical add-on scheduler + # reserves resources for critical add-on pods so that they can be rescheduled after + # a failure. This annotation works in tandem with the toleration below. + annotations: + scheduler.alpha.kubernetes.io/critical-pod: "" + labels: + name: nvidia-device-plugin-ds + spec: + tolerations: + # Allow this pod to be rescheduled while the node is in "critical add-ons only" mode. + # This, along with the annotation above marks this pod as a critical add-on. + - key: CriticalAddonsOnly + operator: Exists + - key: nvidia.com/gpu + operator: Exists + effect: NoSchedule + containers: + - image: nvidia/k8s-device-plugin:1.0.0-beta + name: nvidia-device-plugin-ctr + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + volumeMounts: + - name: device-plugin + mountPath: /var/lib/kubelet/device-plugins + volumes: + - name: device-plugin + hostPath: + path: /var/lib/kubelet/device-plugins +{{- end }} diff --git a/charts/substrabac/templates/daemonset-pull-docker-images.yaml b/charts/substrabac/templates/daemonset-pull-docker-images.yaml new file mode 100644 index 000000000..619692bc9 --- /dev/null +++ b/charts/substrabac/templates/daemonset-pull-docker-images.yaml @@ -0,0 +1,74 @@ +{{- if .Values.docker.config }} +--- +apiVersion: v1 +kind: Secret +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: {{ .Values.docker.config }} +metadata: + name: {{ template "substra.fullname" . }}-pull-docker-images-creds + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" . }}-pull-docker-images-creds + app.kubernetes.io/part-of: {{ template "substra.name" . }} +--- +{{- end }} +apiVersion: extensions/v1beta1 +kind: DaemonSet +metadata: + name: {{ template "substra.fullname" . }}-pull-docker-images + labels: + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" . }}-pull-docker-images + app.kubernetes.io/part-of: {{ template "substra.name" . }} +spec: + selector: + matchLabels: + name: {{ template "substra.fullname" . }}-pull-docker-images + updateStrategy: + type: RollingUpdate + template: + metadata: + labels: + name: {{ template "substra.fullname" . }}-pull-docker-images + spec: + initContainers: + - image: docker + name: init + resources: + requests: + cpu: 0.15 + securityContext: + privileged: true + command: ["sh", "-c"] + args: + - | + {{- range .Values.docker.pullImages }} + docker pull {{ . }} + {{- end }} + volumeMounts: + - name: dockersock + mountPath: "/var/run/docker.sock" + {{- if .Values.docker.config }} + - name: dockerconfig + mountPath: "/root/.docker" + {{- end }} + containers: + - image: "gcr.io/google-containers/pause:2.0" + name: pause + volumes: + - name: dockersock + hostPath: + path: {{ .Values.docker.socket }} + {{- if .Values.docker.config }} + - name: dockerconfig + secret: + secretName: {{ template "substra.fullname" . }}-pull-docker-images-creds + items: + - key: .dockerconfigjson + path: config.json + {{- end }} diff --git a/charts/substrabac/templates/deployment-backend.yaml b/charts/substrabac/templates/deployment-backend.yaml index 73fd41acb..7fa6e3e7a 100644 --- a/charts/substrabac/templates/deployment-backend.yaml +++ b/charts/substrabac/templates/deployment-backend.yaml @@ -20,9 +20,12 @@ spec: app.kubernetes.io/name: {{ template "substra.name" . }}-backend app.kubernetes.io/instance: {{ .Release.Name }} spec: - {{- with .Values.backend.image.pullSecrets }} + {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} imagePullSecrets: - {{- range . }} + {{- range $index, $value := .Values.pullSecretsInline }} + - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + {{- end }} + {{- range .Values.backend.image.pullSecrets }} - name: {{ . }} {{- end }} {{- end }} diff --git a/charts/substrabac/templates/deployment-celerybeat.yaml b/charts/substrabac/templates/deployment-celerybeat.yaml index 583ba6df3..147ce810d 100644 --- a/charts/substrabac/templates/deployment-celerybeat.yaml +++ b/charts/substrabac/templates/deployment-celerybeat.yaml @@ -20,9 +20,12 @@ spec: app.kubernetes.io/name: {{ template "substra.name" . }}-celerybeat app.kubernetes.io/instance: {{ .Release.Name }} spec: - {{- with .Values.celerybeat.image.pullSecrets }} + {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} imagePullSecrets: - {{- range . }} + {{- range $index, $value := .Values.pullSecretsInline }} + - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + {{- end }} + {{- range .Values.backend.image.pullSecrets }} - name: {{ . }} {{- end }} {{- end }} diff --git a/charts/substrabac/templates/deployment-dryrunner.yaml b/charts/substrabac/templates/deployment-dryrunner.yaml index d5bd4f2c6..5d2b956b0 100644 --- a/charts/substrabac/templates/deployment-dryrunner.yaml +++ b/charts/substrabac/templates/deployment-dryrunner.yaml @@ -20,9 +20,12 @@ spec: app.kubernetes.io/name: {{ template "substra.name" . }}-dryrunner app.kubernetes.io/instance: {{ .Release.Name }} spec: - {{- with .Values.celeryworker.image.pullSecrets }} + {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} imagePullSecrets: - {{- range . }} + {{- range $index, $value := .Values.pullSecretsInline }} + - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + {{- end }} + {{- range .Values.backend.image.pullSecrets }} - name: {{ . }} {{- end }} {{- end }} diff --git a/charts/substrabac/templates/deployment-flower.yaml b/charts/substrabac/templates/deployment-flower.yaml index a3b282f64..b7a67c6c7 100644 --- a/charts/substrabac/templates/deployment-flower.yaml +++ b/charts/substrabac/templates/deployment-flower.yaml @@ -21,9 +21,12 @@ spec: app.kubernetes.io/name: {{ template "substra.name" . }}-flower app.kubernetes.io/instance: {{ .Release.Name }} spec: - {{- with .Values.flower.image.pullSecrets }} + {{- if or .Values.pullSecretsInline .Values.flower.image.pullSecrets }} imagePullSecrets: - {{- range . }} + {{- range $index, $value := .Values.pullSecretsInline }} + - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + {{- end }} + {{- range .Values.flower.image.pullSecrets }} - name: {{ . }} {{- end }} {{- end }} diff --git a/charts/substrabac/templates/deployment-scheduler.yaml b/charts/substrabac/templates/deployment-scheduler.yaml index ee008e1d8..91ed1a9f0 100644 --- a/charts/substrabac/templates/deployment-scheduler.yaml +++ b/charts/substrabac/templates/deployment-scheduler.yaml @@ -20,9 +20,12 @@ spec: app.kubernetes.io/name: {{ template "substra.name" . }}-scheduler app.kubernetes.io/instance: {{ .Release.Name }} spec: - {{- with .Values.celeryworker.image.pullSecrets }} + {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} imagePullSecrets: - {{- range . }} + {{- range $index, $value := .Values.pullSecretsInline }} + - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + {{- end }} + {{- range .Values.backend.image.pullSecrets }} - name: {{ . }} {{- end }} {{- end }} diff --git a/charts/substrabac/templates/deployment-worker.yaml b/charts/substrabac/templates/deployment-worker.yaml index 2863d7613..4e3b0a543 100644 --- a/charts/substrabac/templates/deployment-worker.yaml +++ b/charts/substrabac/templates/deployment-worker.yaml @@ -20,9 +20,12 @@ spec: app.kubernetes.io/name: {{ template "substra.name" . }}-worker app.kubernetes.io/instance: {{ .Release.Name }} spec: - {{- with .Values.celeryworker.image.pullSecrets }} + {{- if or .Values.pullSecretsInline .Values.celeryworker.image.pullSecrets }} imagePullSecrets: - {{- range . }} + {{- range $index, $value := .Values.pullSecretsInline }} + - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + {{- end }} + {{- range .Values.celeryworker.image.pullSecrets }} - name: {{ . }} {{- end }} {{- end }} diff --git a/charts/substrabac/templates/job-add-incoming-nodes.yaml b/charts/substrabac/templates/job-add-incoming-nodes.yaml index 6f349e7e0..6c5e8efc6 100644 --- a/charts/substrabac/templates/job-add-incoming-nodes.yaml +++ b/charts/substrabac/templates/job-add-incoming-nodes.yaml @@ -14,9 +14,12 @@ spec: template: spec: restartPolicy: OnFailure - {{- with $.Values.backend.image.pullSecrets }} + {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} imagePullSecrets: - {{- range . }} + {{- range $index, $value := $.Values.pullSecretsInline }} + - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + {{- end }} + {{- range $.Values.backend.image.pullSecrets }} - name: {{ . }} {{- end }} {{- end }} diff --git a/charts/substrabac/templates/job-add-outgoing-nodes.yaml b/charts/substrabac/templates/job-add-outgoing-nodes.yaml index 8b0bf5649..082cb1b13 100644 --- a/charts/substrabac/templates/job-add-outgoing-nodes.yaml +++ b/charts/substrabac/templates/job-add-outgoing-nodes.yaml @@ -14,9 +14,12 @@ spec: template: spec: restartPolicy: OnFailure - {{- with $.Values.backend.image.pullSecrets }} + {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} imagePullSecrets: - {{- range . }} + {{- range $index, $value := $.Values.pullSecretsInline }} + - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + {{- end }} + {{- range $.Values.backend.image.pullSecrets }} - name: {{ . }} {{- end }} {{- end }} diff --git a/charts/substrabac/templates/secret-pull.yaml b/charts/substrabac/templates/secret-pull.yaml new file mode 100644 index 000000000..93e364044 --- /dev/null +++ b/charts/substrabac/templates/secret-pull.yaml @@ -0,0 +1,16 @@ +{{- range $index, $value := .Values.pullSecretsInline }} +--- +apiVersion: v1 +data: + .dockerconfigjson: {{ $value }} +kind: Secret +metadata: + name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + labels: + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} + app.kubernetes.io/name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} + app.kubernetes.io/part-of: {{ template "substra.name" $ }} +type: kubernetes.io/dockerconfigjson +{{- end }} diff --git a/charts/substrabac/values.yaml b/charts/substrabac/values.yaml index 8360d1b1a..105056363 100644 --- a/charts/substrabac/values.yaml +++ b/charts/substrabac/values.yaml @@ -1,3 +1,20 @@ +gpu: + enabled: false + platform: ubuntu # or cos + +docker: + # Path of the docker socket on the host + socket: /var/run/docker.sock + # Dockerconfig to be used to pull the images (base64'd) + config: null + # Images to pull + pullImages: + - eu.gcr.io/substra-208412/substratools:0.1.0 + - eu.gcr.io/substra-208412/substratools:0.0.1 + +# Inline secrets used to pull images of pods (base64'd) +pullSecretsInline: [] + backend: replicaCount: 1 settings: prod From fa2d5e92f292775c58d53bae57452117fa95fdf3 Mon Sep 17 00:00:00 2001 From: Samuel Date: Tue, 1 Oct 2019 14:08:54 +0200 Subject: [PATCH 346/457] get assets: don't cache assets if no process permissions Fix #359 --- substrabac/substrapp/views/algo.py | 42 ++++++++++++----------- substrabac/substrapp/views/datamanager.py | 33 ++++++++++-------- substrabac/substrapp/views/objective.py | 38 ++++++++++---------- substrabac/substrapp/views/utils.py | 6 ++++ 4 files changed, 66 insertions(+), 53 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 2cc7a9ae0..2b29c7110 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -15,7 +15,7 @@ from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (PermissionMixin, find_primary_key_error, validate_pk, get_success_create_code, LedgerException, ValidationException, - get_remote_asset) + get_remote_asset, node_has_process_permission) from substrapp.views.filters_utils import filter_list @@ -137,25 +137,27 @@ def _retrieve(self, request, pk): validate_pk(pk) data = get_object_from_ledger(pk, self.ledger_query_call) - # try to get it from local db to check if description exists - try: - instance = self.get_object() - except Http404: - instance = None - finally: - # check if instance has description - if not instance or not instance.description: - instance = self.create_or_update_algo(data, pk) - - # For security reason, do not give access to local file address - # Restrain data to some fields - # TODO: do we need to send creation date and/or last modified date ? - serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) - data.update(serializer.data) - - replace_storage_addresses(request, data) - - return data + # do not cache if node has not process permission + if not node_has_process_permission(data): + # try to get it from local db to check if description exists + try: + instance = self.get_object() + except Http404: + instance = None + finally: + # check if instance has description + if not instance or not instance.description: + instance = self.create_or_update_algo(data, pk) + + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date ? + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) + data.update(serializer.data) + + replace_storage_addresses(request, data) + + return data def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index a9fef74a0..b645444d8 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -20,7 +20,7 @@ from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict from substrapp.views.utils import (PermissionMixin, find_primary_key_error, validate_pk, get_success_create_code, ValidationException, LedgerException, - get_remote_asset) + get_remote_asset, node_has_process_permission) from substrapp.views.filters_utils import filter_list @@ -190,23 +190,26 @@ def _retrieve(self, request, pk): validate_pk(pk) # get instance from remote node data = get_object_from_ledger(pk, 'queryDataset') - # try to get it from local db to check if description exists - try: - instance = self.get_object() - except Http404: - instance = None - finally: - # check if instance has description or data_opener - if not instance or not instance.description or not instance.data_opener: - instance = self.create_or_update_datamanager(instance, data, pk) - # do not give access to local files address - serializer = self.get_serializer(instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) - data.update(serializer.data) + # do not cache if node has not process permission + if not node_has_process_permission(data): + # try to get it from local db to check if description exists + try: + instance = self.get_object() + except Http404: + instance = None + finally: + # check if instance has description or data_opener + if not instance or not instance.description or not instance.data_opener: + instance = self.create_or_update_datamanager(instance, data, pk) + + # do not give access to local files address + serializer = self.get_serializer(instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) + data.update(serializer.data) - replace_storage_addresses(request, data) + replace_storage_addresses(request, data) - return data + return data def retrieve(self, request, *args, **kwargs): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index fc45d36eb..e4cf462c0 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -25,8 +25,10 @@ from substrapp.utils import get_hash, create_directory, uncompress_path from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.tasks.utils import get_asset_content -from substrapp.views.utils import PermissionMixin, find_primary_key_error, validate_pk, \ - get_success_create_code, ValidationException, LedgerException, get_remote_asset, validate_sort +from substrapp.views.utils import (PermissionMixin, find_primary_key_error, validate_pk, + get_success_create_code, ValidationException, + LedgerException, get_remote_asset, validate_sort, + node_has_process_permission) from substrapp.views.filters_utils import filter_list @@ -180,7 +182,6 @@ def create(self, request, *args, **kwargs): return Response(data, status=st, headers=headers) def create_or_update_objective(self, objective, pk): - # get description from remote node url = objective['description']['storageAddress'] @@ -191,7 +192,6 @@ def create_or_update_objective(self, objective, pk): tmp_description.write(content) instance, created = Objective.objects.update_or_create(pkhash=pk, validated=True) instance.description.save('description.md', tmp_description) - return instance def _retrieve(self, request, pk): @@ -199,20 +199,22 @@ def _retrieve(self, request, pk): # get instance from remote node data = get_object_from_ledger(pk, self.ledger_query_call) - # try to get it from local db to check if description exists - try: - instance = self.get_object() - except Http404: - instance = None - - if not instance or not instance.description: - instance = self.create_or_update_objective(data, pk) - - # For security reason, do not give access to local file address - # Restrain data to some fields - # TODO: do we need to send creation date and/or last modified date ? - serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) - data.update(serializer.data) + # do not cache if node has not process permission + if not node_has_process_permission(data): + # try to get it from local db to check if description exists + try: + instance = self.get_object() + except Http404: + instance = None + + if not instance or not instance.description: + instance = self.create_or_update_objective(data, pk) + + # For security reason, do not give access to local file address + # Restrain data to some fields + # TODO: do we need to send creation date and/or last modified date ? + serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) + data.update(serializer.data) replace_storage_addresses(request, data) diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 94862538c..26ad20977 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -92,6 +92,12 @@ def authenticate_header(self, request): return '' +def node_has_process_permission(asset): + """Check if current node can process input asset.""" + permission = asset['permissions']['process'] + return permission['public'] or get_owner() in permission['authorizedIDs'] + + class PermissionMixin(object): authentication_classes = [import_module(settings.BASIC_AUTHENTICATION_MODULE).BasicAuthentication, From 8455f498b0c9429cc25b00a79b35e6a6d80dc437 Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 3 Oct 2019 10:54:21 +0200 Subject: [PATCH 347/457] fix bug --- substrabac/substrapp/views/algo.py | 2 +- substrabac/substrapp/views/objective.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 2b29c7110..3dab1dcba 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -138,7 +138,7 @@ def _retrieve(self, request, pk): data = get_object_from_ledger(pk, self.ledger_query_call) # do not cache if node has not process permission - if not node_has_process_permission(data): + if node_has_process_permission(data): # try to get it from local db to check if description exists try: instance = self.get_object() diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index e4cf462c0..f15cd4f86 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -200,7 +200,7 @@ def _retrieve(self, request, pk): data = get_object_from_ledger(pk, self.ledger_query_call) # do not cache if node has not process permission - if not node_has_process_permission(data): + if node_has_process_permission(data): # try to get it from local db to check if description exists try: instance = self.get_object() From 89507b9a13111264256937cc6c1bad0588b9485b Mon Sep 17 00:00:00 2001 From: Samuel Date: Thu, 3 Oct 2019 11:42:00 +0200 Subject: [PATCH 348/457] remove remaining not --- substrabac/substrapp/views/datamanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index b645444d8..42502177f 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -192,7 +192,7 @@ def _retrieve(self, request, pk): data = get_object_from_ledger(pk, 'queryDataset') # do not cache if node has not process permission - if not node_has_process_permission(data): + if node_has_process_permission(data): # try to get it from local db to check if description exists try: instance = self.get_object() From 7bfe78e6d9304d971ca5dae0bf75205efdcbf511 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Mon, 7 Oct 2019 11:16:58 +0200 Subject: [PATCH 349/457] Fixing rendering error --- charts/substrabac/Chart.yaml | 2 +- charts/substrabac/templates/job-add-incoming-nodes.yaml | 2 +- charts/substrabac/templates/job-add-outgoing-nodes.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml index f2d363716..9d132b189 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substrabac/Chart.yaml @@ -1,6 +1,6 @@ name: substrabac home: https://substra.org/ -version: 1.0.0-alpha.6 +version: 1.0.0-alpha.7 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: diff --git a/charts/substrabac/templates/job-add-incoming-nodes.yaml b/charts/substrabac/templates/job-add-incoming-nodes.yaml index 6c5e8efc6..650a0401a 100644 --- a/charts/substrabac/templates/job-add-incoming-nodes.yaml +++ b/charts/substrabac/templates/job-add-incoming-nodes.yaml @@ -14,7 +14,7 @@ spec: template: spec: restartPolicy: OnFailure - {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} + {{- if or $.Values.pullSecretsInline $.Values.backend.image.pullSecrets }} imagePullSecrets: {{- range $index, $value := $.Values.pullSecretsInline }} - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} diff --git a/charts/substrabac/templates/job-add-outgoing-nodes.yaml b/charts/substrabac/templates/job-add-outgoing-nodes.yaml index 082cb1b13..29f6521e2 100644 --- a/charts/substrabac/templates/job-add-outgoing-nodes.yaml +++ b/charts/substrabac/templates/job-add-outgoing-nodes.yaml @@ -14,7 +14,7 @@ spec: template: spec: restartPolicy: OnFailure - {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} + {{- if or $.Values.pullSecretsInline $.Values.backend.image.pullSecrets }} imagePullSecrets: {{- range $index, $value := $.Values.pullSecretsInline }} - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} From d3653173d58d96a344e810ad6b5f2e21a277c0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 7 Oct 2019 14:39:20 +0200 Subject: [PATCH 350/457] fix url replace when no caching --- .../substrapp/tests/views/tests_views_algo.py | 26 ++++++++++++++++++- .../tests/views/tests_views_datamanager.py | 26 ++++++++++++++++++- .../tests/views/tests_views_objective.py | 26 ++++++++++++++++++- substrabac/substrapp/views/algo.py | 2 +- substrabac/substrapp/views/datamanager.py | 2 +- 5 files changed, 77 insertions(+), 5 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substrabac/substrapp/tests/views/tests_views_algo.py index 9955d76dc..c06cd415f 100644 --- a/substrabac/substrapp/tests/views/tests_views_algo.py +++ b/substrabac/substrapp/tests/views/tests_views_algo.py @@ -240,9 +240,33 @@ def test_algo_list_storage_addresses_update(self): self.assertEqual(res_algo[field]['storageAddress'], algo[i][field]['storageAddress']) - def test_algo_retrieve_storage_addresses_update(self): + def test_algo_retrieve_storage_addresses_update_with_cache(self): url = reverse('substrapp:algo-detail', args=[algo[0]['key']]) with mock.patch('substrapp.views.algo.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.algo.node_has_process_permission', + return_value=True), \ + mock.patch('substrapp.views.algo.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_algo = copy.deepcopy(algo[0]) + for field in ('description', 'content'): + ledger_algo[field]['storageAddress'] = \ + ledger_algo[field]['storageAddress'].replace('http://testserver', + 'http://remotetestserver') + mquery_ledger.return_value = ledger_algo + + # actual test + res = self.client.get(url, **self.extra) + for field in ('description', 'content'): + self.assertEqual(res.data[field]['storageAddress'], + algo[0][field]['storageAddress']) + + def test_algo_retrieve_storage_addresses_update_without_cache(self): + url = reverse('substrapp:algo-detail', args=[algo[0]['key']]) + with mock.patch('substrapp.views.algo.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.algo.node_has_process_permission', + return_value=False), \ mock.patch('substrapp.views.algo.get_remote_asset') as mget_remote_asset: # mock content diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 808ef7064..90dc1dfac 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -215,9 +215,33 @@ def test_datamanager_list_storage_addresses_update(self): self.assertEqual(res_datamanager[field]['storageAddress'], datamanager[i][field]['storageAddress']) - def test_datamanager_retrieve_storage_addresses_update(self): + def test_datamanager_retrieve_storage_addresses_update_with_cache(self): url = reverse('substrapp:data_manager-detail', args=[datamanager[0]['key']]) with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.datamanager.node_has_process_permission', + return_value=True), \ + mock.patch('substrapp.views.datamanager.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_datamanager = copy.deepcopy(datamanager[0]) + for field in ('description', 'opener'): + ledger_datamanager[field]['storageAddress'] = \ + ledger_datamanager[field]['storageAddress'].replace('http://testserver', + 'http://remotetestserver') + mquery_ledger.return_value = ledger_datamanager + + # actual test + res = self.client.get(url, **self.extra) + for field in ('description', 'opener'): + self.assertEqual(res.data[field]['storageAddress'], + datamanager[0][field]['storageAddress']) + + def test_datamanager_retrieve_storage_addresses_update_without_cache(self): + url = reverse('substrapp:data_manager-detail', args=[datamanager[0]['key']]) + with mock.patch('substrapp.views.datamanager.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.datamanager.node_has_process_permission', + return_value=False), \ mock.patch('substrapp.views.datamanager.get_remote_asset') as mget_remote_asset: # mock content diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 554505d5f..3c9501fe7 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -356,9 +356,33 @@ def test_objective_list_storage_addresses_update(self): self.assertEqual(res_objective[field]['storageAddress'], objective[i][field]['storageAddress']) - def test_objective_retrieve_storage_addresses_update(self): + def test_objective_retrieve_storage_addresses_update_with_cache(self): url = reverse('substrapp:objective-detail', args=[objective[0]['key']]) with mock.patch('substrapp.views.objective.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.objective.node_has_process_permission', + return_value=True), \ + mock.patch('substrapp.views.objective.get_remote_asset') as mget_remote_asset: + + # mock content + mget_remote_asset.return_value = b'dummy binary content' + ledger_objective = copy.deepcopy(objective[0]) + for field in ('description', 'metrics'): + ledger_objective[field]['storageAddress'] = \ + ledger_objective[field]['storageAddress'].replace('http://testserver', + 'http://remotetestserver') + mquery_ledger.return_value = ledger_objective + + # actual test + res = self.client.get(url, **self.extra) + for field in ('description', 'metrics'): + self.assertEqual(res.data[field]['storageAddress'], + objective[0][field]['storageAddress']) + + def test_objective_retrieve_storage_addresses_update_without_cache(self): + url = reverse('substrapp:objective-detail', args=[objective[0]['key']]) + with mock.patch('substrapp.views.objective.get_object_from_ledger') as mquery_ledger, \ + mock.patch('substrapp.views.objective.node_has_process_permission', + return_value=False), \ mock.patch('substrapp.views.objective.get_remote_asset') as mget_remote_asset: # mock content diff --git a/substrabac/substrapp/views/algo.py b/substrabac/substrapp/views/algo.py index 3dab1dcba..79c3180e9 100644 --- a/substrabac/substrapp/views/algo.py +++ b/substrabac/substrapp/views/algo.py @@ -155,7 +155,7 @@ def _retrieve(self, request, pk): serializer = self.get_serializer(instance, fields=('owner', 'pkhash')) data.update(serializer.data) - replace_storage_addresses(request, data) + replace_storage_addresses(request, data) return data diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index 42502177f..e6d343010 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -207,7 +207,7 @@ def _retrieve(self, request, pk): serializer = self.get_serializer(instance, fields=('owner', 'pkhash', 'creation_date', 'last_modified')) data.update(serializer.data) - replace_storage_addresses(request, data) + replace_storage_addresses(request, data) return data From f1ed46e8cd557ce0e67fddf45b9a3adb2dd7f455 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Mon, 7 Oct 2019 15:05:10 +0200 Subject: [PATCH 351/457] Fix default mode for pulling images --- charts/substrabac/values.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/charts/substrabac/values.yaml b/charts/substrabac/values.yaml index 105056363..a71045cf6 100644 --- a/charts/substrabac/values.yaml +++ b/charts/substrabac/values.yaml @@ -8,9 +8,8 @@ docker: # Dockerconfig to be used to pull the images (base64'd) config: null # Images to pull - pullImages: - - eu.gcr.io/substra-208412/substratools:0.1.0 - - eu.gcr.io/substra-208412/substratools:0.0.1 + pullImages: [] + # - eu.gcr.io/substra-208412/substratools:0.0.1 # Inline secrets used to pull images of pods (base64'd) pullSecretsInline: [] From d86d0432ce30d5e6f6c845003fbaf3486f59be70 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Mon, 7 Oct 2019 15:05:47 +0200 Subject: [PATCH 352/457] Bump version --- charts/substrabac/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml index 9d132b189..fdb493c18 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substrabac/Chart.yaml @@ -1,6 +1,6 @@ name: substrabac home: https://substra.org/ -version: 1.0.0-alpha.7 +version: 1.0.0-alpha.8 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: From d082537f313f4fadfcb817f7b6385f82e871aabe Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 3 Oct 2019 09:51:21 +0200 Subject: [PATCH 353/457] Remove dryrun --- .gitignore | 1 - README.md | 4 - assets/celery chunantes dryrunner.png | Bin 124296 -> 0 bytes assets/celery owkin dryrunner.png | Bin 123876 -> 0 bytes .../templates/deployment-dryrunner.yaml | 176 ------------------ docker/celeryworker/Dockerfile | 1 - docker/start.py | 22 --- populate.py | 23 +-- .../containers/dryrun_data_sample/Dockerfile | 13 -- .../dryrun_data_sample/open_data_sample.py | 7 - .../tests/views/tests_views_datamanager.py | 28 --- .../tests/views/tests_views_datasample.py | 121 +----------- .../tests/views/tests_views_objective.py | 77 +------- substrabac/substrapp/views/datamanager.py | 35 +--- substrabac/substrapp/views/datasample.py | 116 +----------- substrabac/substrapp/views/objective.py | 119 +----------- 16 files changed, 26 insertions(+), 717 deletions(-) delete mode 100644 assets/celery chunantes dryrunner.png delete mode 100644 assets/celery owkin dryrunner.png delete mode 100644 charts/substrabac/templates/deployment-dryrunner.yaml delete mode 100644 substrabac/containers/dryrun_data_sample/Dockerfile delete mode 100644 substrabac/containers/dryrun_data_sample/open_data_sample.py diff --git a/.gitignore b/.gitignore index 7f89fbe3d..acabfcdf1 100644 --- a/.gitignore +++ b/.gitignore @@ -117,7 +117,6 @@ substrabac/substrapp/**/conf # ledger binary files bin -dryrun # test files substrabac/substrabac/description.md diff --git a/README.md b/README.md index 7ba8bd14e..4698a4c71 100644 --- a/README.md +++ b/README.md @@ -142,10 +142,8 @@ Note the use of the development settings. ```shell DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 celery -E -A substrabac worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 celery -E -A substrabac worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker -DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 celery -E -A substrabac worker -l info -B -n owkin -Q owkin,owkin.dryrunner,celery --hostname owkin.dryrunner DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 celery -E -A substrabac worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 celery -E -A substrabac worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker -DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 celery -E -A substrabac worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.dryrunner,celery --hostname chu-nantes.dryrunner DJANGO_SETTINGS_MODULE=substrabac.settings.common celery -A substrabac beat -l info ``` @@ -261,10 +259,8 @@ Use these configurations for easier debugging and productivity: ![](assets/server_chunantes.png) ![](assets/celery owkin worker.png) ![](assets/celery owkin scheduler.png) -![](assets/celery owkin dryrunner.png) ![](assets/celery chunantes worker.png) ![](assets/celery chunantes scheduler.png) -![](assets/celery chunantes dryrunner.png) ![](assets/celery_beat.png) Do not hesitate to put breakpoints in your code. Even with periodic celery tasks and hit the `bug` button for launching your pre configurations. diff --git a/assets/celery chunantes dryrunner.png b/assets/celery chunantes dryrunner.png deleted file mode 100644 index 343136dc3b161243714ac3896df12a37f15b1c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 124296 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 diff --git a/assets/celery owkin dryrunner.png b/assets/celery owkin dryrunner.png deleted file mode 100644 index 60b95934dfe64e6e6193764f528e92c6b6dbb67a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123876 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%0AY`-D^-lCxR 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�gNMo;0T$Z#dY`J}A~!t;-; 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 diff --git a/charts/substrabac/templates/deployment-dryrunner.yaml b/charts/substrabac/templates/deployment-dryrunner.yaml deleted file mode 100644 index 5d2b956b0..000000000 --- a/charts/substrabac/templates/deployment-dryrunner.yaml +++ /dev/null @@ -1,176 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ template "substra.fullname" . }}-dryrunner - labels: - app.kubernetes.io/managed-by: {{ .Release.Service }} - app.kubernetes.io/instance: {{ .Release.Name }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} - app.kubernetes.io/name: {{ template "substra.name" . }}-dryrunner - app.kubernetes.io/part-of: {{ template "substra.name" . }} -spec: - replicas: {{ .Values.celeryworker.replicaCount }} - selector: - matchLabels: - app.kubernetes.io/name: {{ template "substra.name" . }}-dryrunner - app.kubernetes.io/instance: {{ .Release.Name }} - template: - metadata: - labels: - app.kubernetes.io/name: {{ template "substra.name" . }}-dryrunner - app.kubernetes.io/instance: {{ .Release.Name }} - spec: - {{- if or .Values.pullSecretsInline .Values.backend.image.pullSecrets }} - imagePullSecrets: - {{- range $index, $value := .Values.pullSecretsInline }} - - name: {{ template "substra.fullname" $ }}-pull-secret-{{ $index }} - {{- end }} - {{- range .Values.backend.image.pullSecrets }} - - name: {{ . }} - {{- end }} - {{- end }} - containers: - - name: dryrunner - image: "{{ .Values.celeryworker.image.repository }}:{{ .Values.celeryworker.image.tag }}" - {{- if .Values.celeryworker.image.pullPolicy }} - imagePullPolicy: "{{ .Values.celeryworker.image.pullPolicy }}" - {{- end }} - command: ["celery"] - args: ["-A", "substrabac", "worker", "-E", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},{{ .Values.organization.name }}.dryrunner,celery", "--hostname", "{{ .Values.organization.name }}.dryrunner"] - env: - - name: ORG - value: {{ .Values.organization.name }} - - name: SUBSTRABAC_ORG - value: {{ .Values.organization.name }} - - name: SUBSTRABAC_DEFAULT_PORT - value: "8000" - - name: CELERY_BROKER_URL - value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.{{ .Values.backend.settings }} - - name: PYTHONUNBUFFERED - value: "1" - {{- with .Values.backend.auth }} - - name: BACK_AUTH_USER - value: {{ .user | quote }} - - name: BACK_AUTH_PASSWORD - value: {{ .password | quote }} - {{- else }} - - name: BACK_AUTH_USER - value: "" - - name: BACK_AUTH_PASSWORD - value: "" - {{- end }} - - name: DATABASE_HOST - value: {{ .Release.Name }}-postgresql - - name: FABRIC_CFG_PATH_ENV - value: /var/hyperledger/fabric_cfg - - name: CORE_PEER_ADDRESS_ENV - value: "{{ .Values.peer.host }}:{{ .Values.peer.port }}" - - name: FABRIC_LOGGING_SPEC - value: debug - - name: DEFAULT_DOMAIN - value: "{{ .Values.backend.defaultDomain }}" - - name: SUBSTRABAC_{{ .Values.organization.name | upper }}_DB_NAME - value: {{ .Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABAC_DB_USER - value: {{ .Values.postgresql.postgresqlUsername }} - - name: SUBSTRABAC_DB_PWD - value: {{ .Values.postgresql.postgresqlPassword }} - - name: DATABASE_HOST - value: {{ .Release.Name }}-postgresql - - name: MEDIA_ROOT - value: {{ .Values.persistence.hostPath }}/medias/ - - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/substrabac/conf.json - volumeMounts: - - mountPath: /host/var/run/docker.sock - name: dockersocket - - mountPath: {{ .Values.persistence.hostPath }} - name: data - - mountPath: /conf/{{ .Values.organization.name }}/substrabac - name: config - readOnly: true - - mountPath: /var/hyperledger/msp/signcerts - name: id-cert - - mountPath: /var/hyperledger/msp/keystore - name: id-key - - mountPath: /var/hyperledger/msp/cacerts - name: cacert - - mountPath: /var/hyperledger/msp/admincerts - name: admin-cert - - mountPath: /var/hyperledger/tls/server/pair - name: tls - - mountPath: /var/hyperledger/tls/server/cert - name: tls-rootcert - - mountPath: /var/hyperledger/tls/client/pair - name: tls-client - - mountPath: /var/hyperledger/tls/client/cert - name: tls-clientrootcert - - mountPath: /var/hyperledger/tls/ord/cert - name: ord-tls-rootcert - - mountPath: /var/hyperledger/admin_msp/signcerts - name: admin-cert - - mountPath: /var/hyperledger/admin_msp/keystore - name: admin-key - - mountPath: /var/hyperledger/admin_msp/cacerts - name: cacert - - mountPath: /var/hyperledger/admin_msp/admincerts - name: admin-cert - resources: - {{- toYaml .Values.celeryworker.resources | nindent 12 }} - volumes: - - name: dockersocket - hostPath: - path: /var/run/docker.sock - - name: data - persistentVolumeClaim: - claimName: {{ include "substra.fullname" . }} - - name: config - configMap: - name: {{ include "substra.fullname" . }}-backend - - name: fabric - configMap: - name: {{ $.Values.secrets.fabricConfigmap }} - - name: id-cert - secret: - secretName: {{ $.Values.secrets.cert }} - - name: id-key - secret: - secretName: {{ $.Values.secrets.key }} - - name: cacert - secret: - secretName: {{ $.Values.secrets.caCert }} - - name: tls - secret: - secretName: {{ $.Values.secrets.tls }} - - name: tls-rootcert - secret: - secretName: {{ $.Values.secrets.tlsRootCert }} - - name: tls-client - secret: - secretName: {{ $.Values.secrets.tlsClient }} - - name: tls-clientrootcert - secret: - secretName: {{ $.Values.secrets.tlsClientRootCerts }} - - name: admin-cert - secret: - secretName: {{ $.Values.secrets.adminCert }} - - name: admin-key - secret: - secretName: {{ $.Values.secrets.adminKey }} - - name: ord-tls-rootcert - secret: - secretName: {{ $.Values.secrets.tlsRootCert }} - {{- with .Values.celeryworker.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.celeryworker.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.celeryworker.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index c362c71a4..fbc05f4c3 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -12,7 +12,6 @@ COPY ./substrabac/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt COPY ./substrabac/libs /usr/src/app/libs -COPY ./substrabac/containers /usr/src/app/containers COPY ./substrabac/substrapp /usr/src/app/substrapp COPY ./substrabac/substrabac /usr/src/app/substrabac COPY ./substrabac/node /usr/src/app/node diff --git a/docker/start.py b/docker/start.py index 081ac4335..a74f3e39f 100644 --- a/docker/start.py +++ b/docker/start.py @@ -7,7 +7,6 @@ dir_path = os.path.dirname(os.path.realpath(__file__)) raven_backend_url = "https://cff352ba26fc49f19e01692db93bf951@sentry.io/1317743" -raven_dryrunner_url = "https://a1c2de65bb0f4120aa11d75bca9b47f6@sentry.io/1402760" raven_worker_url = "https://76abd6b5d11e48ea8a118831c86fc615@sentry.io/1402762" raven_scheduler_url = raven_worker_url @@ -221,23 +220,6 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro'] + hlf_volumes, 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} - dryrunner = { - 'container_name': f'{org_name_stripped}.dryrunner', - 'labels': ['substra'], - 'hostname': f'{org_name}.dryrunner', - 'image': 'substra/celeryworker', - 'restart': 'unless-stopped', - 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - f'celery -A substrabac worker -l info -n {org_name_stripped} ' - f'-Q {org_name},{org_name}.dryrunner,celery --hostname {org_name}.dryrunner"', - 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, - 'environment': backend_global_env.copy(), - 'volumes': [ - '/var/run/docker.sock:/var/run/docker.sock', - f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias:rw', - f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro'] + hlf_volumes, - 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} - # Check if we have nvidia docker if 'nvidia' in check_output(['docker', 'system', 'info', '-f', '"{{.Runtimes}}"']).decode('utf-8'): worker['runtime'] = 'nvidia' @@ -245,7 +227,6 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): if launch_settings == 'dev': media_root = f'MEDIA_ROOT={SUBSTRA_FOLDER}/medias/{org_name_stripped}' worker['environment'].append(media_root) - dryrunner['environment'].append(media_root) backend['environment'].append(media_root) else: default_domain = os.environ.get('SUBSTRABAC_DEFAULT_DOMAIN', '') @@ -253,16 +234,13 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): backend['environment'].append(f"DEFAULT_DOMAIN={default_domain}") worker['environment'].append(f"DEFAULT_DOMAIN={default_domain}") scheduler['environment'].append(f"DEFAULT_DOMAIN={default_domain}") - dryrunner['environment'].append(f"DEFAULT_DOMAIN={default_domain}") backend['environment'].append(f"RAVEN_URL={raven_backend_url}") scheduler['environment'].append(f"RAVEN_URL={raven_scheduler_url}") worker['environment'].append(f"RAVEN_URL={raven_worker_url}") - dryrunner['environment'].append(f"RAVEN_URL={raven_dryrunner_url}") docker_compose['substrabac_services']['substrabac' + org_name_stripped] = backend docker_compose['substrabac_services']['scheduler' + org_name_stripped] = scheduler docker_compose['substrabac_services']['worker' + org_name_stripped] = worker - docker_compose['substrabac_services']['dryrunner' + org_name_stripped] = dryrunner # Create all services along to conf COMPOSITION = {'services': {}, 'version': '2.3', 'networks': {'default': {'external': {'name': 'net_substra'}}}} diff --git a/populate.py b/populate.py index 7e23fd9b4..018c8f939 100644 --- a/populate.py +++ b/populate.py @@ -51,7 +51,7 @@ def zip_folder(path, destination): zipf.close() -def get_or_create(data, profile, asset, dryrun=False, local=True): +def get_or_create(data, profile, asset, local=True): client.set_profile(profile) @@ -61,17 +61,6 @@ def get_or_create(data, profile, asset, dryrun=False, local=True): method = getattr(client, f'add_{asset}') - if dryrun: - print('dryrun') - try: - r = method(data, dryrun=True, **method_kwargs) - except substra.exceptions.AlreadyExists as e: - r = e.response.json() - print(colored(json.dumps(r, indent=2), 'cyan')) - else: - print(colored(json.dumps(r, indent=2), 'magenta')) - - print('real') try: r = method(data, **method_kwargs) @@ -150,7 +139,7 @@ def do_populate(): 'description': os.path.join(dir_path, './fixtures/chunantes/datamanagers/datamanager0/description.md'), 'permissions': PUBLIC_PERMISSIONS, } - data_manager_org1_key = get_or_create(data, org_1, 'dataset', dryrun=True) + data_manager_org1_key = get_or_create(data, org_1, 'dataset') #################################################### @@ -172,7 +161,7 @@ def do_populate(): 'data_manager_keys': [data_manager_org1_key], 'test_only': False, } - train_data_sample_keys = get_or_create(data, org_1, 'data_samples', dryrun=True, local=False) + train_data_sample_keys = get_or_create(data, org_1, 'data_samples', local=False) else: print(f'register train data on datamanager {org_1} (will take datamanager creator as worker)') data = { @@ -184,7 +173,7 @@ def do_populate(): 'data_manager_keys': [data_manager_org1_key], 'test_only': False, } - train_data_sample_keys = get_or_create(data, org_1, 'data_samples', dryrun=True) + train_data_sample_keys = get_or_create(data, org_1, 'data_samples') #################################################### @@ -266,7 +255,7 @@ def do_populate(): 'test_data_manager_key': data_manager_org0_key } - objective_key = get_or_create(data, org_0, 'objective', dryrun=True) + objective_key = get_or_create(data, org_0, 'objective') #################################################### @@ -284,7 +273,7 @@ def do_populate(): 'permissions': PUBLIC_PERMISSIONS, } - get_or_create(data, org_0, 'objective', dryrun=True) + get_or_create(data, org_0, 'objective') #################################################### diff --git a/substrabac/containers/dryrun_data_sample/Dockerfile b/substrabac/containers/dryrun_data_sample/Dockerfile deleted file mode 100644 index 39a3025aa..000000000 --- a/substrabac/containers/dryrun_data_sample/Dockerfile +++ /dev/null @@ -1,13 +0,0 @@ -FROM eu.gcr.io/substra-208412/substratools:0.0.1 - -RUN apt-get update; apt-get install -y build-essential libssl-dev python3 python3-dev python3-pip -RUN pip3 install --upgrade pip -RUN pip3 install pillow numpy sklearn pandas - -RUN mkdir -p /sandbox/metrics - -WORKDIR /sandbox - -ADD ./open_data_sample.py . - -ENTRYPOINT ["python3", "open_data_sample.py"] diff --git a/substrabac/containers/dryrun_data_sample/open_data_sample.py b/substrabac/containers/dryrun_data_sample/open_data_sample.py deleted file mode 100644 index 3b15172b9..000000000 --- a/substrabac/containers/dryrun_data_sample/open_data_sample.py +++ /dev/null @@ -1,7 +0,0 @@ -import substratools as tools - - -if __name__ == "__main__": - opener = tools.opener.load_from_module() - opener.get_X() - opener.get_y() diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substrabac/substrapp/tests/views/tests_views_datamanager.py index 90dc1dfac..b55d78de6 100644 --- a/substrabac/substrapp/tests/views/tests_views_datamanager.py +++ b/substrabac/substrapp/tests/views/tests_views_datamanager.py @@ -163,34 +163,6 @@ def test_datamanager_retrieve_fail(self): response = self.client.get(url + search_params, **self.extra) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - def test_datamanager_create_dryrun(self): - url = reverse('substrapp:data_manager-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - files = { - 'data_opener': open( - os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py'), - 'rb'), - - 'description': open( - os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/description.md'), - 'rb')} - - data = { - 'name': 'ISIC 2018', - 'type': 'Images', - 'permissions_public': True, - 'permissions_authorized_ids': [], - 'dryrun': True - } - - response = self.client.post(url, {**data, **files}, format='multipart', **self.extra) - self.assertEqual(response.data, {'message': f'Your data opener is valid. You can remove the dryrun option.'}) - self.assertEqual(response.status_code, status.HTTP_200_OK) - - for x in files: - files[x].close() - def test_datamanager_list_storage_addresses_update(self): url = reverse('substrapp:data_manager-list') with mock.patch('substrapp.views.datamanager.query_ledger') as mquery_ledger, \ diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substrabac/substrapp/tests/views/tests_views_datasample.py index 1839769a7..1fa01223a 100644 --- a/substrabac/substrapp/tests/views/tests_views_datasample.py +++ b/substrabac/substrapp/tests/views/tests_views_datasample.py @@ -1,5 +1,4 @@ import os -import io import shutil import logging @@ -14,14 +13,12 @@ from substrapp.serializers import LedgerDataSampleSerializer -from substrapp.views.datasample import path_leaf, compute_dryrun as data_sample_compute_dryrun -from substrapp.utils import get_hash, uncompress_content, store_datasamples_archive +from substrapp.views.datasample import path_leaf +from substrapp.utils import get_hash, uncompress_content from substrapp.models import DataManager -from django.core.files.uploadedfile import InMemoryUploadedFile - -from ..common import get_sample_datamanager, FakeFilterDataManager, FakeDataManager, AuthenticatedClient +from ..common import get_sample_datamanager, FakeFilterDataManager, AuthenticatedClient MEDIA_ROOT = "/tmp/unittests_views/" @@ -90,47 +87,6 @@ def test_data_create_bulk(self): for x in data['files']: data[x].close() - @override_settings( - task_eager_propagates=True, - task_always_eager=True, - broker_url='memory://', - backend='memory' - ) - def test_data_create_bulk_dryrun(self): - url = reverse('substrapp:data_sample-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - data_path1 = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - data_path2 = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample0/0024899.zip') - - opener_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') - - data_manager_keys = [get_hash(opener_path)] - - data = { - 'files': [path_leaf(data_path1), path_leaf(data_path2)], - path_leaf(data_path1): open(data_path1, 'rb'), - path_leaf(data_path2): open(data_path2, 'rb'), - 'data_manager_keys': data_manager_keys, - 'test_only': False, - 'dryrun': True - } - - with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ - mock.patch.object(DataManager.objects, 'get') as mgetdatamanager: - mdatamanager.return_value = FakeFilterDataManager(1) - mgetdatamanager.return_value = FakeDataManager(opener_path) - - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertIn('Your dry-run has been taken in account. You can follow the task execution on ', - response.data['message']) - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - for x in data['files']: - data[x].close() - def test_data_create(self): url = reverse('substrapp:data_sample-list') @@ -230,77 +186,6 @@ def test_data_create_path(self): self.assertEqual(response.data[0]['pkhash'], pkhash) self.assertEqual(response.status_code, status.HTTP_201_CREATED) - @override_settings( - task_eager_propagates=True, - task_always_eager=True, - broker_url='memory://', - backend='memory' - ) - def test_data_create_dryrun(self): - - url = reverse('substrapp:data_sample-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - data_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.tar.gz') - - opener_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') - - data_manager_keys = [get_hash(opener_path)] - - data = { - 'file': open(data_path, 'rb'), - 'data_manager_keys': data_manager_keys, - 'test_only': False, - 'dryrun': True - } - - with mock.patch.object(DataManager.objects, 'filter') as mdatamanager, \ - mock.patch.object(DataManager.objects, 'get') as mgetdatamanager: - mdatamanager.return_value = FakeFilterDataManager(1) - mgetdatamanager.return_value = FakeDataManager(opener_path) - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertIn('Your dry-run has been taken in account. You can follow the task execution on ', - response.data['message']) - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - data['file'].close() - - def test_data_sample_compute_dryrun(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - data_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datasamples/datasample1/0024700.zip') - - shutil.copy(data_path, os.path.join(MEDIA_ROOT, '0024700.zip')) - - opener_path = os.path.join(dir_path, '../../../../fixtures/chunantes/datamanagers/datamanager0/opener.py') - - file_filename = "file.zip" - - archive_data = io.BytesIO() - with open(os.path.join(data_path), 'rb') as zip_file: - alen = archive_data.write(zip_file.read()) - - archive_object = InMemoryUploadedFile(archive_data, None, file_filename, - 'application/zip', alen, None) - archive_object.seek(0) - - pkhash, datasamples_path_from_file = store_datasamples_archive(archive_object) - - data = { - 'path': datasamples_path_from_file, - 'pkhash': pkhash, - } - - data_files = [data] - data_manager_keys = [get_hash(opener_path)] - - with mock.patch.object(DataManager.objects, 'get') as mdatamanager: - mdatamanager.return_value = FakeDataManager(opener_path) - data_sample_compute_dryrun(data_files, data_manager_keys, []) - def test_datasamples_list(self): url = reverse('substrapp:data_sample-list') with mock.patch('substrapp.views.datasample.query_ledger') as mquery_ledger: diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substrabac/substrapp/tests/views/tests_views_objective.py index 3c9501fe7..78fdd5c11 100644 --- a/substrabac/substrapp/tests/views/tests_views_objective.py +++ b/substrabac/substrapp/tests/views/tests_views_objective.py @@ -16,10 +16,9 @@ from substrapp.ledger_utils import LedgerError -from substrapp.views.objective import compute_dryrun as objective_compute_dryrun from substrapp.utils import compute_hash, get_hash -from ..common import get_sample_objective, FakeTask, AuthenticatedClient +from ..common import get_sample_objective, AuthenticatedClient from ..assets import objective, datamanager, traintuple, model MEDIA_ROOT = "/tmp/unittests_views/" @@ -234,80 +233,6 @@ def test_objective_create(self): data['description'].close() data['metrics'].close() - def test_objective_create_dryrun(self): - - url = reverse('substrapp:objective-list') - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - objective_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/') - - description_path = os.path.join(objective_path, 'description.md') - - metrics_path = os.path.join(MEDIA_ROOT, 'metrics.zip') - - zip_folder(objective_path, metrics_path) - - test_data_manager_key = get_hash(os.path.join( - dir_path, '../../../../fixtures/owkin/datamanagers/datamanager0/opener.py')) - - data = { - 'name': 'Simplified skin lesion classification', - 'description': open(description_path, 'rb'), - 'metrics_name': 'macro-average recall', - 'metrics': open(metrics_path, 'rb'), - 'permissions_public': True, - 'permissions_authorized_ids': [], - 'test_data_sample_keys': self.test_data_sample_keys, - 'test_data_manager_key': test_data_manager_key, - 'dryrun': True - } - - with mock.patch('substrapp.views.objective.compute_dryrun.apply_async') as mdryrun_task: - - mdryrun_task.return_value = FakeTask('42') - response = self.client.post(url, data=data, format='multipart', **self.extra) - - self.assertEqual(response.data['id'], '42') - self.assertEqual(response.data['message'], - 'Your dry-run has been taken in account. ' - 'You can follow the task execution on https://localhost/task/42/') - self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - - data['description'].close() - data['metrics'].close() - - def test_objective_compute_dryrun(self): - - dir_path = os.path.dirname(os.path.realpath(__file__)) - - objective_path = os.path.join(dir_path, '../../../../fixtures/owkin/objectives/objective0/') - description_path = os.path.join(objective_path, 'description.md') - zip_path = os.path.join(MEDIA_ROOT, 'metrics.zip') - - opener_path = os.path.join(dir_path, '../../../../fixtures/owkin/datamanagers/datamanager0/opener.py') - - zip_folder(objective_path, zip_path) - - with open(opener_path, 'rb') as f: - opener_content = f.read() - - pkhash = get_hash(description_path) - - test_data_manager_key = compute_hash(opener_content) - - with mock.patch('substrapp.views.objective.get_object_from_ledger') as mdatamanager,\ - mock.patch('substrapp.views.objective.get_asset_content') as mget_asset_content: - mdatamanager.return_value = { - 'opener': { - 'storageAddress': 'test', - 'hash': pkhash - }, - 'owner': 'external_node_id' - } - mget_asset_content.return_value = opener_content - objective_compute_dryrun(zip_path, test_data_manager_key, pkhash) - def test_objective_leaderboard_sort(self): url = reverse('substrapp:objective-leaderboard', args=[objective[0]['key']]) with mock.patch('substrapp.views.objective.query_ledger') as mquery_ledger: diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index e6d343010..b1c496c5d 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -1,4 +1,3 @@ -import ast import tempfile import logging from django.conf import settings @@ -43,22 +42,6 @@ class DataManagerViewSet(mixins.CreateModelMixin, def perform_create(self, serializer): return serializer.save() - def handle_dryrun(self, data_opener): - - file = data_opener.open().read() - - try: - node = ast.parse(file) - except BaseException: - raise Exception('Opener must be a valid python file, please review your opener file and the documentation.') - - imported_module_names = [m.name for e in node.body if isinstance(e, ast.Import) for m in e.names] - if 'substratools' not in imported_module_names: - err_msg = 'Opener must import substratools, please review your opener and the documentation.' - return {'message': err_msg}, status.HTTP_400_BAD_REQUEST - - return {'message': f'Your data opener is valid. You can remove the dryrun option.'} - def commit(self, serializer, request): # create on ledger + db ledger_data = { @@ -106,7 +89,7 @@ def commit(self, serializer, request): return d - def _create(self, request, data_opener, dryrun): + def _create(self, request, data_opener): pkhash = get_hash(data_opener) serializer = self.get_serializer(data={ 'pkhash': pkhash, @@ -123,26 +106,18 @@ def _create(self, request, data_opener, dryrun): st = status.HTTP_409_CONFLICT raise ValidationException(e.args, pkhash, st) else: - if dryrun: - return self.handle_dryrun(data_opener) - # create on ledger + db return self.commit(serializer, request) - def _get_create_status(self, dryrun): - if dryrun: - st = status.HTTP_200_OK - else: - st = get_success_create_code() + def _get_create_status(self): - return st + return get_success_create_code() def create(self, request, *args, **kwargs): - dryrun = request.data.get('dryrun', False) data_opener = request.data.get('data_opener') try: - data = self._create(request, data_opener, dryrun) + data = self._create(request, data_opener) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -151,7 +126,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) - st = self._get_create_status(dryrun) + st = self._get_create_status() return Response(data, status=st, headers=headers) def create_or_update_datamanager(self, instance, datamanager, pk): diff --git a/substrabac/substrapp/views/datasample.py b/substrabac/substrapp/views/datasample.py index 431199a29..a35bb3327 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substrabac/substrapp/views/datasample.py @@ -1,31 +1,24 @@ import logging from os.path import normpath -import docker import os import ntpath -import uuid import shutil from checksumdir import dirhash from django.conf import settings -from docker.errors import ContainerError from rest_framework import status, mixins from rest_framework.decorators import action from rest_framework.exceptions import ValidationError from rest_framework.fields import BooleanField from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet -from rest_framework.reverse import reverse - -from substrabac.celery import app from substrapp.models import DataSample, DataManager from substrapp.serializers import DataSampleSerializer, LedgerDataSampleSerializer from substrapp.serializers.ledger.datasample.util import updateLedgerDataSample from substrapp.serializers.ledger.datasample.tasks import updateLedgerDataSampleAsync from substrapp.utils import store_datasamples_archive -from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials from substrapp.views.utils import find_primary_key_error, LedgerException, ValidationException, \ get_success_create_code from substrapp.ledger_utils import query_ledger, LedgerError, LedgerTimeout, LedgerConflict @@ -40,13 +33,6 @@ class DataSampleViewSet(mixins.CreateModelMixin, queryset = DataSample.objects.all() serializer_class = DataSampleSerializer - def dryrun_task(self, data, data_manager_keys, paths_to_remove): - task = compute_dryrun.apply_async((data, data_manager_keys, paths_to_remove), - queue=f"{settings.LEDGER['name']}.dryrunner") - current_site = getattr(settings, "DEFAULT_DOMAIN") - task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' - return task, f'Your dry-run has been taken in account. You can follow the task execution on {task_route}' - @staticmethod def check_datamanagers(data_manager_keys): datamanager_count = DataManager.objects.filter(pkhash__in=data_manager_keys).count() @@ -170,20 +156,10 @@ def compute_data(self, request, paths_to_remove): return list(data.values()) - def handle_dryrun(self, data, data_manager_keys, paths_to_remove): - - try: - task, msg = self.dryrun_task(data, data_manager_keys, paths_to_remove) - except Exception as e: - raise Exception(f'Could not launch data creation with dry-run on this instance: {str(e)}') - else: - return {'id': task.id, 'message': msg}, status.HTTP_202_ACCEPTED - - def _create(self, request, data_manager_keys, test_only, dryrun): + def _create(self, request, data_manager_keys, test_only): # compute_data will uncompress data archives to paths which will be - # hardlinked thanks to datasample pre_save signal. In case of dryrun - # we must keep those references, which will be removed by the dryrun tasks. + # hardlinked thanks to datasample pre_save signal. # In all other cases, we need to remove those references. if not data_manager_keys: @@ -208,8 +184,6 @@ def _create(self, request, data_manager_keys, test_only, dryrun): st = status.HTTP_409_CONFLICT raise ValidationException(e.args, pkhashes, st) else: - if dryrun: - return self.handle_dryrun(computed_data, data_manager_keys, paths_to_remove) # create on ledger + db ledger_data = {'test_only': test_only, @@ -217,19 +191,15 @@ def _create(self, request, data_manager_keys, test_only, dryrun): data, st = self.commit(serializer, ledger_data) # pre_save signal executed return data, st finally: - if not dryrun: - # Remove the reference paths of uncompressed data archive as they were all - # harlinked in the commit. We must keep them for the dryrun case - for gpath in paths_to_remove: - shutil.rmtree(gpath, ignore_errors=True) + for gpath in paths_to_remove: + shutil.rmtree(gpath, ignore_errors=True) def create(self, request, *args, **kwargs): - dryrun = request.data.get('dryrun', False) test_only = request.data.get('test_only', False) data_manager_keys = request.data.getlist('data_manager_keys', []) try: - data, st = self._create(request, data_manager_keys, test_only, dryrun) + data, st = self._create(request, data_manager_keys, test_only) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -301,79 +271,3 @@ def bulk_update(self, request): def path_leaf(path): head, tail = ntpath.split(path) return tail or ntpath.basename(head) - - -@app.task(bind=True, ignore_result=False) -def compute_dryrun(self, data_samples, data_manager_keys, paths_to_remove): - from shutil import copy - from substrapp.models import DataManager - - client = docker.from_env() - - # Name of the dry-run subtuple (not important) - pkhash = data_samples[0]['pkhash'] - dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' - subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) - data_path = os.path.join(subtuple_directory, 'data') - volumes = {} - - try: - for data_sample in data_samples: - # for all data paths, we need to create symbolic links inside data_path - # and add real path to volume bind docker - os.symlink(data_sample['path'], os.path.join(data_path, data_sample['pkhash'])) - volumes.update({ - data_sample['path']: {'bind': data_sample['path'], 'mode': 'ro'} - }) - - for datamanager_key in data_manager_keys: - datamanager = DataManager.objects.get(pk=datamanager_key) - copy(datamanager.data_opener.path, os.path.join(subtuple_directory, 'opener/opener.py')) - - opener_file = os.path.join(subtuple_directory, 'opener/opener.py') - data_sample_docker_path = os.path.join(getattr(settings, 'PROJECT_ROOT'), 'containers/dryrun_data_sample') - - data_docker = 'data_dry_run' - data_docker_name = f'{data_docker}_{dryrun_uuid}' - - volumes.update({ - data_path: {'bind': '/sandbox/data', 'mode': 'ro'}, - opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'} - }) - - client.images.build(path=data_sample_docker_path, - tag=data_docker, - rm=False) - - job_args = { - 'image': data_docker, - 'name': data_docker_name, - 'cpuset_cpus': '0-0', - 'mem_limit': '1G', - 'command': None, - 'volumes': volumes, - 'shm_size': '8G', - 'labels': ['dryrun'], - 'detach': False, - 'auto_remove': False, - 'remove': False, - } - - client.containers.run(**job_args) - - except ContainerError as e: - raise Exception(e.stderr) - - finally: - try: - container = client.containers.get(data_docker_name) - container.remove() - except Exception: - logger.error('Could not remove containers') - - remove_subtuple_materials(subtuple_directory) - - # Clean dryrun materials - for path in paths_to_remove: - # Remove all possible data (data in servermedias is read-only) - shutil.rmtree(path, ignore_errors=True) diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index f15cd4f86..1e6e77399 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -1,30 +1,22 @@ -import docker import logging -import os import re import tempfile -import uuid -from django.conf import settings from django.db import IntegrityError from django.http import Http404 from django.urls import reverse -from docker.errors import ContainerError from rest_framework import status, mixins from rest_framework.decorators import action from rest_framework.exceptions import ValidationError from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet -from substrabac.celery import app from substrapp.models import Objective from substrapp.serializers import ObjectiveSerializer, LedgerObjectiveSerializer from substrapp.ledger_utils import query_ledger, get_object_from_ledger, LedgerError, LedgerTimeout, LedgerConflict -from substrapp.utils import get_hash, create_directory, uncompress_path -from substrapp.tasks.tasks import build_subtuple_folders, remove_subtuple_materials -from substrapp.tasks.utils import get_asset_content +from substrapp.utils import get_hash from substrapp.views.utils import (PermissionMixin, find_primary_key_error, validate_pk, get_success_create_code, ValidationException, LedgerException, get_remote_asset, validate_sort, @@ -51,28 +43,6 @@ class ObjectiveViewSet(mixins.CreateModelMixin, def perform_create(self, serializer): return serializer.save() - def handle_dryrun(self, pkhash, metrics, test_data_manager_key): - try: - dryrun_directory = os.path.join(getattr(settings, 'MEDIA_ROOT'), 'dryrun') - create_directory(dryrun_directory) - - metrics_path = os.path.join(dryrun_directory, f'metrics_{pkhash}.archive') - - with open(metrics_path, 'wb') as fh: - fh.write(metrics.open().read()) - task = compute_dryrun.apply_async( - (metrics_path, test_data_manager_key, pkhash), - queue=f"{settings.LEDGER['name']}.dryrunner" - ) - except Exception as e: - raise Exception(f'Could not launch objective creation with dry-run on this instance: {str(e)}') - else: - current_site = getattr(settings, "DEFAULT_DOMAIN") - task_route = f'{current_site}{reverse("substrapp:task-detail", args=[task.id])}' - msg = f'Your dry-run has been taken in account. You can follow the task execution on {task_route}' - - return {'id': task.id, 'message': msg} - def commit(self, serializer, request): # create on local db try: @@ -130,10 +100,9 @@ def commit(self, serializer, request): return d - def _create(self, request, dryrun): + def _create(self, request): metrics = request.data.get('metrics') description = request.data.get('description') - test_data_manager_key = request.data.get('test_data_manager_key', '') pkhash = get_hash(description) @@ -151,25 +120,16 @@ def _create(self, request, dryrun): st = status.HTTP_409_CONFLICT raise ValidationException(e.args, pkhash, st) else: - if dryrun: - return self.handle_dryrun(pkhash, metrics, test_data_manager_key) - # create on ledger + db return self.commit(serializer, request) - def _get_create_status(self, dryrun): - if dryrun: - st = status.HTTP_202_ACCEPTED - else: - st = get_success_create_code() - - return st + def _get_create_status(self): + return get_success_create_code() def create(self, request, *args, **kwargs): - dryrun = request.data.get('dryrun', False) try: - data = self._create(request, dryrun) + data = self._create(request) except ValidationException as e: return Response({'message': e.data, 'pkhash': e.pkhash}, status=e.st) except LedgerException as e: @@ -178,7 +138,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) - st = self._get_create_status(dryrun) + st = self._get_create_status() return Response(data, status=st, headers=headers) def create_or_update_objective(self, objective, pk): @@ -293,73 +253,6 @@ def leaderboard(self, request, pk): return Response(leaderboard, status=status.HTTP_200_OK) -@app.task(bind=True, ignore_result=False) -def compute_dryrun(self, archive_path, test_data_manager_key, pkhash): - if not test_data_manager_key: - os.remove(archive_path) - raise Exception('Cannot do an objective dryrun without a data manager key.') - - dryrun_uuid = f'{pkhash}_{uuid.uuid4().hex}' - - subtuple_directory = build_subtuple_folders({'key': dryrun_uuid}) - metrics_path = f'{subtuple_directory}/metrics' - uncompress_path(archive_path, metrics_path) - os.remove(archive_path) - - datamanager = get_object_from_ledger(test_data_manager_key, 'queryDataManager') - opener_content = get_asset_content( - datamanager['opener']['storageAddress'], - datamanager['owner'], - datamanager['opener']['hash'], - ) - - with open(os.path.join(subtuple_directory, 'opener/opener.py'), 'wb') as fh: - fh.write(opener_content) - - # Launch verification - client = docker.from_env() - pred_path = os.path.join(subtuple_directory, 'pred') - opener_file = os.path.join(subtuple_directory, 'opener/opener.py') - - metrics_docker = 'metrics_dry_run' - metrics_docker_name = f'{metrics_docker}_{dryrun_uuid}' - volumes = { - pred_path: {'bind': '/sandbox/pred', 'mode': 'rw'}, - opener_file: {'bind': '/sandbox/opener/__init__.py', 'mode': 'ro'}} - - client.images.build(path=metrics_path, - tag=metrics_docker, - rm=False) - - job_args = { - 'image': metrics_docker, - 'name': metrics_docker_name, - 'cpuset_cpus': '0-0', - 'mem_limit': '1G', - 'command': '--dry-run', - 'volumes': volumes, - 'shm_size': '8G', - 'labels': ['dryrun'], - 'detach': False, - 'auto_remove': False, - 'remove': False} - - try: - client.containers.run(**job_args) - if not os.path.exists(os.path.join(pred_path, 'perf.json')): - raise Exception('Perf file not found') - except ContainerError as e: - raise Exception(e.stderr) - finally: - try: - container = client.containers.get(metrics_docker_name) - container.remove(force=True) - except BaseException as e: - logging.error(e, exc_info=True) - - remove_subtuple_materials(subtuple_directory) - - class ObjectivePermissionViewSet(PermissionMixin, GenericViewSet): queryset = Objective.objects.all() From b46b7ebda636ec45c42fdf5e75ab1100c93dbe6c Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Fri, 4 Oct 2019 07:46:53 +0200 Subject: [PATCH 354/457] Remove useless methods --- substrabac/substrapp/views/datamanager.py | 6 +----- substrabac/substrapp/views/objective.py | 5 +---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/substrabac/substrapp/views/datamanager.py b/substrabac/substrapp/views/datamanager.py index b1c496c5d..982e6fa1a 100644 --- a/substrabac/substrapp/views/datamanager.py +++ b/substrabac/substrapp/views/datamanager.py @@ -109,10 +109,6 @@ def _create(self, request, data_opener): # create on ledger + db return self.commit(serializer, request) - def _get_create_status(self): - - return get_success_create_code() - def create(self, request, *args, **kwargs): data_opener = request.data.get('data_opener') @@ -126,7 +122,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) - st = self._get_create_status() + st = get_success_create_code() return Response(data, status=st, headers=headers) def create_or_update_datamanager(self, instance, datamanager, pk): diff --git a/substrabac/substrapp/views/objective.py b/substrabac/substrapp/views/objective.py index 1e6e77399..7aaa43e59 100644 --- a/substrabac/substrapp/views/objective.py +++ b/substrabac/substrapp/views/objective.py @@ -123,9 +123,6 @@ def _create(self, request): # create on ledger + db return self.commit(serializer, request) - def _get_create_status(self): - return get_success_create_code() - def create(self, request, *args, **kwargs): try: @@ -138,7 +135,7 @@ def create(self, request, *args, **kwargs): return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST) else: headers = self.get_success_headers(data) - st = self._get_create_status() + st = get_success_create_code() return Response(data, status=st, headers=headers) def create_or_update_objective(self, objective, pk): From 9d76e3b21582f7f6bcf9a2abea1e57a093e70e3f Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Tue, 8 Oct 2019 10:16:34 +0200 Subject: [PATCH 355/457] Fix an issue when you don't pull docker images --- charts/substrabac/Chart.yaml | 2 +- charts/substrabac/templates/daemonset-pull-docker-images.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml index fdb493c18..fd2bd5eee 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substrabac/Chart.yaml @@ -1,6 +1,6 @@ name: substrabac home: https://substra.org/ -version: 1.0.0-alpha.8 +version: 1.0.0-alpha.9 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: diff --git a/charts/substrabac/templates/daemonset-pull-docker-images.yaml b/charts/substrabac/templates/daemonset-pull-docker-images.yaml index 619692bc9..75369a41c 100644 --- a/charts/substrabac/templates/daemonset-pull-docker-images.yaml +++ b/charts/substrabac/templates/daemonset-pull-docker-images.yaml @@ -1,3 +1,4 @@ +{{- if .Values.docker.pullImages }}} {{- if .Values.docker.config }} --- apiVersion: v1 @@ -72,3 +73,4 @@ spec: - key: .dockerconfigjson path: config.json {{- end }} +{{- end }} From 064f7aece4dd86f67c533c39b86c04bf9252c3e4 Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Wed, 9 Oct 2019 10:54:49 +0200 Subject: [PATCH 356/457] Shame, shame, shame --- charts/substrabac/Chart.yaml | 2 +- charts/substrabac/templates/daemonset-pull-docker-images.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/substrabac/Chart.yaml b/charts/substrabac/Chart.yaml index fd2bd5eee..d9a43b7bc 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substrabac/Chart.yaml @@ -1,6 +1,6 @@ name: substrabac home: https://substra.org/ -version: 1.0.0-alpha.9 +version: 1.0.0-alpha.10 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: diff --git a/charts/substrabac/templates/daemonset-pull-docker-images.yaml b/charts/substrabac/templates/daemonset-pull-docker-images.yaml index 75369a41c..36fb9cd90 100644 --- a/charts/substrabac/templates/daemonset-pull-docker-images.yaml +++ b/charts/substrabac/templates/daemonset-pull-docker-images.yaml @@ -1,4 +1,4 @@ -{{- if .Values.docker.pullImages }}} +{{- if .Values.docker.pullImages }} {{- if .Values.docker.config }} --- apiVersion: v1 From 90f968d85291459fd17145c91e66df0646bc1a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Tue, 8 Oct 2019 16:00:47 +0200 Subject: [PATCH 357/457] update populate with new sdk errors --- populate.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/populate.py b/populate.py index 018c8f939..e6d5ea845 100644 --- a/populate.py +++ b/populate.py @@ -5,11 +5,15 @@ import tempfile import time import zipfile +import logging import substra from termcolor import colored +logging.basicConfig(filename='populate.log', + format='[%(asctime)-15s: %(levelname)s] %(message)s') + dir_path = os.path.dirname(os.path.realpath(__file__)) USER, PASSWORD = ('admin', 'admin') @@ -65,8 +69,7 @@ def get_or_create(data, profile, asset, local=True): r = method(data, **method_kwargs) except substra.exceptions.AlreadyExists as e: - r = e.response.json() - print(colored(json.dumps(r, indent=2), 'cyan')) + print(colored(e, 'cyan')) key_or_keys = e.pkhash else: @@ -83,10 +86,6 @@ def update_datamanager(data_manager_key, data, profile): try: r = client.update_dataset(data_manager_key, data) - except substra.exceptions.AlreadyExists as e: - r = e.response.json() - print(colored(json.dumps(r, indent=2), 'cyan')) - except substra.exceptions.InvalidRequest as e: # FIXME if the data manager is already associated with the objective # backend answer with a 400 and a raw error coming from the From dea18e07cb93e63f12a4d70cf8c94650ef008387 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 10 Oct 2019 13:52:25 +0200 Subject: [PATCH 358/457] Add RpcError retry on ledger call --- substrabac/substrapp/ledger_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrabac/substrapp/ledger_utils.py b/substrabac/substrapp/ledger_utils.py index bb5a61bdb..21711f1fd 100644 --- a/substrabac/substrapp/ledger_utils.py +++ b/substrabac/substrapp/ledger_utils.py @@ -6,6 +6,7 @@ from django.conf import settings from rest_framework import status +from aiogrpc import RpcError LEDGER = getattr(settings, 'LEDGER', None) @@ -95,7 +96,7 @@ def _wrapper(*args, **kwargs): while True: try: return fn(*args, **kwargs) - except (LedgerMVCCError, LedgerTimeout, LedgerBadResponse) as e: + except (LedgerMVCCError, LedgerTimeout, LedgerBadResponse, RpcError) as e: _nbtries -= 1 if not nbtries: From 0806accaca4fbdd3f7e9837780d68b7f8765996f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Fri, 11 Oct 2019 09:48:49 +0200 Subject: [PATCH 359/457] 401 and 403 response statuses for download calls (#378) * proper 401/403 responses for download calls * do not handle anonymous users (cannot happen) --- .../substrapp/tests/views/tests_utils.py | 19 ++++++++++++------- substrabac/substrapp/views/utils.py | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/substrabac/substrapp/tests/views/tests_utils.py b/substrabac/substrapp/tests/views/tests_utils.py index d6dda138f..b4d265641 100644 --- a/substrabac/substrapp/tests/views/tests_utils.py +++ b/substrabac/substrapp/tests/views/tests_utils.py @@ -15,7 +15,7 @@ class MockRequest: user = None -def with_permission_mixin(remote, same_file_property): +def with_permission_mixin(remote, same_file_property, has_access): def inner(f): @functools.wraps(f) def wrapper(self): @@ -42,7 +42,7 @@ class TestModel: permission_mixin = PermissionMixin() permission_mixin.get_object = mock.MagicMock(return_value=TestModel()) - permission_mixin._has_access = mock.MagicMock(return_value=True) + permission_mixin._has_access = mock.MagicMock(return_value=has_access) permission_mixin.lookup_url_kwarg = 'foo' permission_mixin.kwargs = {'foo': 'bar'} permission_mixin.ledger_query_call = 'foo' @@ -85,8 +85,8 @@ def wrapper(*args, **kwargs): class PermissionMixinDownloadFileTests(APITestCase): - @with_permission_mixin(remote=False, same_file_property=False) - def test_download_file_local(self, permission_mixin, content, filename, **kwargs): + @with_permission_mixin(remote=False, same_file_property=False, has_access=True) + def test_download_file_local_allowed(self, permission_mixin, content, filename, **kwargs): res = permission_mixin.download_file(MockRequest(), 'file_property', 'ledger_file_property') @@ -95,7 +95,12 @@ def test_download_file_local(self, permission_mixin, content, filename, **kwargs self.assertEqual(res['Content-Disposition'], f'attachment; filename="{filename}"') self.assertTrue(permission_mixin.get_object.called) - @with_permission_mixin(remote=True, same_file_property=False) + @with_permission_mixin(remote=False, same_file_property=True, has_access=False) + def test_download_file_local_denied(self, permission_mixin, **kwargs): + res = permission_mixin.download_file(MockRequest(), 'file_property') + self.assertEqual(res.status_code, status.HTTP_403_FORBIDDEN) + + @with_permission_mixin(remote=True, same_file_property=False, has_access=True) @with_requests_mock(allowed=True) def test_download_file_remote_allowed(self, permission_mixin, content, filename, **kwargs): res = permission_mixin.download_file(MockRequest(), @@ -106,7 +111,7 @@ def test_download_file_remote_allowed(self, permission_mixin, content, filename, self.assertEqual(res['Content-Disposition'], f'attachment; filename="{filename}"') self.assertFalse(permission_mixin.get_object.called) - @with_permission_mixin(remote=True, same_file_property=False) + @with_permission_mixin(remote=True, same_file_property=False, has_access=True) @with_requests_mock(allowed=False) def test_download_file_remote_denied(self, permission_mixin, **kwargs): res = permission_mixin.download_file(MockRequest(), @@ -115,7 +120,7 @@ def test_download_file_remote_denied(self, permission_mixin, **kwargs): self.assertEqual(res.status_code, status.HTTP_401_UNAUTHORIZED) self.assertFalse(permission_mixin.get_object.called) - @with_permission_mixin(remote=True, same_file_property=True) + @with_permission_mixin(remote=True, same_file_property=True, has_access=True) @with_requests_mock(allowed=True) def test_download_file_remote_same_file_property(self, permission_mixin, content, filename, **kwargs): diff --git a/substrabac/substrapp/views/utils.py b/substrabac/substrapp/views/utils.py index 26ad20977..69c54f1d6 100644 --- a/substrabac/substrapp/views/utils.py +++ b/substrabac/substrapp/views/utils.py @@ -130,7 +130,7 @@ def download_file(self, request, django_field, ledger_field=None): if not self._has_access(request.user, asset): return Response({'message': 'Unauthorized'}, - status=status.HTTP_401_UNAUTHORIZED) + status=status.HTTP_403_FORBIDDEN) if get_owner() == asset['owner']: obj = self.get_object() From 18124d658144571215dbcd545196cf10b916d8b9 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Tue, 15 Oct 2019 10:31:34 +0200 Subject: [PATCH 360/457] doc: update licence file From 56c0bc52cfc64dd67a8ad1f26ef02d40d27d04ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Wed, 16 Oct 2019 10:32:27 +0200 Subject: [PATCH 361/457] fix sdk exception handling in populate --- populate.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/populate.py b/populate.py index e6d5ea845..5944c4272 100644 --- a/populate.py +++ b/populate.py @@ -428,12 +428,5 @@ def do_populate(): try: do_populate() except substra.exceptions.HTTPError as e: - try: - error = e.response.json() - except Exception: - error_message = e.response.text - else: - error_message = json.dumps(error, indent=2) print(colored(str(e), 'red')) - print(colored(error_message, 'red')) exit(1) From 5afa5434fe31a460e57a1c89d0ae4d20432984f8 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 17 Oct 2019 15:04:12 +0200 Subject: [PATCH 362/457] Add skaffold file --- skaffold.yaml | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 skaffold.yaml diff --git a/skaffold.yaml b/skaffold.yaml new file mode 100644 index 000000000..d51c2481b --- /dev/null +++ b/skaffold.yaml @@ -0,0 +1,140 @@ +apiVersion: skaffold/v1beta13 +kind: Config +build: + tagPolicy: + envTemplate: + template: "{{ .IMAGE_NAME}}:latest" + + artifacts: + - image: eu.gcr.io/substra-208412/substra-backend + context: . + docker: + dockerfile: docker/substrabac/Dockerfile + + - image: eu.gcr.io/substra-208412/celerybeat + context: . + docker: + dockerfile: docker/celerybeat/Dockerfile + + - image: eu.gcr.io/substra-208412/celeryworker + context: . + docker: + dockerfile: docker/celeryworker/Dockerfile + + - image: eu.gcr.io/substra-208412/flower + context: . + docker: + dockerfile: docker/flower/Dockerfile + +deploy: + helm: + releases: + - name: substra-backend-peer-1 + chartPath: charts/substrabac + namespace: peer-1 + imageStrategy: + helm: {} + values: + backend.image: eu.gcr.io/substra-208412/substra-backend + celerybeat.image: eu.gcr.io/substra-208412/celerybeat + celeryworker.image: eu.gcr.io/substra-208412/celeryworker + flower.image: eu.gcr.io/substra-208412/flower + overrides: + secrets: + fabricConfigmap: network-peer-1-hlf-k8s-fabric + backend: + image: + tag: latest + settings: dev + defaultDomain: http://substrabac.node-1 + ingress: + enabled: true + hosts: + - { host: substrabac.node-1, paths: ["/"] } + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/client-body-buffer-size: 100m + nginx.ingress.kubernetes.io/proxy-body-size: 100m + auth: + user: node-1 + password: node-1pwd + header: "Basic bm9kZS0xOm5vZGUtMXB3ZA==" + celerybeat: + image: + tag: latest + celeryworker: + image: + tag: latest + organization: + name: MyPeer1 + peer: + host: network-peer-1.peer-1 + port: 7051 + mspID: MyPeer1MSP + orderer: + host: network-orderer.orderer + port: 7050 + name: MyOrderer + persistence: + hostPath: /tmp/peer-1 + incomingNodes: + - { name: MyPeer1MSP, secret: selfSecret1 } + - { name: MyPeer2MSP, secret: nodeSecret2 } + outgoingNodes: + - { name: MyPeer1MSP, secret: selfSecret1 } + - { name: MyPeer2MSP, secret: nodeSecret1 } + + - name: substra-backend-peer-2 + chartPath: charts/substrabac + namespace: peer-2 + imageStrategy: + helm: {} + values: + backend.image: eu.gcr.io/substra-208412/substra-backend + celerybeat.image: eu.gcr.io/substra-208412/celerybeat + celeryworker.image: eu.gcr.io/substra-208412/celeryworker + flower.image: eu.gcr.io/substra-208412/flower + overrides: + secrets: + fabricConfigmap: network-peer-2-hlf-k8s-fabric + backend: + image: + tag: latest + settings: dev + defaultDomain: http://substrabac.node-2 + ingress: + enabled: true + hosts: + - { host: substrabac.node-2, paths: ["/"] } + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/client-body-buffer-size: 100m + nginx.ingress.kubernetes.io/proxy-body-size: 100m + auth: + user: node-2 + password: node-2pwd + header: "Basic bm9kZS0yOm5vZGUtMnB3ZA==" + celerybeat: + image: + tag: latest + celeryworker: + image: + tag: latest + organization: + name: MyPeer1 + peer: + host: network-peer-2.peer-2 + port: 7051 + mspID: MyPeer2MSP + orderer: + host: network-orderer.orderer + port: 7050 + name: MyOrderer + persistence: + hostPath: /tmp/peer-2 + incomingNodes: + - { name: MyPeer1MSP, secret: nodeSecret1 } + - { name: MyPeer2MSP, secret: selfSecret2 } + outgoingNodes: + - { name: MyPeer1MSP, secret: nodeSecret2 } + - { name: MyPeer2MSP, secret: selfSecret2 } From 7701a80a7abbe17c2ae8dc82252ef01d02a793fc Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Thu, 17 Oct 2019 14:21:30 +0200 Subject: [PATCH 363/457] Rename substra-network-tools --- charts/substrabac/README.md | 6 +++--- charts/substrabac/values.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/substrabac/README.md b/charts/substrabac/README.md index e0d45f768..374ab50cc 100644 --- a/charts/substrabac/README.md +++ b/charts/substrabac/README.md @@ -6,17 +6,17 @@ Having a Kubernetes cluster working with Helm initialized. You can do thant loca Then simply launch your cluster using `minikube start` and configure helm with `helm init`. You will also need the Hyperledger Fabric network setup on the cluster. -Look at the corresponding chart for that (chart-substra-network-tools) +Look at the corresponding chart for that (chart-hlf-k8s) You will also need a postgresql instance on the cluster, it should already be the case if you install the network first. ## Install the package ``` -helm install --name substra-network-tools owkin/substra-network-tools +helm install --name hlf-k8s owkin/hlf-k8s helm install --name substra owkin/substra ``` ### Cleanup ``` -helm delete --purge substra-network-tools substra +helm delete --purge hlf-k8s substra ``` diff --git a/charts/substrabac/values.yaml b/charts/substrabac/values.yaml index a71045cf6..acbd6109b 100644 --- a/charts/substrabac/values.yaml +++ b/charts/substrabac/values.yaml @@ -106,7 +106,7 @@ secrets: # This will include the organization config json file (peer only) orgConfig: org-config # This will include the organization config json file (peer only) - fabricConfigmap: network-substra-network-tools-fabric + fabricConfigmap: network-hlf-k8s-fabric organization: name: substra From b902ca838444eafb2de41dc0d6f73870616ad3f1 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Fri, 18 Oct 2019 17:26:53 +0200 Subject: [PATCH 364/457] renaming substrabac --- .gitignore | 6 +++--- .../{substrabac => substra-backend}/.gitignore | 0 .../{substrabac => substra-backend}/.helmignore | 0 .../{substrabac => substra-backend}/Chart.yaml | 6 +++--- .../{substrabac => substra-backend}/README.md | 0 .../requirements.lock | 0 .../requirements.yaml | 0 .../templates/_helpers.tpl | 0 .../templates/configmap-backend.yaml | 0 .../templates/daemonset-nvidia-driver-cos.yaml | 0 .../daemonset-nvidia-driver-ubuntu.yaml | 0 .../templates/daemonset-nvidia-plugin.yaml | 0 .../templates/daemonset-pull-docker-images.yaml | 0 .../templates/deployment-backend.yaml | 0 .../templates/deployment-celerybeat.yaml | 0 .../templates/deployment-flower.yaml | 0 .../templates/deployment-scheduler.yaml | 0 .../templates/deployment-worker.yaml | 0 .../templates/ingress-backend.yaml | 0 .../templates/job-add-incoming-nodes.yaml | 0 .../templates/job-add-outgoing-nodes.yaml | 0 .../templates/secret-pull.yaml | 0 .../templates/service-backend.yaml | 0 .../templates/service-flower.yaml | 0 .../templates/storage.yaml | 0 .../{substrabac => substra-backend}/values.yaml | 0 charts/substrabac/charts/postgresql-6.2.1.tgz | Bin 0 -> 22419 bytes charts/substrabac/charts/rabbitmq-6.2.6.tgz | Bin 0 -> 19254 bytes {substrabac => substra-backend}/.coveragerc | 0 .../events/__init__.py | 0 {substrabac => substra-backend}/events/apps.py | 0 .../libs/SQLPrintingMiddleware.py | 0 .../libs/__init__.py | 0 .../libs/authentication.py | 0 .../libs/gen_secret_key.py | 0 .../libs/pagination.py | 0 .../libs/serializers.py | 0 .../libs/timestampModel.py | 0 .../libs/versioning.py | 0 {substrabac => substra-backend}/manage.py | 0 .../node-register/__init__.py | 0 .../node-register/apps.py | 0 .../node/__init__.py | 0 {substrabac => substra-backend}/node/apps.py | 0 .../node/authentication.py | 0 .../node/fixtures/nodes-chunantes.yaml | 0 .../node/fixtures/nodes-clb.yaml | 0 .../node/fixtures/nodes-owkin.yaml | 0 .../management/commands/create_incoming_node.py | 0 .../management/commands/create_outgoing_node.py | 0 .../management/commands/get_incoming_node.py | 0 .../management/commands/get_outgoing_node.py | 0 .../node/migrations/0001_initial.py | 0 .../node/migrations/0002_nodeuser.py | 0 .../node/migrations/__init__.py | 0 {substrabac => substra-backend}/node/models.py | 0 .../node/signals/__init__.py | 0 .../node/signals/node/__init__.py | 0 .../node/signals/node/pre_save.py | 0 .../node/tests/__init__.py | 0 .../node/tests/views/__init__.py | 0 .../node/tests/views/tests_views_node.py | 0 {substrabac => substra-backend}/node/urls.py | 0 .../node/views/__init__.py | 0 .../node/views/node.py | 0 .../requirements.txt | 0 .../substrabackend}/__init__.py | 0 .../substrabackend}/celery.py | 0 .../substrabackend}/settings/__init__.py | 0 .../substrabackend}/settings/common.py | 0 .../substrabackend}/settings/deps/__init__.py | 0 .../substrabackend}/settings/deps/cors.py | 0 .../substrabackend}/settings/deps/ledger.py | 0 .../substrabackend}/settings/deps/org.py | 0 .../substrabackend}/settings/deps/raven.py | 0 .../settings/deps/restframework.py | 0 .../substrabackend}/settings/dev.py | 0 .../substrabackend}/settings/prod.py | 0 .../substrabackend}/settings/server/__init__.py | 0 .../substrabackend}/settings/server/dev.py | 0 .../settings/server/nobasicauth/__init__.py | 0 .../settings/server/nobasicauth/dev.py | 0 .../settings/server/nobasicauth/prod.py | 0 .../substrabackend}/settings/server/prod.py | 0 .../substrabackend}/settings/test.py | 0 .../substrabackend}/urls.py | 0 .../substrabackend}/views.py | 0 .../substrabackend}/wsgi.py | 4 ++-- .../substrapp/__init__.py | 0 .../substrapp/admin.py | 0 .../substrapp/apps.py | 0 .../substrapp/ledger_utils.py | 0 .../management/commands/bulkcreatedatasample.py | 0 .../management/commands/createdataset.py | 0 .../management/commands/createobjective.py | 0 .../tests/tests_bulkcreatedatasample.py | 4 ++-- .../management/tests/tests_createdatamanager.py | 0 .../management/tests/tests_createobjective.py | 0 .../substrapp/management/utils/__init__.py | 0 .../substrapp/management/utils/localRequest.py | 0 .../substrapp/migrations/0001_initial.py | 0 .../substrapp/migrations/__init__.py | 0 .../substrapp/models/__init__.py | 0 .../substrapp/models/algo.py | 0 .../substrapp/models/datamanager.py | 0 .../substrapp/models/datasample.py | 0 .../substrapp/models/model.py | 0 .../substrapp/models/objective.py | 0 .../substrapp/serializers/__init__.py | 0 .../substrapp/serializers/algo.py | 0 .../substrapp/serializers/datamanager.py | 0 .../substrapp/serializers/datasample.py | 0 .../substrapp/serializers/ledger/__init__.py | 0 .../serializers/ledger/algo/__init__.py | 0 .../serializers/ledger/algo/serializer.py | 0 .../substrapp/serializers/ledger/algo/tasks.py | 0 .../substrapp/serializers/ledger/algo/util.py | 0 .../serializers/ledger/computeplan/__init__.py | 0 .../ledger/computeplan/serializer.py | 0 .../serializers/ledger/computeplan/tasks.py | 0 .../serializers/ledger/computeplan/util.py | 0 .../serializers/ledger/datamanager/__init__.py | 0 .../ledger/datamanager/serializer.py | 0 .../serializers/ledger/datamanager/tasks.py | 0 .../serializers/ledger/datamanager/util.py | 0 .../serializers/ledger/datasample/__init__.py | 0 .../serializers/ledger/datasample/serializer.py | 0 .../serializers/ledger/datasample/tasks.py | 0 .../serializers/ledger/datasample/util.py | 0 .../serializers/ledger/model/__init__.py | 0 .../serializers/ledger/model/serializer.py | 0 .../serializers/ledger/objective/__init__.py | 0 .../serializers/ledger/objective/serializer.py | 0 .../serializers/ledger/objective/tasks.py | 0 .../serializers/ledger/objective/util.py | 0 .../serializers/ledger/testtuple/__init__.py | 0 .../serializers/ledger/testtuple/serializer.py | 0 .../serializers/ledger/testtuple/tasks.py | 0 .../serializers/ledger/testtuple/util.py | 0 .../serializers/ledger/traintuple/__init__.py | 0 .../serializers/ledger/traintuple/serializer.py | 0 .../serializers/ledger/traintuple/tasks.py | 0 .../serializers/ledger/traintuple/util.py | 0 .../substrapp/serializers/ledger/utils.py | 0 .../substrapp/serializers/model.py | 0 .../substrapp/serializers/objective.py | 0 .../substrapp/serializers/utils.py | 0 .../substrapp/signals/__init__.py | 0 .../substrapp/signals/algo/__init__.py | 0 .../substrapp/signals/algo/post_delete.py | 0 .../substrapp/signals/datamanager/__init__.py | 0 .../signals/datamanager/post_delete.py | 0 .../substrapp/signals/datasample/__init__.py | 0 .../substrapp/signals/datasample/post_delete.py | 0 .../substrapp/signals/datasample/pre_save.py | 0 .../substrapp/signals/model/__init__.py | 0 .../substrapp/signals/model/post_delete.py | 0 .../substrapp/signals/objective/__init__.py | 0 .../substrapp/signals/objective/post_delete.py | 0 .../substrapp/tasks/__init__.py | 0 .../substrapp/tasks/exception_handler.py | 4 ++-- .../substrapp/tasks/exceptions.json | 0 .../substrapp/tasks/tasks.py | 4 ++-- .../substrapp/tasks/utils.py | 2 +- .../substrapp/tests/__init__.py | 0 .../substrapp/tests/assets.py | 0 .../substrapp/tests/common.py | 0 .../substrapp/tests/generate_assets.py | 6 +++--- .../substrapp/tests/query/__init__.py | 0 .../substrapp/tests/query/tests_query_algo.py | 0 .../tests/query/tests_query_datamanager.py | 0 .../tests/query/tests_query_datasample.py | 2 +- .../tests/query/tests_query_objective.py | 0 .../substrapp/tests/query/tests_query_tuples.py | 0 .../substrapp/tests/tests_exception.py | 0 .../substrapp/tests/tests_misc.py | 0 .../substrapp/tests/tests_model.py | 0 .../substrapp/tests/tests_tasks.py | 0 .../substrapp/tests/views/__init__.py | 0 .../tests/views/test_views_authentication.py | 0 .../substrapp/tests/views/tests_utils.py | 0 .../substrapp/tests/views/tests_views.py | 0 .../substrapp/tests/views/tests_views_algo.py | 0 .../tests/views/tests_views_computeplan.py | 0 .../tests/views/tests_views_datamanager.py | 0 .../tests/views/tests_views_datasample.py | 0 .../substrapp/tests/views/tests_views_model.py | 0 .../tests/views/tests_views_objective.py | 0 .../substrapp/tests/views/tests_views_task.py | 0 .../substrapp/tests/views/tests_views_tuples.py | 0 .../substrapp/urls.py | 0 .../substrapp/utils.py | 0 .../substrapp/views/__init__.py | 0 .../substrapp/views/algo.py | 0 .../substrapp/views/computeplan.py | 0 .../substrapp/views/datamanager.py | 0 .../substrapp/views/datasample.py | 2 +- .../substrapp/views/filters_utils.py | 0 .../substrapp/views/model.py | 0 .../substrapp/views/objective.py | 0 .../substrapp/views/task.py | 0 .../substrapp/views/testtuple.py | 0 .../substrapp/views/traintuple.py | 0 .../substrapp/views/utils.py | 0 204 files changed, 20 insertions(+), 20 deletions(-) rename charts/{substrabac => substra-backend}/.gitignore (100%) rename charts/{substrabac => substra-backend}/.helmignore (100%) rename charts/{substrabac => substra-backend}/Chart.yaml (67%) rename charts/{substrabac => substra-backend}/README.md (100%) rename charts/{substrabac => substra-backend}/requirements.lock (100%) rename charts/{substrabac => substra-backend}/requirements.yaml (100%) rename charts/{substrabac => substra-backend}/templates/_helpers.tpl (100%) rename charts/{substrabac => substra-backend}/templates/configmap-backend.yaml (100%) rename charts/{substrabac => substra-backend}/templates/daemonset-nvidia-driver-cos.yaml (100%) rename charts/{substrabac => substra-backend}/templates/daemonset-nvidia-driver-ubuntu.yaml (100%) rename charts/{substrabac => substra-backend}/templates/daemonset-nvidia-plugin.yaml (100%) rename charts/{substrabac => substra-backend}/templates/daemonset-pull-docker-images.yaml (100%) rename charts/{substrabac => substra-backend}/templates/deployment-backend.yaml (100%) rename charts/{substrabac => substra-backend}/templates/deployment-celerybeat.yaml (100%) rename charts/{substrabac => substra-backend}/templates/deployment-flower.yaml (100%) rename charts/{substrabac => substra-backend}/templates/deployment-scheduler.yaml (100%) rename charts/{substrabac => substra-backend}/templates/deployment-worker.yaml (100%) rename charts/{substrabac => substra-backend}/templates/ingress-backend.yaml (100%) rename charts/{substrabac => substra-backend}/templates/job-add-incoming-nodes.yaml (100%) rename charts/{substrabac => substra-backend}/templates/job-add-outgoing-nodes.yaml (100%) rename charts/{substrabac => substra-backend}/templates/secret-pull.yaml (100%) rename charts/{substrabac => substra-backend}/templates/service-backend.yaml (100%) rename charts/{substrabac => substra-backend}/templates/service-flower.yaml (100%) rename charts/{substrabac => substra-backend}/templates/storage.yaml (100%) rename charts/{substrabac => substra-backend}/values.yaml (100%) create mode 100644 charts/substrabac/charts/postgresql-6.2.1.tgz create mode 100644 charts/substrabac/charts/rabbitmq-6.2.6.tgz rename {substrabac => substra-backend}/.coveragerc (100%) rename {substrabac => substra-backend}/events/__init__.py (100%) rename {substrabac => substra-backend}/events/apps.py (100%) rename {substrabac => substra-backend}/libs/SQLPrintingMiddleware.py (100%) rename {substrabac => substra-backend}/libs/__init__.py (100%) rename {substrabac => substra-backend}/libs/authentication.py (100%) rename {substrabac => substra-backend}/libs/gen_secret_key.py (100%) rename {substrabac => substra-backend}/libs/pagination.py (100%) rename {substrabac => substra-backend}/libs/serializers.py (100%) rename {substrabac => substra-backend}/libs/timestampModel.py (100%) rename {substrabac => substra-backend}/libs/versioning.py (100%) rename {substrabac => substra-backend}/manage.py (100%) rename {substrabac => substra-backend}/node-register/__init__.py (100%) rename {substrabac => substra-backend}/node-register/apps.py (100%) rename {substrabac => substra-backend}/node/__init__.py (100%) rename {substrabac => substra-backend}/node/apps.py (100%) rename {substrabac => substra-backend}/node/authentication.py (100%) rename {substrabac => substra-backend}/node/fixtures/nodes-chunantes.yaml (100%) rename {substrabac => substra-backend}/node/fixtures/nodes-clb.yaml (100%) rename {substrabac => substra-backend}/node/fixtures/nodes-owkin.yaml (100%) rename {substrabac => substra-backend}/node/management/commands/create_incoming_node.py (100%) rename {substrabac => substra-backend}/node/management/commands/create_outgoing_node.py (100%) rename {substrabac => substra-backend}/node/management/commands/get_incoming_node.py (100%) rename {substrabac => substra-backend}/node/management/commands/get_outgoing_node.py (100%) rename {substrabac => substra-backend}/node/migrations/0001_initial.py (100%) rename {substrabac => substra-backend}/node/migrations/0002_nodeuser.py (100%) rename {substrabac => substra-backend}/node/migrations/__init__.py (100%) rename {substrabac => substra-backend}/node/models.py (100%) rename {substrabac => substra-backend}/node/signals/__init__.py (100%) rename {substrabac => substra-backend}/node/signals/node/__init__.py (100%) rename {substrabac => substra-backend}/node/signals/node/pre_save.py (100%) rename {substrabac => substra-backend}/node/tests/__init__.py (100%) rename {substrabac => substra-backend}/node/tests/views/__init__.py (100%) rename {substrabac => substra-backend}/node/tests/views/tests_views_node.py (100%) rename {substrabac => substra-backend}/node/urls.py (100%) rename {substrabac => substra-backend}/node/views/__init__.py (100%) rename {substrabac => substra-backend}/node/views/node.py (100%) rename {substrabac => substra-backend}/requirements.txt (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/__init__.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/celery.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/__init__.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/common.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/deps/__init__.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/deps/cors.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/deps/ledger.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/deps/org.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/deps/raven.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/deps/restframework.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/dev.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/prod.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/server/__init__.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/server/dev.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/server/nobasicauth/__init__.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/server/nobasicauth/dev.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/server/nobasicauth/prod.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/server/prod.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/settings/test.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/urls.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/views.py (100%) rename {substrabac/substrabac => substra-backend/substrabackend}/wsgi.py (70%) rename {substrabac => substra-backend}/substrapp/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/admin.py (100%) rename {substrabac => substra-backend}/substrapp/apps.py (100%) rename {substrabac => substra-backend}/substrapp/ledger_utils.py (100%) rename {substrabac => substra-backend}/substrapp/management/commands/bulkcreatedatasample.py (100%) rename {substrabac => substra-backend}/substrapp/management/commands/createdataset.py (100%) rename {substrabac => substra-backend}/substrapp/management/commands/createobjective.py (100%) rename {substrabac => substra-backend}/substrapp/management/tests/tests_bulkcreatedatasample.py (99%) rename {substrabac => substra-backend}/substrapp/management/tests/tests_createdatamanager.py (100%) rename {substrabac => substra-backend}/substrapp/management/tests/tests_createobjective.py (100%) rename {substrabac => substra-backend}/substrapp/management/utils/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/management/utils/localRequest.py (100%) rename {substrabac => substra-backend}/substrapp/migrations/0001_initial.py (100%) rename {substrabac => substra-backend}/substrapp/migrations/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/models/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/models/algo.py (100%) rename {substrabac => substra-backend}/substrapp/models/datamanager.py (100%) rename {substrabac => substra-backend}/substrapp/models/datasample.py (100%) rename {substrabac => substra-backend}/substrapp/models/model.py (100%) rename {substrabac => substra-backend}/substrapp/models/objective.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/algo.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/datamanager.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/datasample.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/algo/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/algo/serializer.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/algo/tasks.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/algo/util.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/computeplan/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/computeplan/serializer.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/computeplan/tasks.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/computeplan/util.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/datamanager/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/datamanager/serializer.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/datamanager/tasks.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/datamanager/util.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/datasample/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/datasample/serializer.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/datasample/tasks.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/datasample/util.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/model/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/model/serializer.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/objective/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/objective/serializer.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/objective/tasks.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/objective/util.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/testtuple/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/testtuple/serializer.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/testtuple/tasks.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/testtuple/util.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/traintuple/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/traintuple/serializer.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/traintuple/tasks.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/traintuple/util.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/ledger/utils.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/model.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/objective.py (100%) rename {substrabac => substra-backend}/substrapp/serializers/utils.py (100%) rename {substrabac => substra-backend}/substrapp/signals/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/signals/algo/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/signals/algo/post_delete.py (100%) rename {substrabac => substra-backend}/substrapp/signals/datamanager/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/signals/datamanager/post_delete.py (100%) rename {substrabac => substra-backend}/substrapp/signals/datasample/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/signals/datasample/post_delete.py (100%) rename {substrabac => substra-backend}/substrapp/signals/datasample/pre_save.py (100%) rename {substrabac => substra-backend}/substrapp/signals/model/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/signals/model/post_delete.py (100%) rename {substrabac => substra-backend}/substrapp/signals/objective/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/signals/objective/post_delete.py (100%) rename {substrabac => substra-backend}/substrapp/tasks/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/tasks/exception_handler.py (96%) rename {substrabac => substra-backend}/substrapp/tasks/exceptions.json (100%) rename {substrabac => substra-backend}/substrapp/tasks/tasks.py (99%) rename {substrabac => substra-backend}/substrapp/tasks/utils.py (99%) rename {substrabac => substra-backend}/substrapp/tests/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/tests/assets.py (100%) rename {substrabac => substra-backend}/substrapp/tests/common.py (100%) rename {substrabac => substra-backend}/substrapp/tests/generate_assets.py (86%) rename {substrabac => substra-backend}/substrapp/tests/query/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/tests/query/tests_query_algo.py (100%) rename {substrabac => substra-backend}/substrapp/tests/query/tests_query_datamanager.py (100%) rename {substrabac => substra-backend}/substrapp/tests/query/tests_query_datasample.py (99%) rename {substrabac => substra-backend}/substrapp/tests/query/tests_query_objective.py (100%) rename {substrabac => substra-backend}/substrapp/tests/query/tests_query_tuples.py (100%) rename {substrabac => substra-backend}/substrapp/tests/tests_exception.py (100%) rename {substrabac => substra-backend}/substrapp/tests/tests_misc.py (100%) rename {substrabac => substra-backend}/substrapp/tests/tests_model.py (100%) rename {substrabac => substra-backend}/substrapp/tests/tests_tasks.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/test_views_authentication.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_utils.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views_algo.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views_computeplan.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views_datamanager.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views_datasample.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views_model.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views_objective.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views_task.py (100%) rename {substrabac => substra-backend}/substrapp/tests/views/tests_views_tuples.py (100%) rename {substrabac => substra-backend}/substrapp/urls.py (100%) rename {substrabac => substra-backend}/substrapp/utils.py (100%) rename {substrabac => substra-backend}/substrapp/views/__init__.py (100%) rename {substrabac => substra-backend}/substrapp/views/algo.py (100%) rename {substrabac => substra-backend}/substrapp/views/computeplan.py (100%) rename {substrabac => substra-backend}/substrapp/views/datamanager.py (100%) rename {substrabac => substra-backend}/substrapp/views/datasample.py (99%) rename {substrabac => substra-backend}/substrapp/views/filters_utils.py (100%) rename {substrabac => substra-backend}/substrapp/views/model.py (100%) rename {substrabac => substra-backend}/substrapp/views/objective.py (100%) rename {substrabac => substra-backend}/substrapp/views/task.py (100%) rename {substrabac => substra-backend}/substrapp/views/testtuple.py (100%) rename {substrabac => substra-backend}/substrapp/views/traintuple.py (100%) rename {substrabac => substra-backend}/substrapp/views/utils.py (100%) diff --git a/.gitignore b/.gitignore index acabfcdf1..497aa5f05 100644 --- a/.gitignore +++ b/.gitignore @@ -110,7 +110,7 @@ venv.bak/ SECRET # conf from substra-network -substrabac/substrapp/**/conf +substra-backend/substrapp/**/conf **/medias/* @@ -119,8 +119,8 @@ bin # test files -substrabac/substrabac/description.md -substrabac/substrabac/metrics.py +substra-backend/substra-backend/description.md +substra-backend/substra-backend/metrics.py # docker database dir postgres-data diff --git a/charts/substrabac/.gitignore b/charts/substra-backend/.gitignore similarity index 100% rename from charts/substrabac/.gitignore rename to charts/substra-backend/.gitignore diff --git a/charts/substrabac/.helmignore b/charts/substra-backend/.helmignore similarity index 100% rename from charts/substrabac/.helmignore rename to charts/substra-backend/.helmignore diff --git a/charts/substrabac/Chart.yaml b/charts/substra-backend/Chart.yaml similarity index 67% rename from charts/substrabac/Chart.yaml rename to charts/substra-backend/Chart.yaml index d9a43b7bc..62d670958 100644 --- a/charts/substrabac/Chart.yaml +++ b/charts/substra-backend/Chart.yaml @@ -1,10 +1,10 @@ -name: substrabac +name: substra-backend home: https://substra.org/ -version: 1.0.0-alpha.10 +version: 1.0.0-alpha.11 description: Main package for Substra icon: https://avatars1.githubusercontent.com/u/38098422?s=200&v=4 sources: - - https://github.com/SubstraFoudation/substrabac + - https://github.com/SubstraFoudation/substra-backend maintainers: - name: ClementGautier email: clement@gautier.im diff --git a/charts/substrabac/README.md b/charts/substra-backend/README.md similarity index 100% rename from charts/substrabac/README.md rename to charts/substra-backend/README.md diff --git a/charts/substrabac/requirements.lock b/charts/substra-backend/requirements.lock similarity index 100% rename from charts/substrabac/requirements.lock rename to charts/substra-backend/requirements.lock diff --git a/charts/substrabac/requirements.yaml b/charts/substra-backend/requirements.yaml similarity index 100% rename from charts/substrabac/requirements.yaml rename to charts/substra-backend/requirements.yaml diff --git a/charts/substrabac/templates/_helpers.tpl b/charts/substra-backend/templates/_helpers.tpl similarity index 100% rename from charts/substrabac/templates/_helpers.tpl rename to charts/substra-backend/templates/_helpers.tpl diff --git a/charts/substrabac/templates/configmap-backend.yaml b/charts/substra-backend/templates/configmap-backend.yaml similarity index 100% rename from charts/substrabac/templates/configmap-backend.yaml rename to charts/substra-backend/templates/configmap-backend.yaml diff --git a/charts/substrabac/templates/daemonset-nvidia-driver-cos.yaml b/charts/substra-backend/templates/daemonset-nvidia-driver-cos.yaml similarity index 100% rename from charts/substrabac/templates/daemonset-nvidia-driver-cos.yaml rename to charts/substra-backend/templates/daemonset-nvidia-driver-cos.yaml diff --git a/charts/substrabac/templates/daemonset-nvidia-driver-ubuntu.yaml b/charts/substra-backend/templates/daemonset-nvidia-driver-ubuntu.yaml similarity index 100% rename from charts/substrabac/templates/daemonset-nvidia-driver-ubuntu.yaml rename to charts/substra-backend/templates/daemonset-nvidia-driver-ubuntu.yaml diff --git a/charts/substrabac/templates/daemonset-nvidia-plugin.yaml b/charts/substra-backend/templates/daemonset-nvidia-plugin.yaml similarity index 100% rename from charts/substrabac/templates/daemonset-nvidia-plugin.yaml rename to charts/substra-backend/templates/daemonset-nvidia-plugin.yaml diff --git a/charts/substrabac/templates/daemonset-pull-docker-images.yaml b/charts/substra-backend/templates/daemonset-pull-docker-images.yaml similarity index 100% rename from charts/substrabac/templates/daemonset-pull-docker-images.yaml rename to charts/substra-backend/templates/daemonset-pull-docker-images.yaml diff --git a/charts/substrabac/templates/deployment-backend.yaml b/charts/substra-backend/templates/deployment-backend.yaml similarity index 100% rename from charts/substrabac/templates/deployment-backend.yaml rename to charts/substra-backend/templates/deployment-backend.yaml diff --git a/charts/substrabac/templates/deployment-celerybeat.yaml b/charts/substra-backend/templates/deployment-celerybeat.yaml similarity index 100% rename from charts/substrabac/templates/deployment-celerybeat.yaml rename to charts/substra-backend/templates/deployment-celerybeat.yaml diff --git a/charts/substrabac/templates/deployment-flower.yaml b/charts/substra-backend/templates/deployment-flower.yaml similarity index 100% rename from charts/substrabac/templates/deployment-flower.yaml rename to charts/substra-backend/templates/deployment-flower.yaml diff --git a/charts/substrabac/templates/deployment-scheduler.yaml b/charts/substra-backend/templates/deployment-scheduler.yaml similarity index 100% rename from charts/substrabac/templates/deployment-scheduler.yaml rename to charts/substra-backend/templates/deployment-scheduler.yaml diff --git a/charts/substrabac/templates/deployment-worker.yaml b/charts/substra-backend/templates/deployment-worker.yaml similarity index 100% rename from charts/substrabac/templates/deployment-worker.yaml rename to charts/substra-backend/templates/deployment-worker.yaml diff --git a/charts/substrabac/templates/ingress-backend.yaml b/charts/substra-backend/templates/ingress-backend.yaml similarity index 100% rename from charts/substrabac/templates/ingress-backend.yaml rename to charts/substra-backend/templates/ingress-backend.yaml diff --git a/charts/substrabac/templates/job-add-incoming-nodes.yaml b/charts/substra-backend/templates/job-add-incoming-nodes.yaml similarity index 100% rename from charts/substrabac/templates/job-add-incoming-nodes.yaml rename to charts/substra-backend/templates/job-add-incoming-nodes.yaml diff --git a/charts/substrabac/templates/job-add-outgoing-nodes.yaml b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml similarity index 100% rename from charts/substrabac/templates/job-add-outgoing-nodes.yaml rename to charts/substra-backend/templates/job-add-outgoing-nodes.yaml diff --git a/charts/substrabac/templates/secret-pull.yaml b/charts/substra-backend/templates/secret-pull.yaml similarity index 100% rename from charts/substrabac/templates/secret-pull.yaml rename to charts/substra-backend/templates/secret-pull.yaml diff --git a/charts/substrabac/templates/service-backend.yaml b/charts/substra-backend/templates/service-backend.yaml similarity index 100% rename from charts/substrabac/templates/service-backend.yaml rename to charts/substra-backend/templates/service-backend.yaml diff --git a/charts/substrabac/templates/service-flower.yaml b/charts/substra-backend/templates/service-flower.yaml similarity index 100% rename from charts/substrabac/templates/service-flower.yaml rename to charts/substra-backend/templates/service-flower.yaml diff --git a/charts/substrabac/templates/storage.yaml b/charts/substra-backend/templates/storage.yaml similarity index 100% rename from charts/substrabac/templates/storage.yaml rename to charts/substra-backend/templates/storage.yaml diff --git a/charts/substrabac/values.yaml b/charts/substra-backend/values.yaml similarity index 100% rename from charts/substrabac/values.yaml rename to charts/substra-backend/values.yaml diff --git a/charts/substrabac/charts/postgresql-6.2.1.tgz b/charts/substrabac/charts/postgresql-6.2.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..15d7581f09db4b7c535cd716c03da0410e1f1d78 GIT binary patch literal 22419 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,A=stmY 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

      $3HcJ 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

      v6OsBfzj;*X1@*Y6ItUqbUze;5Phn^Px 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 literal 0 HcmV?d00001 diff --git a/substrabac/.coveragerc b/substra-backend/.coveragerc similarity index 100% rename from substrabac/.coveragerc rename to substra-backend/.coveragerc diff --git a/substrabac/events/__init__.py b/substra-backend/events/__init__.py similarity index 100% rename from substrabac/events/__init__.py rename to substra-backend/events/__init__.py diff --git a/substrabac/events/apps.py b/substra-backend/events/apps.py similarity index 100% rename from substrabac/events/apps.py rename to substra-backend/events/apps.py diff --git a/substrabac/libs/SQLPrintingMiddleware.py b/substra-backend/libs/SQLPrintingMiddleware.py similarity index 100% rename from substrabac/libs/SQLPrintingMiddleware.py rename to substra-backend/libs/SQLPrintingMiddleware.py diff --git a/substrabac/libs/__init__.py b/substra-backend/libs/__init__.py similarity index 100% rename from substrabac/libs/__init__.py rename to substra-backend/libs/__init__.py diff --git a/substrabac/libs/authentication.py b/substra-backend/libs/authentication.py similarity index 100% rename from substrabac/libs/authentication.py rename to substra-backend/libs/authentication.py diff --git a/substrabac/libs/gen_secret_key.py b/substra-backend/libs/gen_secret_key.py similarity index 100% rename from substrabac/libs/gen_secret_key.py rename to substra-backend/libs/gen_secret_key.py diff --git a/substrabac/libs/pagination.py b/substra-backend/libs/pagination.py similarity index 100% rename from substrabac/libs/pagination.py rename to substra-backend/libs/pagination.py diff --git a/substrabac/libs/serializers.py b/substra-backend/libs/serializers.py similarity index 100% rename from substrabac/libs/serializers.py rename to substra-backend/libs/serializers.py diff --git a/substrabac/libs/timestampModel.py b/substra-backend/libs/timestampModel.py similarity index 100% rename from substrabac/libs/timestampModel.py rename to substra-backend/libs/timestampModel.py diff --git a/substrabac/libs/versioning.py b/substra-backend/libs/versioning.py similarity index 100% rename from substrabac/libs/versioning.py rename to substra-backend/libs/versioning.py diff --git a/substrabac/manage.py b/substra-backend/manage.py similarity index 100% rename from substrabac/manage.py rename to substra-backend/manage.py diff --git a/substrabac/node-register/__init__.py b/substra-backend/node-register/__init__.py similarity index 100% rename from substrabac/node-register/__init__.py rename to substra-backend/node-register/__init__.py diff --git a/substrabac/node-register/apps.py b/substra-backend/node-register/apps.py similarity index 100% rename from substrabac/node-register/apps.py rename to substra-backend/node-register/apps.py diff --git a/substrabac/node/__init__.py b/substra-backend/node/__init__.py similarity index 100% rename from substrabac/node/__init__.py rename to substra-backend/node/__init__.py diff --git a/substrabac/node/apps.py b/substra-backend/node/apps.py similarity index 100% rename from substrabac/node/apps.py rename to substra-backend/node/apps.py diff --git a/substrabac/node/authentication.py b/substra-backend/node/authentication.py similarity index 100% rename from substrabac/node/authentication.py rename to substra-backend/node/authentication.py diff --git a/substrabac/node/fixtures/nodes-chunantes.yaml b/substra-backend/node/fixtures/nodes-chunantes.yaml similarity index 100% rename from substrabac/node/fixtures/nodes-chunantes.yaml rename to substra-backend/node/fixtures/nodes-chunantes.yaml diff --git a/substrabac/node/fixtures/nodes-clb.yaml b/substra-backend/node/fixtures/nodes-clb.yaml similarity index 100% rename from substrabac/node/fixtures/nodes-clb.yaml rename to substra-backend/node/fixtures/nodes-clb.yaml diff --git a/substrabac/node/fixtures/nodes-owkin.yaml b/substra-backend/node/fixtures/nodes-owkin.yaml similarity index 100% rename from substrabac/node/fixtures/nodes-owkin.yaml rename to substra-backend/node/fixtures/nodes-owkin.yaml diff --git a/substrabac/node/management/commands/create_incoming_node.py b/substra-backend/node/management/commands/create_incoming_node.py similarity index 100% rename from substrabac/node/management/commands/create_incoming_node.py rename to substra-backend/node/management/commands/create_incoming_node.py diff --git a/substrabac/node/management/commands/create_outgoing_node.py b/substra-backend/node/management/commands/create_outgoing_node.py similarity index 100% rename from substrabac/node/management/commands/create_outgoing_node.py rename to substra-backend/node/management/commands/create_outgoing_node.py diff --git a/substrabac/node/management/commands/get_incoming_node.py b/substra-backend/node/management/commands/get_incoming_node.py similarity index 100% rename from substrabac/node/management/commands/get_incoming_node.py rename to substra-backend/node/management/commands/get_incoming_node.py diff --git a/substrabac/node/management/commands/get_outgoing_node.py b/substra-backend/node/management/commands/get_outgoing_node.py similarity index 100% rename from substrabac/node/management/commands/get_outgoing_node.py rename to substra-backend/node/management/commands/get_outgoing_node.py diff --git a/substrabac/node/migrations/0001_initial.py b/substra-backend/node/migrations/0001_initial.py similarity index 100% rename from substrabac/node/migrations/0001_initial.py rename to substra-backend/node/migrations/0001_initial.py diff --git a/substrabac/node/migrations/0002_nodeuser.py b/substra-backend/node/migrations/0002_nodeuser.py similarity index 100% rename from substrabac/node/migrations/0002_nodeuser.py rename to substra-backend/node/migrations/0002_nodeuser.py diff --git a/substrabac/node/migrations/__init__.py b/substra-backend/node/migrations/__init__.py similarity index 100% rename from substrabac/node/migrations/__init__.py rename to substra-backend/node/migrations/__init__.py diff --git a/substrabac/node/models.py b/substra-backend/node/models.py similarity index 100% rename from substrabac/node/models.py rename to substra-backend/node/models.py diff --git a/substrabac/node/signals/__init__.py b/substra-backend/node/signals/__init__.py similarity index 100% rename from substrabac/node/signals/__init__.py rename to substra-backend/node/signals/__init__.py diff --git a/substrabac/node/signals/node/__init__.py b/substra-backend/node/signals/node/__init__.py similarity index 100% rename from substrabac/node/signals/node/__init__.py rename to substra-backend/node/signals/node/__init__.py diff --git a/substrabac/node/signals/node/pre_save.py b/substra-backend/node/signals/node/pre_save.py similarity index 100% rename from substrabac/node/signals/node/pre_save.py rename to substra-backend/node/signals/node/pre_save.py diff --git a/substrabac/node/tests/__init__.py b/substra-backend/node/tests/__init__.py similarity index 100% rename from substrabac/node/tests/__init__.py rename to substra-backend/node/tests/__init__.py diff --git a/substrabac/node/tests/views/__init__.py b/substra-backend/node/tests/views/__init__.py similarity index 100% rename from substrabac/node/tests/views/__init__.py rename to substra-backend/node/tests/views/__init__.py diff --git a/substrabac/node/tests/views/tests_views_node.py b/substra-backend/node/tests/views/tests_views_node.py similarity index 100% rename from substrabac/node/tests/views/tests_views_node.py rename to substra-backend/node/tests/views/tests_views_node.py diff --git a/substrabac/node/urls.py b/substra-backend/node/urls.py similarity index 100% rename from substrabac/node/urls.py rename to substra-backend/node/urls.py diff --git a/substrabac/node/views/__init__.py b/substra-backend/node/views/__init__.py similarity index 100% rename from substrabac/node/views/__init__.py rename to substra-backend/node/views/__init__.py diff --git a/substrabac/node/views/node.py b/substra-backend/node/views/node.py similarity index 100% rename from substrabac/node/views/node.py rename to substra-backend/node/views/node.py diff --git a/substrabac/requirements.txt b/substra-backend/requirements.txt similarity index 100% rename from substrabac/requirements.txt rename to substra-backend/requirements.txt diff --git a/substrabac/substrabac/__init__.py b/substra-backend/substrabackend/__init__.py similarity index 100% rename from substrabac/substrabac/__init__.py rename to substra-backend/substrabackend/__init__.py diff --git a/substrabac/substrabac/celery.py b/substra-backend/substrabackend/celery.py similarity index 100% rename from substrabac/substrabac/celery.py rename to substra-backend/substrabackend/celery.py diff --git a/substrabac/substrabac/settings/__init__.py b/substra-backend/substrabackend/settings/__init__.py similarity index 100% rename from substrabac/substrabac/settings/__init__.py rename to substra-backend/substrabackend/settings/__init__.py diff --git a/substrabac/substrabac/settings/common.py b/substra-backend/substrabackend/settings/common.py similarity index 100% rename from substrabac/substrabac/settings/common.py rename to substra-backend/substrabackend/settings/common.py diff --git a/substrabac/substrabac/settings/deps/__init__.py b/substra-backend/substrabackend/settings/deps/__init__.py similarity index 100% rename from substrabac/substrabac/settings/deps/__init__.py rename to substra-backend/substrabackend/settings/deps/__init__.py diff --git a/substrabac/substrabac/settings/deps/cors.py b/substra-backend/substrabackend/settings/deps/cors.py similarity index 100% rename from substrabac/substrabac/settings/deps/cors.py rename to substra-backend/substrabackend/settings/deps/cors.py diff --git a/substrabac/substrabac/settings/deps/ledger.py b/substra-backend/substrabackend/settings/deps/ledger.py similarity index 100% rename from substrabac/substrabac/settings/deps/ledger.py rename to substra-backend/substrabackend/settings/deps/ledger.py diff --git a/substrabac/substrabac/settings/deps/org.py b/substra-backend/substrabackend/settings/deps/org.py similarity index 100% rename from substrabac/substrabac/settings/deps/org.py rename to substra-backend/substrabackend/settings/deps/org.py diff --git a/substrabac/substrabac/settings/deps/raven.py b/substra-backend/substrabackend/settings/deps/raven.py similarity index 100% rename from substrabac/substrabac/settings/deps/raven.py rename to substra-backend/substrabackend/settings/deps/raven.py diff --git a/substrabac/substrabac/settings/deps/restframework.py b/substra-backend/substrabackend/settings/deps/restframework.py similarity index 100% rename from substrabac/substrabac/settings/deps/restframework.py rename to substra-backend/substrabackend/settings/deps/restframework.py diff --git a/substrabac/substrabac/settings/dev.py b/substra-backend/substrabackend/settings/dev.py similarity index 100% rename from substrabac/substrabac/settings/dev.py rename to substra-backend/substrabackend/settings/dev.py diff --git a/substrabac/substrabac/settings/prod.py b/substra-backend/substrabackend/settings/prod.py similarity index 100% rename from substrabac/substrabac/settings/prod.py rename to substra-backend/substrabackend/settings/prod.py diff --git a/substrabac/substrabac/settings/server/__init__.py b/substra-backend/substrabackend/settings/server/__init__.py similarity index 100% rename from substrabac/substrabac/settings/server/__init__.py rename to substra-backend/substrabackend/settings/server/__init__.py diff --git a/substrabac/substrabac/settings/server/dev.py b/substra-backend/substrabackend/settings/server/dev.py similarity index 100% rename from substrabac/substrabac/settings/server/dev.py rename to substra-backend/substrabackend/settings/server/dev.py diff --git a/substrabac/substrabac/settings/server/nobasicauth/__init__.py b/substra-backend/substrabackend/settings/server/nobasicauth/__init__.py similarity index 100% rename from substrabac/substrabac/settings/server/nobasicauth/__init__.py rename to substra-backend/substrabackend/settings/server/nobasicauth/__init__.py diff --git a/substrabac/substrabac/settings/server/nobasicauth/dev.py b/substra-backend/substrabackend/settings/server/nobasicauth/dev.py similarity index 100% rename from substrabac/substrabac/settings/server/nobasicauth/dev.py rename to substra-backend/substrabackend/settings/server/nobasicauth/dev.py diff --git a/substrabac/substrabac/settings/server/nobasicauth/prod.py b/substra-backend/substrabackend/settings/server/nobasicauth/prod.py similarity index 100% rename from substrabac/substrabac/settings/server/nobasicauth/prod.py rename to substra-backend/substrabackend/settings/server/nobasicauth/prod.py diff --git a/substrabac/substrabac/settings/server/prod.py b/substra-backend/substrabackend/settings/server/prod.py similarity index 100% rename from substrabac/substrabac/settings/server/prod.py rename to substra-backend/substrabackend/settings/server/prod.py diff --git a/substrabac/substrabac/settings/test.py b/substra-backend/substrabackend/settings/test.py similarity index 100% rename from substrabac/substrabac/settings/test.py rename to substra-backend/substrabackend/settings/test.py diff --git a/substrabac/substrabac/urls.py b/substra-backend/substrabackend/urls.py similarity index 100% rename from substrabac/substrabac/urls.py rename to substra-backend/substrabackend/urls.py diff --git a/substrabac/substrabac/views.py b/substra-backend/substrabackend/views.py similarity index 100% rename from substrabac/substrabac/views.py rename to substra-backend/substrabackend/views.py diff --git a/substrabac/substrabac/wsgi.py b/substra-backend/substrabackend/wsgi.py similarity index 70% rename from substrabac/substrabac/wsgi.py rename to substra-backend/substrabackend/wsgi.py index 79ab173a2..25cb3a547 100644 --- a/substrabac/substrabac/wsgi.py +++ b/substra-backend/substrabackend/wsgi.py @@ -1,5 +1,5 @@ """ -WSGI config for substrabac project. +WSGI config for substrabackend project. It exposes the WSGI callable as a module-level variable named ``application``. @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "substrabac.settings.prod") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "substrabackend.settings.prod") application = get_wsgi_application() diff --git a/substrabac/substrapp/__init__.py b/substra-backend/substrapp/__init__.py similarity index 100% rename from substrabac/substrapp/__init__.py rename to substra-backend/substrapp/__init__.py diff --git a/substrabac/substrapp/admin.py b/substra-backend/substrapp/admin.py similarity index 100% rename from substrabac/substrapp/admin.py rename to substra-backend/substrapp/admin.py diff --git a/substrabac/substrapp/apps.py b/substra-backend/substrapp/apps.py similarity index 100% rename from substrabac/substrapp/apps.py rename to substra-backend/substrapp/apps.py diff --git a/substrabac/substrapp/ledger_utils.py b/substra-backend/substrapp/ledger_utils.py similarity index 100% rename from substrabac/substrapp/ledger_utils.py rename to substra-backend/substrapp/ledger_utils.py diff --git a/substrabac/substrapp/management/commands/bulkcreatedatasample.py b/substra-backend/substrapp/management/commands/bulkcreatedatasample.py similarity index 100% rename from substrabac/substrapp/management/commands/bulkcreatedatasample.py rename to substra-backend/substrapp/management/commands/bulkcreatedatasample.py diff --git a/substrabac/substrapp/management/commands/createdataset.py b/substra-backend/substrapp/management/commands/createdataset.py similarity index 100% rename from substrabac/substrapp/management/commands/createdataset.py rename to substra-backend/substrapp/management/commands/createdataset.py diff --git a/substrabac/substrapp/management/commands/createobjective.py b/substra-backend/substrapp/management/commands/createobjective.py similarity index 100% rename from substrabac/substrapp/management/commands/createobjective.py rename to substra-backend/substrapp/management/commands/createobjective.py diff --git a/substrabac/substrapp/management/tests/tests_bulkcreatedatasample.py b/substra-backend/substrapp/management/tests/tests_bulkcreatedatasample.py similarity index 99% rename from substrabac/substrapp/management/tests/tests_bulkcreatedatasample.py rename to substra-backend/substrapp/management/tests/tests_bulkcreatedatasample.py index d284f9880..c2895097c 100644 --- a/substrabac/substrapp/management/tests/tests_bulkcreatedatasample.py +++ b/substra-backend/substrapp/management/tests/tests_bulkcreatedatasample.py @@ -429,7 +429,7 @@ def test_bulkcreatedatasample_invalid_datamanager(self): output = err.getvalue().strip() - wanted_output = "One or more datamanager keys provided do not exist in local substrabac database. "\ + wanted_output = "One or more datamanager keys provided do not exist in local database. "\ "Please create them before. DataManager keys: ['bar']" self.assertEqual(wanted_output, output) @@ -466,7 +466,7 @@ def test_bulkcreatedatasample_datamanager_do_not_exist(self): output = err.getvalue().strip() - wanted_output = f"One or more datamanager keys provided do not exist in local substrabac database. " \ + wanted_output = f"One or more datamanager keys provided do not exist in local database. " \ f"Please create them before. DataManager keys: {data_manager_keys}" self.assertEqual(wanted_output, output) diff --git a/substrabac/substrapp/management/tests/tests_createdatamanager.py b/substra-backend/substrapp/management/tests/tests_createdatamanager.py similarity index 100% rename from substrabac/substrapp/management/tests/tests_createdatamanager.py rename to substra-backend/substrapp/management/tests/tests_createdatamanager.py diff --git a/substrabac/substrapp/management/tests/tests_createobjective.py b/substra-backend/substrapp/management/tests/tests_createobjective.py similarity index 100% rename from substrabac/substrapp/management/tests/tests_createobjective.py rename to substra-backend/substrapp/management/tests/tests_createobjective.py diff --git a/substrabac/substrapp/management/utils/__init__.py b/substra-backend/substrapp/management/utils/__init__.py similarity index 100% rename from substrabac/substrapp/management/utils/__init__.py rename to substra-backend/substrapp/management/utils/__init__.py diff --git a/substrabac/substrapp/management/utils/localRequest.py b/substra-backend/substrapp/management/utils/localRequest.py similarity index 100% rename from substrabac/substrapp/management/utils/localRequest.py rename to substra-backend/substrapp/management/utils/localRequest.py diff --git a/substrabac/substrapp/migrations/0001_initial.py b/substra-backend/substrapp/migrations/0001_initial.py similarity index 100% rename from substrabac/substrapp/migrations/0001_initial.py rename to substra-backend/substrapp/migrations/0001_initial.py diff --git a/substrabac/substrapp/migrations/__init__.py b/substra-backend/substrapp/migrations/__init__.py similarity index 100% rename from substrabac/substrapp/migrations/__init__.py rename to substra-backend/substrapp/migrations/__init__.py diff --git a/substrabac/substrapp/models/__init__.py b/substra-backend/substrapp/models/__init__.py similarity index 100% rename from substrabac/substrapp/models/__init__.py rename to substra-backend/substrapp/models/__init__.py diff --git a/substrabac/substrapp/models/algo.py b/substra-backend/substrapp/models/algo.py similarity index 100% rename from substrabac/substrapp/models/algo.py rename to substra-backend/substrapp/models/algo.py diff --git a/substrabac/substrapp/models/datamanager.py b/substra-backend/substrapp/models/datamanager.py similarity index 100% rename from substrabac/substrapp/models/datamanager.py rename to substra-backend/substrapp/models/datamanager.py diff --git a/substrabac/substrapp/models/datasample.py b/substra-backend/substrapp/models/datasample.py similarity index 100% rename from substrabac/substrapp/models/datasample.py rename to substra-backend/substrapp/models/datasample.py diff --git a/substrabac/substrapp/models/model.py b/substra-backend/substrapp/models/model.py similarity index 100% rename from substrabac/substrapp/models/model.py rename to substra-backend/substrapp/models/model.py diff --git a/substrabac/substrapp/models/objective.py b/substra-backend/substrapp/models/objective.py similarity index 100% rename from substrabac/substrapp/models/objective.py rename to substra-backend/substrapp/models/objective.py diff --git a/substrabac/substrapp/serializers/__init__.py b/substra-backend/substrapp/serializers/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/__init__.py rename to substra-backend/substrapp/serializers/__init__.py diff --git a/substrabac/substrapp/serializers/algo.py b/substra-backend/substrapp/serializers/algo.py similarity index 100% rename from substrabac/substrapp/serializers/algo.py rename to substra-backend/substrapp/serializers/algo.py diff --git a/substrabac/substrapp/serializers/datamanager.py b/substra-backend/substrapp/serializers/datamanager.py similarity index 100% rename from substrabac/substrapp/serializers/datamanager.py rename to substra-backend/substrapp/serializers/datamanager.py diff --git a/substrabac/substrapp/serializers/datasample.py b/substra-backend/substrapp/serializers/datasample.py similarity index 100% rename from substrabac/substrapp/serializers/datasample.py rename to substra-backend/substrapp/serializers/datasample.py diff --git a/substrabac/substrapp/serializers/ledger/__init__.py b/substra-backend/substrapp/serializers/ledger/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/__init__.py rename to substra-backend/substrapp/serializers/ledger/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/algo/__init__.py b/substra-backend/substrapp/serializers/ledger/algo/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/algo/__init__.py rename to substra-backend/substrapp/serializers/ledger/algo/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/algo/serializer.py b/substra-backend/substrapp/serializers/ledger/algo/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/algo/serializer.py rename to substra-backend/substrapp/serializers/ledger/algo/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/algo/tasks.py b/substra-backend/substrapp/serializers/ledger/algo/tasks.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/algo/tasks.py rename to substra-backend/substrapp/serializers/ledger/algo/tasks.py diff --git a/substrabac/substrapp/serializers/ledger/algo/util.py b/substra-backend/substrapp/serializers/ledger/algo/util.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/algo/util.py rename to substra-backend/substrapp/serializers/ledger/algo/util.py diff --git a/substrabac/substrapp/serializers/ledger/computeplan/__init__.py b/substra-backend/substrapp/serializers/ledger/computeplan/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/computeplan/__init__.py rename to substra-backend/substrapp/serializers/ledger/computeplan/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/computeplan/serializer.py b/substra-backend/substrapp/serializers/ledger/computeplan/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/computeplan/serializer.py rename to substra-backend/substrapp/serializers/ledger/computeplan/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/computeplan/tasks.py b/substra-backend/substrapp/serializers/ledger/computeplan/tasks.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/computeplan/tasks.py rename to substra-backend/substrapp/serializers/ledger/computeplan/tasks.py diff --git a/substrabac/substrapp/serializers/ledger/computeplan/util.py b/substra-backend/substrapp/serializers/ledger/computeplan/util.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/computeplan/util.py rename to substra-backend/substrapp/serializers/ledger/computeplan/util.py diff --git a/substrabac/substrapp/serializers/ledger/datamanager/__init__.py b/substra-backend/substrapp/serializers/ledger/datamanager/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/datamanager/__init__.py rename to substra-backend/substrapp/serializers/ledger/datamanager/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/datamanager/serializer.py b/substra-backend/substrapp/serializers/ledger/datamanager/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/datamanager/serializer.py rename to substra-backend/substrapp/serializers/ledger/datamanager/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/datamanager/tasks.py b/substra-backend/substrapp/serializers/ledger/datamanager/tasks.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/datamanager/tasks.py rename to substra-backend/substrapp/serializers/ledger/datamanager/tasks.py diff --git a/substrabac/substrapp/serializers/ledger/datamanager/util.py b/substra-backend/substrapp/serializers/ledger/datamanager/util.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/datamanager/util.py rename to substra-backend/substrapp/serializers/ledger/datamanager/util.py diff --git a/substrabac/substrapp/serializers/ledger/datasample/__init__.py b/substra-backend/substrapp/serializers/ledger/datasample/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/datasample/__init__.py rename to substra-backend/substrapp/serializers/ledger/datasample/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/datasample/serializer.py b/substra-backend/substrapp/serializers/ledger/datasample/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/datasample/serializer.py rename to substra-backend/substrapp/serializers/ledger/datasample/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/datasample/tasks.py b/substra-backend/substrapp/serializers/ledger/datasample/tasks.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/datasample/tasks.py rename to substra-backend/substrapp/serializers/ledger/datasample/tasks.py diff --git a/substrabac/substrapp/serializers/ledger/datasample/util.py b/substra-backend/substrapp/serializers/ledger/datasample/util.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/datasample/util.py rename to substra-backend/substrapp/serializers/ledger/datasample/util.py diff --git a/substrabac/substrapp/serializers/ledger/model/__init__.py b/substra-backend/substrapp/serializers/ledger/model/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/model/__init__.py rename to substra-backend/substrapp/serializers/ledger/model/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/model/serializer.py b/substra-backend/substrapp/serializers/ledger/model/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/model/serializer.py rename to substra-backend/substrapp/serializers/ledger/model/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/objective/__init__.py b/substra-backend/substrapp/serializers/ledger/objective/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/objective/__init__.py rename to substra-backend/substrapp/serializers/ledger/objective/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/objective/serializer.py b/substra-backend/substrapp/serializers/ledger/objective/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/objective/serializer.py rename to substra-backend/substrapp/serializers/ledger/objective/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/objective/tasks.py b/substra-backend/substrapp/serializers/ledger/objective/tasks.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/objective/tasks.py rename to substra-backend/substrapp/serializers/ledger/objective/tasks.py diff --git a/substrabac/substrapp/serializers/ledger/objective/util.py b/substra-backend/substrapp/serializers/ledger/objective/util.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/objective/util.py rename to substra-backend/substrapp/serializers/ledger/objective/util.py diff --git a/substrabac/substrapp/serializers/ledger/testtuple/__init__.py b/substra-backend/substrapp/serializers/ledger/testtuple/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/testtuple/__init__.py rename to substra-backend/substrapp/serializers/ledger/testtuple/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/testtuple/serializer.py b/substra-backend/substrapp/serializers/ledger/testtuple/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/testtuple/serializer.py rename to substra-backend/substrapp/serializers/ledger/testtuple/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/testtuple/tasks.py b/substra-backend/substrapp/serializers/ledger/testtuple/tasks.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/testtuple/tasks.py rename to substra-backend/substrapp/serializers/ledger/testtuple/tasks.py diff --git a/substrabac/substrapp/serializers/ledger/testtuple/util.py b/substra-backend/substrapp/serializers/ledger/testtuple/util.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/testtuple/util.py rename to substra-backend/substrapp/serializers/ledger/testtuple/util.py diff --git a/substrabac/substrapp/serializers/ledger/traintuple/__init__.py b/substra-backend/substrapp/serializers/ledger/traintuple/__init__.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/traintuple/__init__.py rename to substra-backend/substrapp/serializers/ledger/traintuple/__init__.py diff --git a/substrabac/substrapp/serializers/ledger/traintuple/serializer.py b/substra-backend/substrapp/serializers/ledger/traintuple/serializer.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/traintuple/serializer.py rename to substra-backend/substrapp/serializers/ledger/traintuple/serializer.py diff --git a/substrabac/substrapp/serializers/ledger/traintuple/tasks.py b/substra-backend/substrapp/serializers/ledger/traintuple/tasks.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/traintuple/tasks.py rename to substra-backend/substrapp/serializers/ledger/traintuple/tasks.py diff --git a/substrabac/substrapp/serializers/ledger/traintuple/util.py b/substra-backend/substrapp/serializers/ledger/traintuple/util.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/traintuple/util.py rename to substra-backend/substrapp/serializers/ledger/traintuple/util.py diff --git a/substrabac/substrapp/serializers/ledger/utils.py b/substra-backend/substrapp/serializers/ledger/utils.py similarity index 100% rename from substrabac/substrapp/serializers/ledger/utils.py rename to substra-backend/substrapp/serializers/ledger/utils.py diff --git a/substrabac/substrapp/serializers/model.py b/substra-backend/substrapp/serializers/model.py similarity index 100% rename from substrabac/substrapp/serializers/model.py rename to substra-backend/substrapp/serializers/model.py diff --git a/substrabac/substrapp/serializers/objective.py b/substra-backend/substrapp/serializers/objective.py similarity index 100% rename from substrabac/substrapp/serializers/objective.py rename to substra-backend/substrapp/serializers/objective.py diff --git a/substrabac/substrapp/serializers/utils.py b/substra-backend/substrapp/serializers/utils.py similarity index 100% rename from substrabac/substrapp/serializers/utils.py rename to substra-backend/substrapp/serializers/utils.py diff --git a/substrabac/substrapp/signals/__init__.py b/substra-backend/substrapp/signals/__init__.py similarity index 100% rename from substrabac/substrapp/signals/__init__.py rename to substra-backend/substrapp/signals/__init__.py diff --git a/substrabac/substrapp/signals/algo/__init__.py b/substra-backend/substrapp/signals/algo/__init__.py similarity index 100% rename from substrabac/substrapp/signals/algo/__init__.py rename to substra-backend/substrapp/signals/algo/__init__.py diff --git a/substrabac/substrapp/signals/algo/post_delete.py b/substra-backend/substrapp/signals/algo/post_delete.py similarity index 100% rename from substrabac/substrapp/signals/algo/post_delete.py rename to substra-backend/substrapp/signals/algo/post_delete.py diff --git a/substrabac/substrapp/signals/datamanager/__init__.py b/substra-backend/substrapp/signals/datamanager/__init__.py similarity index 100% rename from substrabac/substrapp/signals/datamanager/__init__.py rename to substra-backend/substrapp/signals/datamanager/__init__.py diff --git a/substrabac/substrapp/signals/datamanager/post_delete.py b/substra-backend/substrapp/signals/datamanager/post_delete.py similarity index 100% rename from substrabac/substrapp/signals/datamanager/post_delete.py rename to substra-backend/substrapp/signals/datamanager/post_delete.py diff --git a/substrabac/substrapp/signals/datasample/__init__.py b/substra-backend/substrapp/signals/datasample/__init__.py similarity index 100% rename from substrabac/substrapp/signals/datasample/__init__.py rename to substra-backend/substrapp/signals/datasample/__init__.py diff --git a/substrabac/substrapp/signals/datasample/post_delete.py b/substra-backend/substrapp/signals/datasample/post_delete.py similarity index 100% rename from substrabac/substrapp/signals/datasample/post_delete.py rename to substra-backend/substrapp/signals/datasample/post_delete.py diff --git a/substrabac/substrapp/signals/datasample/pre_save.py b/substra-backend/substrapp/signals/datasample/pre_save.py similarity index 100% rename from substrabac/substrapp/signals/datasample/pre_save.py rename to substra-backend/substrapp/signals/datasample/pre_save.py diff --git a/substrabac/substrapp/signals/model/__init__.py b/substra-backend/substrapp/signals/model/__init__.py similarity index 100% rename from substrabac/substrapp/signals/model/__init__.py rename to substra-backend/substrapp/signals/model/__init__.py diff --git a/substrabac/substrapp/signals/model/post_delete.py b/substra-backend/substrapp/signals/model/post_delete.py similarity index 100% rename from substrabac/substrapp/signals/model/post_delete.py rename to substra-backend/substrapp/signals/model/post_delete.py diff --git a/substrabac/substrapp/signals/objective/__init__.py b/substra-backend/substrapp/signals/objective/__init__.py similarity index 100% rename from substrabac/substrapp/signals/objective/__init__.py rename to substra-backend/substrapp/signals/objective/__init__.py diff --git a/substrabac/substrapp/signals/objective/post_delete.py b/substra-backend/substrapp/signals/objective/post_delete.py similarity index 100% rename from substrabac/substrapp/signals/objective/post_delete.py rename to substra-backend/substrapp/signals/objective/post_delete.py diff --git a/substrabac/substrapp/tasks/__init__.py b/substra-backend/substrapp/tasks/__init__.py similarity index 100% rename from substrabac/substrapp/tasks/__init__.py rename to substra-backend/substrapp/tasks/__init__.py diff --git a/substrabac/substrapp/tasks/exception_handler.py b/substra-backend/substrapp/tasks/exception_handler.py similarity index 96% rename from substrabac/substrapp/tasks/exception_handler.py rename to substra-backend/substrapp/tasks/exception_handler.py index 2082ec263..b2eed83ce 100644 --- a/substrabac/substrapp/tasks/exception_handler.py +++ b/substra-backend/substrapp/tasks/exception_handler.py @@ -91,7 +91,7 @@ def find_exception(module): def generate_exceptions_map(append=True): - os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabac.settings.prod' + os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabackend.settings.prod' import requests.exceptions import celery.exceptions @@ -144,7 +144,7 @@ def generate_exceptions_map(append=True): if __name__ == '__main__': - os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabac.settings.common' + os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabackend.settings.common' json_exceptions = generate_exceptions_map() with open(EXCEPTION_PATH, 'w') as outfile: json.dump(json_exceptions, outfile, indent=4) diff --git a/substrabac/substrapp/tasks/exceptions.json b/substra-backend/substrapp/tasks/exceptions.json similarity index 100% rename from substrabac/substrapp/tasks/exceptions.json rename to substra-backend/substrapp/tasks/exceptions.json diff --git a/substrabac/substrapp/tasks/tasks.py b/substra-backend/substrapp/tasks/tasks.py similarity index 99% rename from substrabac/substrapp/tasks/tasks.py rename to substra-backend/substrapp/tasks/tasks.py index 8415cde9a..4949f654a 100644 --- a/substrabac/substrapp/tasks/tasks.py +++ b/substra-backend/substrapp/tasks/tasks.py @@ -16,7 +16,7 @@ from celery.result import AsyncResult from celery.exceptions import Ignore -from substrabac.celery import app +from substrabackend.celery import app from substrapp.utils import get_hash, get_owner, create_directory, uncompress_content from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, query_tuples, LedgerError, LedgerStatusError, get_object_from_ledger) @@ -255,7 +255,7 @@ def prepare_tuple(subtuple, tuple_type): log_start_tuple(tuple_type, subtuple['key']) except LedgerStatusError as e: # Do not log_fail_tuple in this case, because prepare_tuple task are not unique - # in case of multiple instances of substrabac running for the same organisation + # in case of multiple instances of substra backend running for the same organisation # So prepare_tuple tasks are ignored if it cannot log_start_tuple logging.exception(e) raise Ignore() diff --git a/substrabac/substrapp/tasks/utils.py b/substra-backend/substrapp/tasks/utils.py similarity index 99% rename from substrabac/substrapp/tasks/utils.py rename to substra-backend/substrapp/tasks/utils.py index a8e540cc1..9eec36a15 100644 --- a/substrabac/substrapp/tasks/utils.py +++ b/substra-backend/substrapp/tasks/utils.py @@ -196,7 +196,7 @@ def memory_limit_mb(cls): try: return int(os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES') / (1024. ** 2)) // cls.__concurrency except ValueError: - # fixes macOS issue https://github.com/SubstraFoundation/substrabac/issues/262 + # fixes macOS issue https://github.com/SubstraFoundation/substra-backend/issues/262 return int(check_output(['sysctl', '-n', 'hw.memsize']).strip()) // cls.__concurrency @classmethod diff --git a/substrabac/substrapp/tests/__init__.py b/substra-backend/substrapp/tests/__init__.py similarity index 100% rename from substrabac/substrapp/tests/__init__.py rename to substra-backend/substrapp/tests/__init__.py diff --git a/substrabac/substrapp/tests/assets.py b/substra-backend/substrapp/tests/assets.py similarity index 100% rename from substrabac/substrapp/tests/assets.py rename to substra-backend/substrapp/tests/assets.py diff --git a/substrabac/substrapp/tests/common.py b/substra-backend/substrapp/tests/common.py similarity index 100% rename from substrabac/substrapp/tests/common.py rename to substra-backend/substrapp/tests/common.py diff --git a/substrabac/substrapp/tests/generate_assets.py b/substra-backend/substrapp/tests/generate_assets.py similarity index 86% rename from substrabac/substrapp/tests/generate_assets.py rename to substra-backend/substrapp/tests/generate_assets.py index 39b903ca7..174aaa135 100644 --- a/substrabac/substrapp/tests/generate_assets.py +++ b/substra-backend/substrapp/tests/generate_assets.py @@ -10,7 +10,7 @@ def main(): client = Client() - client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0') + client.add_profile('owkin', 'http://owkin.substra-backend:8000', '0.0') client.set_profile('owkin') @@ -32,8 +32,8 @@ def main(): '2. run populate.py\n' '3. run substrapp/tests/generate_assets.py\n"""\n\n') for k, v in assets.items(): - v = v.replace('owkin.substrabac:8000', 'testserver') - v = v.replace('chunantes.substrabac:8001', 'testserver') + v = v.replace('owkin.substra-backend:8000', 'testserver') + v = v.replace('chunantes.substra-backend:8001', 'testserver') v = v.replace('true', 'True') v = v.replace('false', 'False') v = v.replace('null', 'None') diff --git a/substrabac/substrapp/tests/query/__init__.py b/substra-backend/substrapp/tests/query/__init__.py similarity index 100% rename from substrabac/substrapp/tests/query/__init__.py rename to substra-backend/substrapp/tests/query/__init__.py diff --git a/substrabac/substrapp/tests/query/tests_query_algo.py b/substra-backend/substrapp/tests/query/tests_query_algo.py similarity index 100% rename from substrabac/substrapp/tests/query/tests_query_algo.py rename to substra-backend/substrapp/tests/query/tests_query_algo.py diff --git a/substrabac/substrapp/tests/query/tests_query_datamanager.py b/substra-backend/substrapp/tests/query/tests_query_datamanager.py similarity index 100% rename from substrabac/substrapp/tests/query/tests_query_datamanager.py rename to substra-backend/substrapp/tests/query/tests_query_datamanager.py diff --git a/substrabac/substrapp/tests/query/tests_query_datasample.py b/substra-backend/substrapp/tests/query/tests_query_datasample.py similarity index 99% rename from substrabac/substrapp/tests/query/tests_query_datasample.py rename to substra-backend/substrapp/tests/query/tests_query_datasample.py index bbe8618f5..83e8d8fa9 100644 --- a/substrabac/substrapp/tests/query/tests_query_datasample.py +++ b/substra-backend/substrapp/tests/query/tests_query_datasample.py @@ -167,7 +167,7 @@ def test_add_data_sample_ko(self): r = response.json() self.assertEqual( r['message'], - "One or more datamanager keys provided do not exist in local substrabac database. " + "One or more datamanager keys provided do not exist in local database. " "Please create them before. DataManager keys: ['toto']") self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) diff --git a/substrabac/substrapp/tests/query/tests_query_objective.py b/substra-backend/substrapp/tests/query/tests_query_objective.py similarity index 100% rename from substrabac/substrapp/tests/query/tests_query_objective.py rename to substra-backend/substrapp/tests/query/tests_query_objective.py diff --git a/substrabac/substrapp/tests/query/tests_query_tuples.py b/substra-backend/substrapp/tests/query/tests_query_tuples.py similarity index 100% rename from substrabac/substrapp/tests/query/tests_query_tuples.py rename to substra-backend/substrapp/tests/query/tests_query_tuples.py diff --git a/substrabac/substrapp/tests/tests_exception.py b/substra-backend/substrapp/tests/tests_exception.py similarity index 100% rename from substrabac/substrapp/tests/tests_exception.py rename to substra-backend/substrapp/tests/tests_exception.py diff --git a/substrabac/substrapp/tests/tests_misc.py b/substra-backend/substrapp/tests/tests_misc.py similarity index 100% rename from substrabac/substrapp/tests/tests_misc.py rename to substra-backend/substrapp/tests/tests_misc.py diff --git a/substrabac/substrapp/tests/tests_model.py b/substra-backend/substrapp/tests/tests_model.py similarity index 100% rename from substrabac/substrapp/tests/tests_model.py rename to substra-backend/substrapp/tests/tests_model.py diff --git a/substrabac/substrapp/tests/tests_tasks.py b/substra-backend/substrapp/tests/tests_tasks.py similarity index 100% rename from substrabac/substrapp/tests/tests_tasks.py rename to substra-backend/substrapp/tests/tests_tasks.py diff --git a/substrabac/substrapp/tests/views/__init__.py b/substra-backend/substrapp/tests/views/__init__.py similarity index 100% rename from substrabac/substrapp/tests/views/__init__.py rename to substra-backend/substrapp/tests/views/__init__.py diff --git a/substrabac/substrapp/tests/views/test_views_authentication.py b/substra-backend/substrapp/tests/views/test_views_authentication.py similarity index 100% rename from substrabac/substrapp/tests/views/test_views_authentication.py rename to substra-backend/substrapp/tests/views/test_views_authentication.py diff --git a/substrabac/substrapp/tests/views/tests_utils.py b/substra-backend/substrapp/tests/views/tests_utils.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_utils.py rename to substra-backend/substrapp/tests/views/tests_utils.py diff --git a/substrabac/substrapp/tests/views/tests_views.py b/substra-backend/substrapp/tests/views/tests_views.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views.py rename to substra-backend/substrapp/tests/views/tests_views.py diff --git a/substrabac/substrapp/tests/views/tests_views_algo.py b/substra-backend/substrapp/tests/views/tests_views_algo.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views_algo.py rename to substra-backend/substrapp/tests/views/tests_views_algo.py diff --git a/substrabac/substrapp/tests/views/tests_views_computeplan.py b/substra-backend/substrapp/tests/views/tests_views_computeplan.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views_computeplan.py rename to substra-backend/substrapp/tests/views/tests_views_computeplan.py diff --git a/substrabac/substrapp/tests/views/tests_views_datamanager.py b/substra-backend/substrapp/tests/views/tests_views_datamanager.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views_datamanager.py rename to substra-backend/substrapp/tests/views/tests_views_datamanager.py diff --git a/substrabac/substrapp/tests/views/tests_views_datasample.py b/substra-backend/substrapp/tests/views/tests_views_datasample.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views_datasample.py rename to substra-backend/substrapp/tests/views/tests_views_datasample.py diff --git a/substrabac/substrapp/tests/views/tests_views_model.py b/substra-backend/substrapp/tests/views/tests_views_model.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views_model.py rename to substra-backend/substrapp/tests/views/tests_views_model.py diff --git a/substrabac/substrapp/tests/views/tests_views_objective.py b/substra-backend/substrapp/tests/views/tests_views_objective.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views_objective.py rename to substra-backend/substrapp/tests/views/tests_views_objective.py diff --git a/substrabac/substrapp/tests/views/tests_views_task.py b/substra-backend/substrapp/tests/views/tests_views_task.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views_task.py rename to substra-backend/substrapp/tests/views/tests_views_task.py diff --git a/substrabac/substrapp/tests/views/tests_views_tuples.py b/substra-backend/substrapp/tests/views/tests_views_tuples.py similarity index 100% rename from substrabac/substrapp/tests/views/tests_views_tuples.py rename to substra-backend/substrapp/tests/views/tests_views_tuples.py diff --git a/substrabac/substrapp/urls.py b/substra-backend/substrapp/urls.py similarity index 100% rename from substrabac/substrapp/urls.py rename to substra-backend/substrapp/urls.py diff --git a/substrabac/substrapp/utils.py b/substra-backend/substrapp/utils.py similarity index 100% rename from substrabac/substrapp/utils.py rename to substra-backend/substrapp/utils.py diff --git a/substrabac/substrapp/views/__init__.py b/substra-backend/substrapp/views/__init__.py similarity index 100% rename from substrabac/substrapp/views/__init__.py rename to substra-backend/substrapp/views/__init__.py diff --git a/substrabac/substrapp/views/algo.py b/substra-backend/substrapp/views/algo.py similarity index 100% rename from substrabac/substrapp/views/algo.py rename to substra-backend/substrapp/views/algo.py diff --git a/substrabac/substrapp/views/computeplan.py b/substra-backend/substrapp/views/computeplan.py similarity index 100% rename from substrabac/substrapp/views/computeplan.py rename to substra-backend/substrapp/views/computeplan.py diff --git a/substrabac/substrapp/views/datamanager.py b/substra-backend/substrapp/views/datamanager.py similarity index 100% rename from substrabac/substrapp/views/datamanager.py rename to substra-backend/substrapp/views/datamanager.py diff --git a/substrabac/substrapp/views/datasample.py b/substra-backend/substrapp/views/datasample.py similarity index 99% rename from substrabac/substrapp/views/datasample.py rename to substra-backend/substrapp/views/datasample.py index a35bb3327..007fc1b2b 100644 --- a/substrabac/substrapp/views/datasample.py +++ b/substra-backend/substrapp/views/datasample.py @@ -38,7 +38,7 @@ def check_datamanagers(data_manager_keys): datamanager_count = DataManager.objects.filter(pkhash__in=data_manager_keys).count() if datamanager_count != len(data_manager_keys): - raise Exception(f'One or more datamanager keys provided do not exist in local substrabac database. ' + raise Exception(f'One or more datamanager keys provided do not exist in local database. ' f'Please create them before. DataManager keys: {data_manager_keys}') @staticmethod diff --git a/substrabac/substrapp/views/filters_utils.py b/substra-backend/substrapp/views/filters_utils.py similarity index 100% rename from substrabac/substrapp/views/filters_utils.py rename to substra-backend/substrapp/views/filters_utils.py diff --git a/substrabac/substrapp/views/model.py b/substra-backend/substrapp/views/model.py similarity index 100% rename from substrabac/substrapp/views/model.py rename to substra-backend/substrapp/views/model.py diff --git a/substrabac/substrapp/views/objective.py b/substra-backend/substrapp/views/objective.py similarity index 100% rename from substrabac/substrapp/views/objective.py rename to substra-backend/substrapp/views/objective.py diff --git a/substrabac/substrapp/views/task.py b/substra-backend/substrapp/views/task.py similarity index 100% rename from substrabac/substrapp/views/task.py rename to substra-backend/substrapp/views/task.py diff --git a/substrabac/substrapp/views/testtuple.py b/substra-backend/substrapp/views/testtuple.py similarity index 100% rename from substrabac/substrapp/views/testtuple.py rename to substra-backend/substrapp/views/testtuple.py diff --git a/substrabac/substrapp/views/traintuple.py b/substra-backend/substrapp/views/traintuple.py similarity index 100% rename from substrabac/substrapp/views/traintuple.py rename to substra-backend/substrapp/views/traintuple.py diff --git a/substrabac/substrapp/views/utils.py b/substra-backend/substrapp/views/utils.py similarity index 100% rename from substrabac/substrapp/views/utils.py rename to substra-backend/substrapp/views/utils.py From 6c2b2e1e65295858d4b790e2587f84be78ad15cc Mon Sep 17 00:00:00 2001 From: inalgnu Date: Fri, 18 Oct 2019 17:41:09 +0200 Subject: [PATCH 365/457] renaming --- {substra-backend => substrabackend}/.coveragerc | 0 {substra-backend => substrabackend}/events/__init__.py | 0 {substra-backend => substrabackend}/events/apps.py | 0 {substra-backend => substrabackend}/libs/SQLPrintingMiddleware.py | 0 {substra-backend => substrabackend}/libs/__init__.py | 0 {substra-backend => substrabackend}/libs/authentication.py | 0 {substra-backend => substrabackend}/libs/gen_secret_key.py | 0 {substra-backend => substrabackend}/libs/pagination.py | 0 {substra-backend => substrabackend}/libs/serializers.py | 0 {substra-backend => substrabackend}/libs/timestampModel.py | 0 {substra-backend => substrabackend}/libs/versioning.py | 0 {substra-backend => substrabackend}/manage.py | 0 {substra-backend => substrabackend}/node-register/__init__.py | 0 {substra-backend => substrabackend}/node-register/apps.py | 0 {substra-backend => substrabackend}/node/__init__.py | 0 {substra-backend => substrabackend}/node/apps.py | 0 {substra-backend => substrabackend}/node/authentication.py | 0 .../node/fixtures/nodes-chunantes.yaml | 0 {substra-backend => substrabackend}/node/fixtures/nodes-clb.yaml | 0 .../node/fixtures/nodes-owkin.yaml | 0 .../node/management/commands/create_incoming_node.py | 0 .../node/management/commands/create_outgoing_node.py | 0 .../node/management/commands/get_incoming_node.py | 0 .../node/management/commands/get_outgoing_node.py | 0 .../node/migrations/0001_initial.py | 0 .../node/migrations/0002_nodeuser.py | 0 {substra-backend => substrabackend}/node/migrations/__init__.py | 0 {substra-backend => substrabackend}/node/models.py | 0 {substra-backend => substrabackend}/node/signals/__init__.py | 0 {substra-backend => substrabackend}/node/signals/node/__init__.py | 0 {substra-backend => substrabackend}/node/signals/node/pre_save.py | 0 {substra-backend => substrabackend}/node/tests/__init__.py | 0 {substra-backend => substrabackend}/node/tests/views/__init__.py | 0 .../node/tests/views/tests_views_node.py | 0 {substra-backend => substrabackend}/node/urls.py | 0 {substra-backend => substrabackend}/node/views/__init__.py | 0 {substra-backend => substrabackend}/node/views/node.py | 0 {substra-backend => substrabackend}/requirements.txt | 0 {substra-backend => substrabackend}/substrabackend/__init__.py | 0 {substra-backend => substrabackend}/substrabackend/celery.py | 0 .../substrabackend/settings/__init__.py | 0 .../substrabackend/settings/common.py | 0 .../substrabackend/settings/deps/__init__.py | 0 .../substrabackend/settings/deps/cors.py | 0 .../substrabackend/settings/deps/ledger.py | 0 .../substrabackend/settings/deps/org.py | 0 .../substrabackend/settings/deps/raven.py | 0 .../substrabackend/settings/deps/restframework.py | 0 .../substrabackend/settings/dev.py | 0 .../substrabackend/settings/prod.py | 0 .../substrabackend/settings/server/__init__.py | 0 .../substrabackend/settings/server/dev.py | 0 .../substrabackend/settings/server/nobasicauth/__init__.py | 0 .../substrabackend/settings/server/nobasicauth/dev.py | 0 .../substrabackend/settings/server/nobasicauth/prod.py | 0 .../substrabackend/settings/server/prod.py | 0 .../substrabackend/settings/test.py | 0 {substra-backend => substrabackend}/substrabackend/urls.py | 0 {substra-backend => substrabackend}/substrabackend/views.py | 0 {substra-backend => substrabackend}/substrabackend/wsgi.py | 0 {substra-backend => substrabackend}/substrapp/__init__.py | 0 {substra-backend => substrabackend}/substrapp/admin.py | 0 {substra-backend => substrabackend}/substrapp/apps.py | 0 {substra-backend => substrabackend}/substrapp/ledger_utils.py | 0 .../substrapp/management/commands/bulkcreatedatasample.py | 0 .../substrapp/management/commands/createdataset.py | 0 .../substrapp/management/commands/createobjective.py | 0 .../substrapp/management/tests/tests_bulkcreatedatasample.py | 0 .../substrapp/management/tests/tests_createdatamanager.py | 0 .../substrapp/management/tests/tests_createobjective.py | 0 .../substrapp/management/utils/__init__.py | 0 .../substrapp/management/utils/localRequest.py | 0 .../substrapp/migrations/0001_initial.py | 0 .../substrapp/migrations/__init__.py | 0 {substra-backend => substrabackend}/substrapp/models/__init__.py | 0 {substra-backend => substrabackend}/substrapp/models/algo.py | 0 .../substrapp/models/datamanager.py | 0 .../substrapp/models/datasample.py | 0 {substra-backend => substrabackend}/substrapp/models/model.py | 0 {substra-backend => substrabackend}/substrapp/models/objective.py | 0 .../substrapp/serializers/__init__.py | 0 {substra-backend => substrabackend}/substrapp/serializers/algo.py | 0 .../substrapp/serializers/datamanager.py | 0 .../substrapp/serializers/datasample.py | 0 .../substrapp/serializers/ledger/__init__.py | 0 .../substrapp/serializers/ledger/algo/__init__.py | 0 .../substrapp/serializers/ledger/algo/serializer.py | 0 .../substrapp/serializers/ledger/algo/tasks.py | 0 .../substrapp/serializers/ledger/algo/util.py | 0 .../substrapp/serializers/ledger/computeplan/__init__.py | 0 .../substrapp/serializers/ledger/computeplan/serializer.py | 0 .../substrapp/serializers/ledger/computeplan/tasks.py | 0 .../substrapp/serializers/ledger/computeplan/util.py | 0 .../substrapp/serializers/ledger/datamanager/__init__.py | 0 .../substrapp/serializers/ledger/datamanager/serializer.py | 0 .../substrapp/serializers/ledger/datamanager/tasks.py | 0 .../substrapp/serializers/ledger/datamanager/util.py | 0 .../substrapp/serializers/ledger/datasample/__init__.py | 0 .../substrapp/serializers/ledger/datasample/serializer.py | 0 .../substrapp/serializers/ledger/datasample/tasks.py | 0 .../substrapp/serializers/ledger/datasample/util.py | 0 .../substrapp/serializers/ledger/model/__init__.py | 0 .../substrapp/serializers/ledger/model/serializer.py | 0 .../substrapp/serializers/ledger/objective/__init__.py | 0 .../substrapp/serializers/ledger/objective/serializer.py | 0 .../substrapp/serializers/ledger/objective/tasks.py | 0 .../substrapp/serializers/ledger/objective/util.py | 0 .../substrapp/serializers/ledger/testtuple/__init__.py | 0 .../substrapp/serializers/ledger/testtuple/serializer.py | 0 .../substrapp/serializers/ledger/testtuple/tasks.py | 0 .../substrapp/serializers/ledger/testtuple/util.py | 0 .../substrapp/serializers/ledger/traintuple/__init__.py | 0 .../substrapp/serializers/ledger/traintuple/serializer.py | 0 .../substrapp/serializers/ledger/traintuple/tasks.py | 0 .../substrapp/serializers/ledger/traintuple/util.py | 0 .../substrapp/serializers/ledger/utils.py | 0 .../substrapp/serializers/model.py | 0 .../substrapp/serializers/objective.py | 0 .../substrapp/serializers/utils.py | 0 {substra-backend => substrabackend}/substrapp/signals/__init__.py | 0 .../substrapp/signals/algo/__init__.py | 0 .../substrapp/signals/algo/post_delete.py | 0 .../substrapp/signals/datamanager/__init__.py | 0 .../substrapp/signals/datamanager/post_delete.py | 0 .../substrapp/signals/datasample/__init__.py | 0 .../substrapp/signals/datasample/post_delete.py | 0 .../substrapp/signals/datasample/pre_save.py | 0 .../substrapp/signals/model/__init__.py | 0 .../substrapp/signals/model/post_delete.py | 0 .../substrapp/signals/objective/__init__.py | 0 .../substrapp/signals/objective/post_delete.py | 0 {substra-backend => substrabackend}/substrapp/tasks/__init__.py | 0 .../substrapp/tasks/exception_handler.py | 0 .../substrapp/tasks/exceptions.json | 0 {substra-backend => substrabackend}/substrapp/tasks/tasks.py | 0 {substra-backend => substrabackend}/substrapp/tasks/utils.py | 0 {substra-backend => substrabackend}/substrapp/tests/__init__.py | 0 {substra-backend => substrabackend}/substrapp/tests/assets.py | 0 {substra-backend => substrabackend}/substrapp/tests/common.py | 0 .../substrapp/tests/generate_assets.py | 0 .../substrapp/tests/query/__init__.py | 0 .../substrapp/tests/query/tests_query_algo.py | 0 .../substrapp/tests/query/tests_query_datamanager.py | 0 .../substrapp/tests/query/tests_query_datasample.py | 0 .../substrapp/tests/query/tests_query_objective.py | 0 .../substrapp/tests/query/tests_query_tuples.py | 0 .../substrapp/tests/tests_exception.py | 0 {substra-backend => substrabackend}/substrapp/tests/tests_misc.py | 0 .../substrapp/tests/tests_model.py | 0 .../substrapp/tests/tests_tasks.py | 0 .../substrapp/tests/views/__init__.py | 0 .../substrapp/tests/views/test_views_authentication.py | 0 .../substrapp/tests/views/tests_utils.py | 0 .../substrapp/tests/views/tests_views.py | 0 .../substrapp/tests/views/tests_views_algo.py | 0 .../substrapp/tests/views/tests_views_computeplan.py | 0 .../substrapp/tests/views/tests_views_datamanager.py | 0 .../substrapp/tests/views/tests_views_datasample.py | 0 .../substrapp/tests/views/tests_views_model.py | 0 .../substrapp/tests/views/tests_views_objective.py | 0 .../substrapp/tests/views/tests_views_task.py | 0 .../substrapp/tests/views/tests_views_tuples.py | 0 {substra-backend => substrabackend}/substrapp/urls.py | 0 {substra-backend => substrabackend}/substrapp/utils.py | 0 {substra-backend => substrabackend}/substrapp/views/__init__.py | 0 {substra-backend => substrabackend}/substrapp/views/algo.py | 0 .../substrapp/views/computeplan.py | 0 .../substrapp/views/datamanager.py | 0 {substra-backend => substrabackend}/substrapp/views/datasample.py | 0 .../substrapp/views/filters_utils.py | 0 {substra-backend => substrabackend}/substrapp/views/model.py | 0 {substra-backend => substrabackend}/substrapp/views/objective.py | 0 {substra-backend => substrabackend}/substrapp/views/task.py | 0 {substra-backend => substrabackend}/substrapp/views/testtuple.py | 0 {substra-backend => substrabackend}/substrapp/views/traintuple.py | 0 {substra-backend => substrabackend}/substrapp/views/utils.py | 0 176 files changed, 0 insertions(+), 0 deletions(-) rename {substra-backend => substrabackend}/.coveragerc (100%) rename {substra-backend => substrabackend}/events/__init__.py (100%) rename {substra-backend => substrabackend}/events/apps.py (100%) rename {substra-backend => substrabackend}/libs/SQLPrintingMiddleware.py (100%) rename {substra-backend => substrabackend}/libs/__init__.py (100%) rename {substra-backend => substrabackend}/libs/authentication.py (100%) rename {substra-backend => substrabackend}/libs/gen_secret_key.py (100%) rename {substra-backend => substrabackend}/libs/pagination.py (100%) rename {substra-backend => substrabackend}/libs/serializers.py (100%) rename {substra-backend => substrabackend}/libs/timestampModel.py (100%) rename {substra-backend => substrabackend}/libs/versioning.py (100%) rename {substra-backend => substrabackend}/manage.py (100%) rename {substra-backend => substrabackend}/node-register/__init__.py (100%) rename {substra-backend => substrabackend}/node-register/apps.py (100%) rename {substra-backend => substrabackend}/node/__init__.py (100%) rename {substra-backend => substrabackend}/node/apps.py (100%) rename {substra-backend => substrabackend}/node/authentication.py (100%) rename {substra-backend => substrabackend}/node/fixtures/nodes-chunantes.yaml (100%) rename {substra-backend => substrabackend}/node/fixtures/nodes-clb.yaml (100%) rename {substra-backend => substrabackend}/node/fixtures/nodes-owkin.yaml (100%) rename {substra-backend => substrabackend}/node/management/commands/create_incoming_node.py (100%) rename {substra-backend => substrabackend}/node/management/commands/create_outgoing_node.py (100%) rename {substra-backend => substrabackend}/node/management/commands/get_incoming_node.py (100%) rename {substra-backend => substrabackend}/node/management/commands/get_outgoing_node.py (100%) rename {substra-backend => substrabackend}/node/migrations/0001_initial.py (100%) rename {substra-backend => substrabackend}/node/migrations/0002_nodeuser.py (100%) rename {substra-backend => substrabackend}/node/migrations/__init__.py (100%) rename {substra-backend => substrabackend}/node/models.py (100%) rename {substra-backend => substrabackend}/node/signals/__init__.py (100%) rename {substra-backend => substrabackend}/node/signals/node/__init__.py (100%) rename {substra-backend => substrabackend}/node/signals/node/pre_save.py (100%) rename {substra-backend => substrabackend}/node/tests/__init__.py (100%) rename {substra-backend => substrabackend}/node/tests/views/__init__.py (100%) rename {substra-backend => substrabackend}/node/tests/views/tests_views_node.py (100%) rename {substra-backend => substrabackend}/node/urls.py (100%) rename {substra-backend => substrabackend}/node/views/__init__.py (100%) rename {substra-backend => substrabackend}/node/views/node.py (100%) rename {substra-backend => substrabackend}/requirements.txt (100%) rename {substra-backend => substrabackend}/substrabackend/__init__.py (100%) rename {substra-backend => substrabackend}/substrabackend/celery.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/__init__.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/common.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/deps/__init__.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/deps/cors.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/deps/ledger.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/deps/org.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/deps/raven.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/deps/restframework.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/dev.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/prod.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/server/__init__.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/server/dev.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/server/nobasicauth/__init__.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/server/nobasicauth/dev.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/server/nobasicauth/prod.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/server/prod.py (100%) rename {substra-backend => substrabackend}/substrabackend/settings/test.py (100%) rename {substra-backend => substrabackend}/substrabackend/urls.py (100%) rename {substra-backend => substrabackend}/substrabackend/views.py (100%) rename {substra-backend => substrabackend}/substrabackend/wsgi.py (100%) rename {substra-backend => substrabackend}/substrapp/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/admin.py (100%) rename {substra-backend => substrabackend}/substrapp/apps.py (100%) rename {substra-backend => substrabackend}/substrapp/ledger_utils.py (100%) rename {substra-backend => substrabackend}/substrapp/management/commands/bulkcreatedatasample.py (100%) rename {substra-backend => substrabackend}/substrapp/management/commands/createdataset.py (100%) rename {substra-backend => substrabackend}/substrapp/management/commands/createobjective.py (100%) rename {substra-backend => substrabackend}/substrapp/management/tests/tests_bulkcreatedatasample.py (100%) rename {substra-backend => substrabackend}/substrapp/management/tests/tests_createdatamanager.py (100%) rename {substra-backend => substrabackend}/substrapp/management/tests/tests_createobjective.py (100%) rename {substra-backend => substrabackend}/substrapp/management/utils/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/management/utils/localRequest.py (100%) rename {substra-backend => substrabackend}/substrapp/migrations/0001_initial.py (100%) rename {substra-backend => substrabackend}/substrapp/migrations/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/models/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/models/algo.py (100%) rename {substra-backend => substrabackend}/substrapp/models/datamanager.py (100%) rename {substra-backend => substrabackend}/substrapp/models/datasample.py (100%) rename {substra-backend => substrabackend}/substrapp/models/model.py (100%) rename {substra-backend => substrabackend}/substrapp/models/objective.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/algo.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/datamanager.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/datasample.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/algo/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/algo/serializer.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/algo/tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/algo/util.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/computeplan/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/computeplan/serializer.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/computeplan/tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/computeplan/util.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/datamanager/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/datamanager/serializer.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/datamanager/tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/datamanager/util.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/datasample/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/datasample/serializer.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/datasample/tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/datasample/util.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/model/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/model/serializer.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/objective/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/objective/serializer.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/objective/tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/objective/util.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/testtuple/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/testtuple/serializer.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/testtuple/tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/testtuple/util.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/traintuple/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/traintuple/serializer.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/traintuple/tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/traintuple/util.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/ledger/utils.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/model.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/objective.py (100%) rename {substra-backend => substrabackend}/substrapp/serializers/utils.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/algo/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/algo/post_delete.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/datamanager/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/datamanager/post_delete.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/datasample/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/datasample/post_delete.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/datasample/pre_save.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/model/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/model/post_delete.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/objective/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/signals/objective/post_delete.py (100%) rename {substra-backend => substrabackend}/substrapp/tasks/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/tasks/exception_handler.py (100%) rename {substra-backend => substrabackend}/substrapp/tasks/exceptions.json (100%) rename {substra-backend => substrabackend}/substrapp/tasks/tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/tasks/utils.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/assets.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/common.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/generate_assets.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/query/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/query/tests_query_algo.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/query/tests_query_datamanager.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/query/tests_query_datasample.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/query/tests_query_objective.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/query/tests_query_tuples.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/tests_exception.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/tests_misc.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/tests_model.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/tests_tasks.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/test_views_authentication.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_utils.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views_algo.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views_computeplan.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views_datamanager.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views_datasample.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views_model.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views_objective.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views_task.py (100%) rename {substra-backend => substrabackend}/substrapp/tests/views/tests_views_tuples.py (100%) rename {substra-backend => substrabackend}/substrapp/urls.py (100%) rename {substra-backend => substrabackend}/substrapp/utils.py (100%) rename {substra-backend => substrabackend}/substrapp/views/__init__.py (100%) rename {substra-backend => substrabackend}/substrapp/views/algo.py (100%) rename {substra-backend => substrabackend}/substrapp/views/computeplan.py (100%) rename {substra-backend => substrabackend}/substrapp/views/datamanager.py (100%) rename {substra-backend => substrabackend}/substrapp/views/datasample.py (100%) rename {substra-backend => substrabackend}/substrapp/views/filters_utils.py (100%) rename {substra-backend => substrabackend}/substrapp/views/model.py (100%) rename {substra-backend => substrabackend}/substrapp/views/objective.py (100%) rename {substra-backend => substrabackend}/substrapp/views/task.py (100%) rename {substra-backend => substrabackend}/substrapp/views/testtuple.py (100%) rename {substra-backend => substrabackend}/substrapp/views/traintuple.py (100%) rename {substra-backend => substrabackend}/substrapp/views/utils.py (100%) diff --git a/substra-backend/.coveragerc b/substrabackend/.coveragerc similarity index 100% rename from substra-backend/.coveragerc rename to substrabackend/.coveragerc diff --git a/substra-backend/events/__init__.py b/substrabackend/events/__init__.py similarity index 100% rename from substra-backend/events/__init__.py rename to substrabackend/events/__init__.py diff --git a/substra-backend/events/apps.py b/substrabackend/events/apps.py similarity index 100% rename from substra-backend/events/apps.py rename to substrabackend/events/apps.py diff --git a/substra-backend/libs/SQLPrintingMiddleware.py b/substrabackend/libs/SQLPrintingMiddleware.py similarity index 100% rename from substra-backend/libs/SQLPrintingMiddleware.py rename to substrabackend/libs/SQLPrintingMiddleware.py diff --git a/substra-backend/libs/__init__.py b/substrabackend/libs/__init__.py similarity index 100% rename from substra-backend/libs/__init__.py rename to substrabackend/libs/__init__.py diff --git a/substra-backend/libs/authentication.py b/substrabackend/libs/authentication.py similarity index 100% rename from substra-backend/libs/authentication.py rename to substrabackend/libs/authentication.py diff --git a/substra-backend/libs/gen_secret_key.py b/substrabackend/libs/gen_secret_key.py similarity index 100% rename from substra-backend/libs/gen_secret_key.py rename to substrabackend/libs/gen_secret_key.py diff --git a/substra-backend/libs/pagination.py b/substrabackend/libs/pagination.py similarity index 100% rename from substra-backend/libs/pagination.py rename to substrabackend/libs/pagination.py diff --git a/substra-backend/libs/serializers.py b/substrabackend/libs/serializers.py similarity index 100% rename from substra-backend/libs/serializers.py rename to substrabackend/libs/serializers.py diff --git a/substra-backend/libs/timestampModel.py b/substrabackend/libs/timestampModel.py similarity index 100% rename from substra-backend/libs/timestampModel.py rename to substrabackend/libs/timestampModel.py diff --git a/substra-backend/libs/versioning.py b/substrabackend/libs/versioning.py similarity index 100% rename from substra-backend/libs/versioning.py rename to substrabackend/libs/versioning.py diff --git a/substra-backend/manage.py b/substrabackend/manage.py similarity index 100% rename from substra-backend/manage.py rename to substrabackend/manage.py diff --git a/substra-backend/node-register/__init__.py b/substrabackend/node-register/__init__.py similarity index 100% rename from substra-backend/node-register/__init__.py rename to substrabackend/node-register/__init__.py diff --git a/substra-backend/node-register/apps.py b/substrabackend/node-register/apps.py similarity index 100% rename from substra-backend/node-register/apps.py rename to substrabackend/node-register/apps.py diff --git a/substra-backend/node/__init__.py b/substrabackend/node/__init__.py similarity index 100% rename from substra-backend/node/__init__.py rename to substrabackend/node/__init__.py diff --git a/substra-backend/node/apps.py b/substrabackend/node/apps.py similarity index 100% rename from substra-backend/node/apps.py rename to substrabackend/node/apps.py diff --git a/substra-backend/node/authentication.py b/substrabackend/node/authentication.py similarity index 100% rename from substra-backend/node/authentication.py rename to substrabackend/node/authentication.py diff --git a/substra-backend/node/fixtures/nodes-chunantes.yaml b/substrabackend/node/fixtures/nodes-chunantes.yaml similarity index 100% rename from substra-backend/node/fixtures/nodes-chunantes.yaml rename to substrabackend/node/fixtures/nodes-chunantes.yaml diff --git a/substra-backend/node/fixtures/nodes-clb.yaml b/substrabackend/node/fixtures/nodes-clb.yaml similarity index 100% rename from substra-backend/node/fixtures/nodes-clb.yaml rename to substrabackend/node/fixtures/nodes-clb.yaml diff --git a/substra-backend/node/fixtures/nodes-owkin.yaml b/substrabackend/node/fixtures/nodes-owkin.yaml similarity index 100% rename from substra-backend/node/fixtures/nodes-owkin.yaml rename to substrabackend/node/fixtures/nodes-owkin.yaml diff --git a/substra-backend/node/management/commands/create_incoming_node.py b/substrabackend/node/management/commands/create_incoming_node.py similarity index 100% rename from substra-backend/node/management/commands/create_incoming_node.py rename to substrabackend/node/management/commands/create_incoming_node.py diff --git a/substra-backend/node/management/commands/create_outgoing_node.py b/substrabackend/node/management/commands/create_outgoing_node.py similarity index 100% rename from substra-backend/node/management/commands/create_outgoing_node.py rename to substrabackend/node/management/commands/create_outgoing_node.py diff --git a/substra-backend/node/management/commands/get_incoming_node.py b/substrabackend/node/management/commands/get_incoming_node.py similarity index 100% rename from substra-backend/node/management/commands/get_incoming_node.py rename to substrabackend/node/management/commands/get_incoming_node.py diff --git a/substra-backend/node/management/commands/get_outgoing_node.py b/substrabackend/node/management/commands/get_outgoing_node.py similarity index 100% rename from substra-backend/node/management/commands/get_outgoing_node.py rename to substrabackend/node/management/commands/get_outgoing_node.py diff --git a/substra-backend/node/migrations/0001_initial.py b/substrabackend/node/migrations/0001_initial.py similarity index 100% rename from substra-backend/node/migrations/0001_initial.py rename to substrabackend/node/migrations/0001_initial.py diff --git a/substra-backend/node/migrations/0002_nodeuser.py b/substrabackend/node/migrations/0002_nodeuser.py similarity index 100% rename from substra-backend/node/migrations/0002_nodeuser.py rename to substrabackend/node/migrations/0002_nodeuser.py diff --git a/substra-backend/node/migrations/__init__.py b/substrabackend/node/migrations/__init__.py similarity index 100% rename from substra-backend/node/migrations/__init__.py rename to substrabackend/node/migrations/__init__.py diff --git a/substra-backend/node/models.py b/substrabackend/node/models.py similarity index 100% rename from substra-backend/node/models.py rename to substrabackend/node/models.py diff --git a/substra-backend/node/signals/__init__.py b/substrabackend/node/signals/__init__.py similarity index 100% rename from substra-backend/node/signals/__init__.py rename to substrabackend/node/signals/__init__.py diff --git a/substra-backend/node/signals/node/__init__.py b/substrabackend/node/signals/node/__init__.py similarity index 100% rename from substra-backend/node/signals/node/__init__.py rename to substrabackend/node/signals/node/__init__.py diff --git a/substra-backend/node/signals/node/pre_save.py b/substrabackend/node/signals/node/pre_save.py similarity index 100% rename from substra-backend/node/signals/node/pre_save.py rename to substrabackend/node/signals/node/pre_save.py diff --git a/substra-backend/node/tests/__init__.py b/substrabackend/node/tests/__init__.py similarity index 100% rename from substra-backend/node/tests/__init__.py rename to substrabackend/node/tests/__init__.py diff --git a/substra-backend/node/tests/views/__init__.py b/substrabackend/node/tests/views/__init__.py similarity index 100% rename from substra-backend/node/tests/views/__init__.py rename to substrabackend/node/tests/views/__init__.py diff --git a/substra-backend/node/tests/views/tests_views_node.py b/substrabackend/node/tests/views/tests_views_node.py similarity index 100% rename from substra-backend/node/tests/views/tests_views_node.py rename to substrabackend/node/tests/views/tests_views_node.py diff --git a/substra-backend/node/urls.py b/substrabackend/node/urls.py similarity index 100% rename from substra-backend/node/urls.py rename to substrabackend/node/urls.py diff --git a/substra-backend/node/views/__init__.py b/substrabackend/node/views/__init__.py similarity index 100% rename from substra-backend/node/views/__init__.py rename to substrabackend/node/views/__init__.py diff --git a/substra-backend/node/views/node.py b/substrabackend/node/views/node.py similarity index 100% rename from substra-backend/node/views/node.py rename to substrabackend/node/views/node.py diff --git a/substra-backend/requirements.txt b/substrabackend/requirements.txt similarity index 100% rename from substra-backend/requirements.txt rename to substrabackend/requirements.txt diff --git a/substra-backend/substrabackend/__init__.py b/substrabackend/substrabackend/__init__.py similarity index 100% rename from substra-backend/substrabackend/__init__.py rename to substrabackend/substrabackend/__init__.py diff --git a/substra-backend/substrabackend/celery.py b/substrabackend/substrabackend/celery.py similarity index 100% rename from substra-backend/substrabackend/celery.py rename to substrabackend/substrabackend/celery.py diff --git a/substra-backend/substrabackend/settings/__init__.py b/substrabackend/substrabackend/settings/__init__.py similarity index 100% rename from substra-backend/substrabackend/settings/__init__.py rename to substrabackend/substrabackend/settings/__init__.py diff --git a/substra-backend/substrabackend/settings/common.py b/substrabackend/substrabackend/settings/common.py similarity index 100% rename from substra-backend/substrabackend/settings/common.py rename to substrabackend/substrabackend/settings/common.py diff --git a/substra-backend/substrabackend/settings/deps/__init__.py b/substrabackend/substrabackend/settings/deps/__init__.py similarity index 100% rename from substra-backend/substrabackend/settings/deps/__init__.py rename to substrabackend/substrabackend/settings/deps/__init__.py diff --git a/substra-backend/substrabackend/settings/deps/cors.py b/substrabackend/substrabackend/settings/deps/cors.py similarity index 100% rename from substra-backend/substrabackend/settings/deps/cors.py rename to substrabackend/substrabackend/settings/deps/cors.py diff --git a/substra-backend/substrabackend/settings/deps/ledger.py b/substrabackend/substrabackend/settings/deps/ledger.py similarity index 100% rename from substra-backend/substrabackend/settings/deps/ledger.py rename to substrabackend/substrabackend/settings/deps/ledger.py diff --git a/substra-backend/substrabackend/settings/deps/org.py b/substrabackend/substrabackend/settings/deps/org.py similarity index 100% rename from substra-backend/substrabackend/settings/deps/org.py rename to substrabackend/substrabackend/settings/deps/org.py diff --git a/substra-backend/substrabackend/settings/deps/raven.py b/substrabackend/substrabackend/settings/deps/raven.py similarity index 100% rename from substra-backend/substrabackend/settings/deps/raven.py rename to substrabackend/substrabackend/settings/deps/raven.py diff --git a/substra-backend/substrabackend/settings/deps/restframework.py b/substrabackend/substrabackend/settings/deps/restframework.py similarity index 100% rename from substra-backend/substrabackend/settings/deps/restframework.py rename to substrabackend/substrabackend/settings/deps/restframework.py diff --git a/substra-backend/substrabackend/settings/dev.py b/substrabackend/substrabackend/settings/dev.py similarity index 100% rename from substra-backend/substrabackend/settings/dev.py rename to substrabackend/substrabackend/settings/dev.py diff --git a/substra-backend/substrabackend/settings/prod.py b/substrabackend/substrabackend/settings/prod.py similarity index 100% rename from substra-backend/substrabackend/settings/prod.py rename to substrabackend/substrabackend/settings/prod.py diff --git a/substra-backend/substrabackend/settings/server/__init__.py b/substrabackend/substrabackend/settings/server/__init__.py similarity index 100% rename from substra-backend/substrabackend/settings/server/__init__.py rename to substrabackend/substrabackend/settings/server/__init__.py diff --git a/substra-backend/substrabackend/settings/server/dev.py b/substrabackend/substrabackend/settings/server/dev.py similarity index 100% rename from substra-backend/substrabackend/settings/server/dev.py rename to substrabackend/substrabackend/settings/server/dev.py diff --git a/substra-backend/substrabackend/settings/server/nobasicauth/__init__.py b/substrabackend/substrabackend/settings/server/nobasicauth/__init__.py similarity index 100% rename from substra-backend/substrabackend/settings/server/nobasicauth/__init__.py rename to substrabackend/substrabackend/settings/server/nobasicauth/__init__.py diff --git a/substra-backend/substrabackend/settings/server/nobasicauth/dev.py b/substrabackend/substrabackend/settings/server/nobasicauth/dev.py similarity index 100% rename from substra-backend/substrabackend/settings/server/nobasicauth/dev.py rename to substrabackend/substrabackend/settings/server/nobasicauth/dev.py diff --git a/substra-backend/substrabackend/settings/server/nobasicauth/prod.py b/substrabackend/substrabackend/settings/server/nobasicauth/prod.py similarity index 100% rename from substra-backend/substrabackend/settings/server/nobasicauth/prod.py rename to substrabackend/substrabackend/settings/server/nobasicauth/prod.py diff --git a/substra-backend/substrabackend/settings/server/prod.py b/substrabackend/substrabackend/settings/server/prod.py similarity index 100% rename from substra-backend/substrabackend/settings/server/prod.py rename to substrabackend/substrabackend/settings/server/prod.py diff --git a/substra-backend/substrabackend/settings/test.py b/substrabackend/substrabackend/settings/test.py similarity index 100% rename from substra-backend/substrabackend/settings/test.py rename to substrabackend/substrabackend/settings/test.py diff --git a/substra-backend/substrabackend/urls.py b/substrabackend/substrabackend/urls.py similarity index 100% rename from substra-backend/substrabackend/urls.py rename to substrabackend/substrabackend/urls.py diff --git a/substra-backend/substrabackend/views.py b/substrabackend/substrabackend/views.py similarity index 100% rename from substra-backend/substrabackend/views.py rename to substrabackend/substrabackend/views.py diff --git a/substra-backend/substrabackend/wsgi.py b/substrabackend/substrabackend/wsgi.py similarity index 100% rename from substra-backend/substrabackend/wsgi.py rename to substrabackend/substrabackend/wsgi.py diff --git a/substra-backend/substrapp/__init__.py b/substrabackend/substrapp/__init__.py similarity index 100% rename from substra-backend/substrapp/__init__.py rename to substrabackend/substrapp/__init__.py diff --git a/substra-backend/substrapp/admin.py b/substrabackend/substrapp/admin.py similarity index 100% rename from substra-backend/substrapp/admin.py rename to substrabackend/substrapp/admin.py diff --git a/substra-backend/substrapp/apps.py b/substrabackend/substrapp/apps.py similarity index 100% rename from substra-backend/substrapp/apps.py rename to substrabackend/substrapp/apps.py diff --git a/substra-backend/substrapp/ledger_utils.py b/substrabackend/substrapp/ledger_utils.py similarity index 100% rename from substra-backend/substrapp/ledger_utils.py rename to substrabackend/substrapp/ledger_utils.py diff --git a/substra-backend/substrapp/management/commands/bulkcreatedatasample.py b/substrabackend/substrapp/management/commands/bulkcreatedatasample.py similarity index 100% rename from substra-backend/substrapp/management/commands/bulkcreatedatasample.py rename to substrabackend/substrapp/management/commands/bulkcreatedatasample.py diff --git a/substra-backend/substrapp/management/commands/createdataset.py b/substrabackend/substrapp/management/commands/createdataset.py similarity index 100% rename from substra-backend/substrapp/management/commands/createdataset.py rename to substrabackend/substrapp/management/commands/createdataset.py diff --git a/substra-backend/substrapp/management/commands/createobjective.py b/substrabackend/substrapp/management/commands/createobjective.py similarity index 100% rename from substra-backend/substrapp/management/commands/createobjective.py rename to substrabackend/substrapp/management/commands/createobjective.py diff --git a/substra-backend/substrapp/management/tests/tests_bulkcreatedatasample.py b/substrabackend/substrapp/management/tests/tests_bulkcreatedatasample.py similarity index 100% rename from substra-backend/substrapp/management/tests/tests_bulkcreatedatasample.py rename to substrabackend/substrapp/management/tests/tests_bulkcreatedatasample.py diff --git a/substra-backend/substrapp/management/tests/tests_createdatamanager.py b/substrabackend/substrapp/management/tests/tests_createdatamanager.py similarity index 100% rename from substra-backend/substrapp/management/tests/tests_createdatamanager.py rename to substrabackend/substrapp/management/tests/tests_createdatamanager.py diff --git a/substra-backend/substrapp/management/tests/tests_createobjective.py b/substrabackend/substrapp/management/tests/tests_createobjective.py similarity index 100% rename from substra-backend/substrapp/management/tests/tests_createobjective.py rename to substrabackend/substrapp/management/tests/tests_createobjective.py diff --git a/substra-backend/substrapp/management/utils/__init__.py b/substrabackend/substrapp/management/utils/__init__.py similarity index 100% rename from substra-backend/substrapp/management/utils/__init__.py rename to substrabackend/substrapp/management/utils/__init__.py diff --git a/substra-backend/substrapp/management/utils/localRequest.py b/substrabackend/substrapp/management/utils/localRequest.py similarity index 100% rename from substra-backend/substrapp/management/utils/localRequest.py rename to substrabackend/substrapp/management/utils/localRequest.py diff --git a/substra-backend/substrapp/migrations/0001_initial.py b/substrabackend/substrapp/migrations/0001_initial.py similarity index 100% rename from substra-backend/substrapp/migrations/0001_initial.py rename to substrabackend/substrapp/migrations/0001_initial.py diff --git a/substra-backend/substrapp/migrations/__init__.py b/substrabackend/substrapp/migrations/__init__.py similarity index 100% rename from substra-backend/substrapp/migrations/__init__.py rename to substrabackend/substrapp/migrations/__init__.py diff --git a/substra-backend/substrapp/models/__init__.py b/substrabackend/substrapp/models/__init__.py similarity index 100% rename from substra-backend/substrapp/models/__init__.py rename to substrabackend/substrapp/models/__init__.py diff --git a/substra-backend/substrapp/models/algo.py b/substrabackend/substrapp/models/algo.py similarity index 100% rename from substra-backend/substrapp/models/algo.py rename to substrabackend/substrapp/models/algo.py diff --git a/substra-backend/substrapp/models/datamanager.py b/substrabackend/substrapp/models/datamanager.py similarity index 100% rename from substra-backend/substrapp/models/datamanager.py rename to substrabackend/substrapp/models/datamanager.py diff --git a/substra-backend/substrapp/models/datasample.py b/substrabackend/substrapp/models/datasample.py similarity index 100% rename from substra-backend/substrapp/models/datasample.py rename to substrabackend/substrapp/models/datasample.py diff --git a/substra-backend/substrapp/models/model.py b/substrabackend/substrapp/models/model.py similarity index 100% rename from substra-backend/substrapp/models/model.py rename to substrabackend/substrapp/models/model.py diff --git a/substra-backend/substrapp/models/objective.py b/substrabackend/substrapp/models/objective.py similarity index 100% rename from substra-backend/substrapp/models/objective.py rename to substrabackend/substrapp/models/objective.py diff --git a/substra-backend/substrapp/serializers/__init__.py b/substrabackend/substrapp/serializers/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/__init__.py rename to substrabackend/substrapp/serializers/__init__.py diff --git a/substra-backend/substrapp/serializers/algo.py b/substrabackend/substrapp/serializers/algo.py similarity index 100% rename from substra-backend/substrapp/serializers/algo.py rename to substrabackend/substrapp/serializers/algo.py diff --git a/substra-backend/substrapp/serializers/datamanager.py b/substrabackend/substrapp/serializers/datamanager.py similarity index 100% rename from substra-backend/substrapp/serializers/datamanager.py rename to substrabackend/substrapp/serializers/datamanager.py diff --git a/substra-backend/substrapp/serializers/datasample.py b/substrabackend/substrapp/serializers/datasample.py similarity index 100% rename from substra-backend/substrapp/serializers/datasample.py rename to substrabackend/substrapp/serializers/datasample.py diff --git a/substra-backend/substrapp/serializers/ledger/__init__.py b/substrabackend/substrapp/serializers/ledger/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/__init__.py rename to substrabackend/substrapp/serializers/ledger/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/algo/__init__.py b/substrabackend/substrapp/serializers/ledger/algo/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/algo/__init__.py rename to substrabackend/substrapp/serializers/ledger/algo/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/algo/serializer.py b/substrabackend/substrapp/serializers/ledger/algo/serializer.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/algo/serializer.py rename to substrabackend/substrapp/serializers/ledger/algo/serializer.py diff --git a/substra-backend/substrapp/serializers/ledger/algo/tasks.py b/substrabackend/substrapp/serializers/ledger/algo/tasks.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/algo/tasks.py rename to substrabackend/substrapp/serializers/ledger/algo/tasks.py diff --git a/substra-backend/substrapp/serializers/ledger/algo/util.py b/substrabackend/substrapp/serializers/ledger/algo/util.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/algo/util.py rename to substrabackend/substrapp/serializers/ledger/algo/util.py diff --git a/substra-backend/substrapp/serializers/ledger/computeplan/__init__.py b/substrabackend/substrapp/serializers/ledger/computeplan/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/computeplan/__init__.py rename to substrabackend/substrapp/serializers/ledger/computeplan/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/computeplan/serializer.py b/substrabackend/substrapp/serializers/ledger/computeplan/serializer.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/computeplan/serializer.py rename to substrabackend/substrapp/serializers/ledger/computeplan/serializer.py diff --git a/substra-backend/substrapp/serializers/ledger/computeplan/tasks.py b/substrabackend/substrapp/serializers/ledger/computeplan/tasks.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/computeplan/tasks.py rename to substrabackend/substrapp/serializers/ledger/computeplan/tasks.py diff --git a/substra-backend/substrapp/serializers/ledger/computeplan/util.py b/substrabackend/substrapp/serializers/ledger/computeplan/util.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/computeplan/util.py rename to substrabackend/substrapp/serializers/ledger/computeplan/util.py diff --git a/substra-backend/substrapp/serializers/ledger/datamanager/__init__.py b/substrabackend/substrapp/serializers/ledger/datamanager/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/datamanager/__init__.py rename to substrabackend/substrapp/serializers/ledger/datamanager/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/datamanager/serializer.py b/substrabackend/substrapp/serializers/ledger/datamanager/serializer.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/datamanager/serializer.py rename to substrabackend/substrapp/serializers/ledger/datamanager/serializer.py diff --git a/substra-backend/substrapp/serializers/ledger/datamanager/tasks.py b/substrabackend/substrapp/serializers/ledger/datamanager/tasks.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/datamanager/tasks.py rename to substrabackend/substrapp/serializers/ledger/datamanager/tasks.py diff --git a/substra-backend/substrapp/serializers/ledger/datamanager/util.py b/substrabackend/substrapp/serializers/ledger/datamanager/util.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/datamanager/util.py rename to substrabackend/substrapp/serializers/ledger/datamanager/util.py diff --git a/substra-backend/substrapp/serializers/ledger/datasample/__init__.py b/substrabackend/substrapp/serializers/ledger/datasample/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/datasample/__init__.py rename to substrabackend/substrapp/serializers/ledger/datasample/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/datasample/serializer.py b/substrabackend/substrapp/serializers/ledger/datasample/serializer.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/datasample/serializer.py rename to substrabackend/substrapp/serializers/ledger/datasample/serializer.py diff --git a/substra-backend/substrapp/serializers/ledger/datasample/tasks.py b/substrabackend/substrapp/serializers/ledger/datasample/tasks.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/datasample/tasks.py rename to substrabackend/substrapp/serializers/ledger/datasample/tasks.py diff --git a/substra-backend/substrapp/serializers/ledger/datasample/util.py b/substrabackend/substrapp/serializers/ledger/datasample/util.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/datasample/util.py rename to substrabackend/substrapp/serializers/ledger/datasample/util.py diff --git a/substra-backend/substrapp/serializers/ledger/model/__init__.py b/substrabackend/substrapp/serializers/ledger/model/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/model/__init__.py rename to substrabackend/substrapp/serializers/ledger/model/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/model/serializer.py b/substrabackend/substrapp/serializers/ledger/model/serializer.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/model/serializer.py rename to substrabackend/substrapp/serializers/ledger/model/serializer.py diff --git a/substra-backend/substrapp/serializers/ledger/objective/__init__.py b/substrabackend/substrapp/serializers/ledger/objective/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/objective/__init__.py rename to substrabackend/substrapp/serializers/ledger/objective/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/objective/serializer.py b/substrabackend/substrapp/serializers/ledger/objective/serializer.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/objective/serializer.py rename to substrabackend/substrapp/serializers/ledger/objective/serializer.py diff --git a/substra-backend/substrapp/serializers/ledger/objective/tasks.py b/substrabackend/substrapp/serializers/ledger/objective/tasks.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/objective/tasks.py rename to substrabackend/substrapp/serializers/ledger/objective/tasks.py diff --git a/substra-backend/substrapp/serializers/ledger/objective/util.py b/substrabackend/substrapp/serializers/ledger/objective/util.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/objective/util.py rename to substrabackend/substrapp/serializers/ledger/objective/util.py diff --git a/substra-backend/substrapp/serializers/ledger/testtuple/__init__.py b/substrabackend/substrapp/serializers/ledger/testtuple/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/testtuple/__init__.py rename to substrabackend/substrapp/serializers/ledger/testtuple/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/testtuple/serializer.py b/substrabackend/substrapp/serializers/ledger/testtuple/serializer.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/testtuple/serializer.py rename to substrabackend/substrapp/serializers/ledger/testtuple/serializer.py diff --git a/substra-backend/substrapp/serializers/ledger/testtuple/tasks.py b/substrabackend/substrapp/serializers/ledger/testtuple/tasks.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/testtuple/tasks.py rename to substrabackend/substrapp/serializers/ledger/testtuple/tasks.py diff --git a/substra-backend/substrapp/serializers/ledger/testtuple/util.py b/substrabackend/substrapp/serializers/ledger/testtuple/util.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/testtuple/util.py rename to substrabackend/substrapp/serializers/ledger/testtuple/util.py diff --git a/substra-backend/substrapp/serializers/ledger/traintuple/__init__.py b/substrabackend/substrapp/serializers/ledger/traintuple/__init__.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/traintuple/__init__.py rename to substrabackend/substrapp/serializers/ledger/traintuple/__init__.py diff --git a/substra-backend/substrapp/serializers/ledger/traintuple/serializer.py b/substrabackend/substrapp/serializers/ledger/traintuple/serializer.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/traintuple/serializer.py rename to substrabackend/substrapp/serializers/ledger/traintuple/serializer.py diff --git a/substra-backend/substrapp/serializers/ledger/traintuple/tasks.py b/substrabackend/substrapp/serializers/ledger/traintuple/tasks.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/traintuple/tasks.py rename to substrabackend/substrapp/serializers/ledger/traintuple/tasks.py diff --git a/substra-backend/substrapp/serializers/ledger/traintuple/util.py b/substrabackend/substrapp/serializers/ledger/traintuple/util.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/traintuple/util.py rename to substrabackend/substrapp/serializers/ledger/traintuple/util.py diff --git a/substra-backend/substrapp/serializers/ledger/utils.py b/substrabackend/substrapp/serializers/ledger/utils.py similarity index 100% rename from substra-backend/substrapp/serializers/ledger/utils.py rename to substrabackend/substrapp/serializers/ledger/utils.py diff --git a/substra-backend/substrapp/serializers/model.py b/substrabackend/substrapp/serializers/model.py similarity index 100% rename from substra-backend/substrapp/serializers/model.py rename to substrabackend/substrapp/serializers/model.py diff --git a/substra-backend/substrapp/serializers/objective.py b/substrabackend/substrapp/serializers/objective.py similarity index 100% rename from substra-backend/substrapp/serializers/objective.py rename to substrabackend/substrapp/serializers/objective.py diff --git a/substra-backend/substrapp/serializers/utils.py b/substrabackend/substrapp/serializers/utils.py similarity index 100% rename from substra-backend/substrapp/serializers/utils.py rename to substrabackend/substrapp/serializers/utils.py diff --git a/substra-backend/substrapp/signals/__init__.py b/substrabackend/substrapp/signals/__init__.py similarity index 100% rename from substra-backend/substrapp/signals/__init__.py rename to substrabackend/substrapp/signals/__init__.py diff --git a/substra-backend/substrapp/signals/algo/__init__.py b/substrabackend/substrapp/signals/algo/__init__.py similarity index 100% rename from substra-backend/substrapp/signals/algo/__init__.py rename to substrabackend/substrapp/signals/algo/__init__.py diff --git a/substra-backend/substrapp/signals/algo/post_delete.py b/substrabackend/substrapp/signals/algo/post_delete.py similarity index 100% rename from substra-backend/substrapp/signals/algo/post_delete.py rename to substrabackend/substrapp/signals/algo/post_delete.py diff --git a/substra-backend/substrapp/signals/datamanager/__init__.py b/substrabackend/substrapp/signals/datamanager/__init__.py similarity index 100% rename from substra-backend/substrapp/signals/datamanager/__init__.py rename to substrabackend/substrapp/signals/datamanager/__init__.py diff --git a/substra-backend/substrapp/signals/datamanager/post_delete.py b/substrabackend/substrapp/signals/datamanager/post_delete.py similarity index 100% rename from substra-backend/substrapp/signals/datamanager/post_delete.py rename to substrabackend/substrapp/signals/datamanager/post_delete.py diff --git a/substra-backend/substrapp/signals/datasample/__init__.py b/substrabackend/substrapp/signals/datasample/__init__.py similarity index 100% rename from substra-backend/substrapp/signals/datasample/__init__.py rename to substrabackend/substrapp/signals/datasample/__init__.py diff --git a/substra-backend/substrapp/signals/datasample/post_delete.py b/substrabackend/substrapp/signals/datasample/post_delete.py similarity index 100% rename from substra-backend/substrapp/signals/datasample/post_delete.py rename to substrabackend/substrapp/signals/datasample/post_delete.py diff --git a/substra-backend/substrapp/signals/datasample/pre_save.py b/substrabackend/substrapp/signals/datasample/pre_save.py similarity index 100% rename from substra-backend/substrapp/signals/datasample/pre_save.py rename to substrabackend/substrapp/signals/datasample/pre_save.py diff --git a/substra-backend/substrapp/signals/model/__init__.py b/substrabackend/substrapp/signals/model/__init__.py similarity index 100% rename from substra-backend/substrapp/signals/model/__init__.py rename to substrabackend/substrapp/signals/model/__init__.py diff --git a/substra-backend/substrapp/signals/model/post_delete.py b/substrabackend/substrapp/signals/model/post_delete.py similarity index 100% rename from substra-backend/substrapp/signals/model/post_delete.py rename to substrabackend/substrapp/signals/model/post_delete.py diff --git a/substra-backend/substrapp/signals/objective/__init__.py b/substrabackend/substrapp/signals/objective/__init__.py similarity index 100% rename from substra-backend/substrapp/signals/objective/__init__.py rename to substrabackend/substrapp/signals/objective/__init__.py diff --git a/substra-backend/substrapp/signals/objective/post_delete.py b/substrabackend/substrapp/signals/objective/post_delete.py similarity index 100% rename from substra-backend/substrapp/signals/objective/post_delete.py rename to substrabackend/substrapp/signals/objective/post_delete.py diff --git a/substra-backend/substrapp/tasks/__init__.py b/substrabackend/substrapp/tasks/__init__.py similarity index 100% rename from substra-backend/substrapp/tasks/__init__.py rename to substrabackend/substrapp/tasks/__init__.py diff --git a/substra-backend/substrapp/tasks/exception_handler.py b/substrabackend/substrapp/tasks/exception_handler.py similarity index 100% rename from substra-backend/substrapp/tasks/exception_handler.py rename to substrabackend/substrapp/tasks/exception_handler.py diff --git a/substra-backend/substrapp/tasks/exceptions.json b/substrabackend/substrapp/tasks/exceptions.json similarity index 100% rename from substra-backend/substrapp/tasks/exceptions.json rename to substrabackend/substrapp/tasks/exceptions.json diff --git a/substra-backend/substrapp/tasks/tasks.py b/substrabackend/substrapp/tasks/tasks.py similarity index 100% rename from substra-backend/substrapp/tasks/tasks.py rename to substrabackend/substrapp/tasks/tasks.py diff --git a/substra-backend/substrapp/tasks/utils.py b/substrabackend/substrapp/tasks/utils.py similarity index 100% rename from substra-backend/substrapp/tasks/utils.py rename to substrabackend/substrapp/tasks/utils.py diff --git a/substra-backend/substrapp/tests/__init__.py b/substrabackend/substrapp/tests/__init__.py similarity index 100% rename from substra-backend/substrapp/tests/__init__.py rename to substrabackend/substrapp/tests/__init__.py diff --git a/substra-backend/substrapp/tests/assets.py b/substrabackend/substrapp/tests/assets.py similarity index 100% rename from substra-backend/substrapp/tests/assets.py rename to substrabackend/substrapp/tests/assets.py diff --git a/substra-backend/substrapp/tests/common.py b/substrabackend/substrapp/tests/common.py similarity index 100% rename from substra-backend/substrapp/tests/common.py rename to substrabackend/substrapp/tests/common.py diff --git a/substra-backend/substrapp/tests/generate_assets.py b/substrabackend/substrapp/tests/generate_assets.py similarity index 100% rename from substra-backend/substrapp/tests/generate_assets.py rename to substrabackend/substrapp/tests/generate_assets.py diff --git a/substra-backend/substrapp/tests/query/__init__.py b/substrabackend/substrapp/tests/query/__init__.py similarity index 100% rename from substra-backend/substrapp/tests/query/__init__.py rename to substrabackend/substrapp/tests/query/__init__.py diff --git a/substra-backend/substrapp/tests/query/tests_query_algo.py b/substrabackend/substrapp/tests/query/tests_query_algo.py similarity index 100% rename from substra-backend/substrapp/tests/query/tests_query_algo.py rename to substrabackend/substrapp/tests/query/tests_query_algo.py diff --git a/substra-backend/substrapp/tests/query/tests_query_datamanager.py b/substrabackend/substrapp/tests/query/tests_query_datamanager.py similarity index 100% rename from substra-backend/substrapp/tests/query/tests_query_datamanager.py rename to substrabackend/substrapp/tests/query/tests_query_datamanager.py diff --git a/substra-backend/substrapp/tests/query/tests_query_datasample.py b/substrabackend/substrapp/tests/query/tests_query_datasample.py similarity index 100% rename from substra-backend/substrapp/tests/query/tests_query_datasample.py rename to substrabackend/substrapp/tests/query/tests_query_datasample.py diff --git a/substra-backend/substrapp/tests/query/tests_query_objective.py b/substrabackend/substrapp/tests/query/tests_query_objective.py similarity index 100% rename from substra-backend/substrapp/tests/query/tests_query_objective.py rename to substrabackend/substrapp/tests/query/tests_query_objective.py diff --git a/substra-backend/substrapp/tests/query/tests_query_tuples.py b/substrabackend/substrapp/tests/query/tests_query_tuples.py similarity index 100% rename from substra-backend/substrapp/tests/query/tests_query_tuples.py rename to substrabackend/substrapp/tests/query/tests_query_tuples.py diff --git a/substra-backend/substrapp/tests/tests_exception.py b/substrabackend/substrapp/tests/tests_exception.py similarity index 100% rename from substra-backend/substrapp/tests/tests_exception.py rename to substrabackend/substrapp/tests/tests_exception.py diff --git a/substra-backend/substrapp/tests/tests_misc.py b/substrabackend/substrapp/tests/tests_misc.py similarity index 100% rename from substra-backend/substrapp/tests/tests_misc.py rename to substrabackend/substrapp/tests/tests_misc.py diff --git a/substra-backend/substrapp/tests/tests_model.py b/substrabackend/substrapp/tests/tests_model.py similarity index 100% rename from substra-backend/substrapp/tests/tests_model.py rename to substrabackend/substrapp/tests/tests_model.py diff --git a/substra-backend/substrapp/tests/tests_tasks.py b/substrabackend/substrapp/tests/tests_tasks.py similarity index 100% rename from substra-backend/substrapp/tests/tests_tasks.py rename to substrabackend/substrapp/tests/tests_tasks.py diff --git a/substra-backend/substrapp/tests/views/__init__.py b/substrabackend/substrapp/tests/views/__init__.py similarity index 100% rename from substra-backend/substrapp/tests/views/__init__.py rename to substrabackend/substrapp/tests/views/__init__.py diff --git a/substra-backend/substrapp/tests/views/test_views_authentication.py b/substrabackend/substrapp/tests/views/test_views_authentication.py similarity index 100% rename from substra-backend/substrapp/tests/views/test_views_authentication.py rename to substrabackend/substrapp/tests/views/test_views_authentication.py diff --git a/substra-backend/substrapp/tests/views/tests_utils.py b/substrabackend/substrapp/tests/views/tests_utils.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_utils.py rename to substrabackend/substrapp/tests/views/tests_utils.py diff --git a/substra-backend/substrapp/tests/views/tests_views.py b/substrabackend/substrapp/tests/views/tests_views.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views.py rename to substrabackend/substrapp/tests/views/tests_views.py diff --git a/substra-backend/substrapp/tests/views/tests_views_algo.py b/substrabackend/substrapp/tests/views/tests_views_algo.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views_algo.py rename to substrabackend/substrapp/tests/views/tests_views_algo.py diff --git a/substra-backend/substrapp/tests/views/tests_views_computeplan.py b/substrabackend/substrapp/tests/views/tests_views_computeplan.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views_computeplan.py rename to substrabackend/substrapp/tests/views/tests_views_computeplan.py diff --git a/substra-backend/substrapp/tests/views/tests_views_datamanager.py b/substrabackend/substrapp/tests/views/tests_views_datamanager.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views_datamanager.py rename to substrabackend/substrapp/tests/views/tests_views_datamanager.py diff --git a/substra-backend/substrapp/tests/views/tests_views_datasample.py b/substrabackend/substrapp/tests/views/tests_views_datasample.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views_datasample.py rename to substrabackend/substrapp/tests/views/tests_views_datasample.py diff --git a/substra-backend/substrapp/tests/views/tests_views_model.py b/substrabackend/substrapp/tests/views/tests_views_model.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views_model.py rename to substrabackend/substrapp/tests/views/tests_views_model.py diff --git a/substra-backend/substrapp/tests/views/tests_views_objective.py b/substrabackend/substrapp/tests/views/tests_views_objective.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views_objective.py rename to substrabackend/substrapp/tests/views/tests_views_objective.py diff --git a/substra-backend/substrapp/tests/views/tests_views_task.py b/substrabackend/substrapp/tests/views/tests_views_task.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views_task.py rename to substrabackend/substrapp/tests/views/tests_views_task.py diff --git a/substra-backend/substrapp/tests/views/tests_views_tuples.py b/substrabackend/substrapp/tests/views/tests_views_tuples.py similarity index 100% rename from substra-backend/substrapp/tests/views/tests_views_tuples.py rename to substrabackend/substrapp/tests/views/tests_views_tuples.py diff --git a/substra-backend/substrapp/urls.py b/substrabackend/substrapp/urls.py similarity index 100% rename from substra-backend/substrapp/urls.py rename to substrabackend/substrapp/urls.py diff --git a/substra-backend/substrapp/utils.py b/substrabackend/substrapp/utils.py similarity index 100% rename from substra-backend/substrapp/utils.py rename to substrabackend/substrapp/utils.py diff --git a/substra-backend/substrapp/views/__init__.py b/substrabackend/substrapp/views/__init__.py similarity index 100% rename from substra-backend/substrapp/views/__init__.py rename to substrabackend/substrapp/views/__init__.py diff --git a/substra-backend/substrapp/views/algo.py b/substrabackend/substrapp/views/algo.py similarity index 100% rename from substra-backend/substrapp/views/algo.py rename to substrabackend/substrapp/views/algo.py diff --git a/substra-backend/substrapp/views/computeplan.py b/substrabackend/substrapp/views/computeplan.py similarity index 100% rename from substra-backend/substrapp/views/computeplan.py rename to substrabackend/substrapp/views/computeplan.py diff --git a/substra-backend/substrapp/views/datamanager.py b/substrabackend/substrapp/views/datamanager.py similarity index 100% rename from substra-backend/substrapp/views/datamanager.py rename to substrabackend/substrapp/views/datamanager.py diff --git a/substra-backend/substrapp/views/datasample.py b/substrabackend/substrapp/views/datasample.py similarity index 100% rename from substra-backend/substrapp/views/datasample.py rename to substrabackend/substrapp/views/datasample.py diff --git a/substra-backend/substrapp/views/filters_utils.py b/substrabackend/substrapp/views/filters_utils.py similarity index 100% rename from substra-backend/substrapp/views/filters_utils.py rename to substrabackend/substrapp/views/filters_utils.py diff --git a/substra-backend/substrapp/views/model.py b/substrabackend/substrapp/views/model.py similarity index 100% rename from substra-backend/substrapp/views/model.py rename to substrabackend/substrapp/views/model.py diff --git a/substra-backend/substrapp/views/objective.py b/substrabackend/substrapp/views/objective.py similarity index 100% rename from substra-backend/substrapp/views/objective.py rename to substrabackend/substrapp/views/objective.py diff --git a/substra-backend/substrapp/views/task.py b/substrabackend/substrapp/views/task.py similarity index 100% rename from substra-backend/substrapp/views/task.py rename to substrabackend/substrapp/views/task.py diff --git a/substra-backend/substrapp/views/testtuple.py b/substrabackend/substrapp/views/testtuple.py similarity index 100% rename from substra-backend/substrapp/views/testtuple.py rename to substrabackend/substrapp/views/testtuple.py diff --git a/substra-backend/substrapp/views/traintuple.py b/substrabackend/substrapp/views/traintuple.py similarity index 100% rename from substra-backend/substrapp/views/traintuple.py rename to substrabackend/substrapp/views/traintuple.py diff --git a/substra-backend/substrapp/views/utils.py b/substrabackend/substrapp/views/utils.py similarity index 100% rename from substra-backend/substrapp/views/utils.py rename to substrabackend/substrapp/views/utils.py From 08f714326bce7877da1c26349c212a8f7172c891 Mon Sep 17 00:00:00 2001 From: inalgnu Date: Fri, 18 Oct 2019 17:57:20 +0200 Subject: [PATCH 366/457] step1 --- .flake8 | 8 ++++---- Jenkinsfile | 20 ++++++++++---------- README.md | 6 +++--- docker/substra-backend/Dockerfile | 20 ++++++++++++++++++++ docker/substrabac/Dockerfile | 20 -------------------- skaffold.yaml | 14 +++++++------- substrabackend/manage.py | 2 +- 7 files changed, 45 insertions(+), 45 deletions(-) create mode 100644 docker/substra-backend/Dockerfile delete mode 100644 docker/substrabac/Dockerfile diff --git a/.flake8 b/.flake8 index 36cc911aa..b40fbc9e5 100644 --- a/.flake8 +++ b/.flake8 @@ -1,8 +1,8 @@ [flake8] max-line-length = 120 ignore = E402, W504, F403, F405 -exclude = substrabac/substrapp/migrations/*, - substrabac/substrapp/tests/assets.py, - substrabac/substrabac/settings/*, - substrabac/node/migrations/*, +exclude = substrabackend/substrapp/migrations/*, + substrabackend/substrapp/tests/assets.py, + substrabackend/substrabackend/settings/*, + substrabackend/node/migrations/*, .env, .venv diff --git a/Jenkinsfile b/Jenkinsfile index f6330dfd6..f78d81747 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -27,14 +27,14 @@ pipeline { stage('Test Helm') { agent { kubernetes { - label 'substrabac-helm' + label 'substra-backend-helm' defaultContainer 'helm' yamlFile '.cicd/agent-helm.yaml' } } steps { - sh "helm lint charts/substrabac" + sh "helm lint charts/substra-backend" } } @@ -53,11 +53,11 @@ pipeline { sh "docker login -u _json_key --password-stdin https://eu.gcr.io/substra-208412/ < /secret/kaniko-secret.json" sh "apt install -y python3-pip python3-dev build-essential gfortran musl-dev postgresql-contrib git curl netcat" - dir("substrabac") { + dir("substra-backend") { sh "pip install flake8" sh "flake8" sh "pip install -r requirements.txt" - sh "DJANGO_SETTINGS_MODULE=substrabac.settings.test coverage run manage.py test" + sh "DJANGO_SETTINGS_MODULE=substrabackend.settings.test coverage run manage.py test" sh "coverage report" sh "coverage html" } @@ -69,7 +69,7 @@ pipeline { allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true, - reportDir: 'substrabac/htmlcov', + reportDir: 'substra-backend/htmlcov', reportFiles: 'index.html', reportName: 'Coverage Report' ] @@ -77,10 +77,10 @@ pipeline { } } - stage('Build substrabac') { + stage('Build substra-backend') { agent { kubernetes { - label 'substrabac-kaniko-substrabac' + label 'substra-backend-kaniko-substrabackend' yamlFile '.cicd/agent-kaniko.yaml' } } @@ -88,7 +88,7 @@ pipeline { steps { container(name:'kaniko', shell:'/busybox/sh') { sh '''#!/busybox/sh - /kaniko/executor -f `pwd`/docker/substrabac/Dockerfile -c `pwd` -d "eu.gcr.io/substra-208412/substrabac:$GIT_COMMIT" + /kaniko/executor -f `pwd`/docker/substra-backend/Dockerfile -c `pwd` -d "eu.gcr.io/substra-208412/substra-backend:$GIT_COMMIT" ''' } } @@ -131,7 +131,7 @@ pipeline { stage('Publish Helm') { agent { kubernetes { - label 'substrabac-helm' + label 'substra-backend-helm' defaultContainer 'helm' yamlFile '.cicd/agent-helm.yaml' } @@ -143,7 +143,7 @@ pipeline { sh "helm init --client-only" sh "helm plugin install https://github.com/chartmuseum/helm-push" sh "helm repo add substra https://substra-charts.owkin.com --username owlways --password Cokear4nnRK9ooC" - sh "helm push charts/substrabac substra || true" + sh "helm push charts/substra-backend substra || true" } } } diff --git a/README.md b/README.md index 4698a4c71..4756a7d62 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -# Substrabac +# Substra-Backend Backend of the Substra platform ## Version -You will note substrabac use a versioned REST API with the header protocol. +You will note substra-backend use a versioned REST API with the header protocol. Current is `0.0`. ## Getting started 1: Prepare the django app 1. Clone the repo: ``` - git clone https://github.com/SubstraFoundation/substrabac + git clone https://github.com/SubstraFoundation/substra-backend ``` 2. :warning: Do this step only if your environment development is on linux. On linux systems, all the docker instances create files with `root` permissions. diff --git a/docker/substra-backend/Dockerfile b/docker/substra-backend/Dockerfile new file mode 100644 index 000000000..97499ccc9 --- /dev/null +++ b/docker/substra-backend/Dockerfile @@ -0,0 +1,20 @@ +FROM python:3.6 + +RUN apt-get update +RUN apt-get install -y python3 python3-pip python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev g++ gcc gfortran musl-dev postgresql-contrib +RUN apt-get install -y git curl netcat + +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +COPY ./substrabackend/requirements.txt /usr/src/app/. + +RUN pip3 install -r requirements.txt + +COPY ./substrabackend/manage.py /usr/src/app/manage.py +COPY ./substrabackend/libs /usr/src/app/libs +COPY ./substrabackend/substrapp /usr/src/app/substrapp +COPY ./substrabackend/events /usr/src/app/events +COPY ./substrabackend/substrabackend /usr/src/app/substrabackend +COPY ./substrabackend/node /usr/src/app/node +COPY ./substrabackend/node-register /usr/src/app/node-register diff --git a/docker/substrabac/Dockerfile b/docker/substrabac/Dockerfile deleted file mode 100644 index b09ed78de..000000000 --- a/docker/substrabac/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM python:3.6 - -RUN apt-get update -RUN apt-get install -y python3 python3-pip python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev g++ gcc gfortran musl-dev postgresql-contrib -RUN apt-get install -y git curl netcat - -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app - -COPY ./substrabac/requirements.txt /usr/src/app/. - -RUN pip3 install -r requirements.txt - -COPY ./substrabac/manage.py /usr/src/app/manage.py -COPY ./substrabac/libs /usr/src/app/libs -COPY ./substrabac/substrapp /usr/src/app/substrapp -COPY ./substrabac/events /usr/src/app/events -COPY ./substrabac/substrabac /usr/src/app/substrabac -COPY ./substrabac/node /usr/src/app/node -COPY ./substrabac/node-register /usr/src/app/node-register diff --git a/skaffold.yaml b/skaffold.yaml index d51c2481b..f7f623199 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -9,7 +9,7 @@ build: - image: eu.gcr.io/substra-208412/substra-backend context: . docker: - dockerfile: docker/substrabac/Dockerfile + dockerfile: docker/substra-backend/Dockerfile - image: eu.gcr.io/substra-208412/celerybeat context: . @@ -30,7 +30,7 @@ deploy: helm: releases: - name: substra-backend-peer-1 - chartPath: charts/substrabac + chartPath: charts/substra-backend namespace: peer-1 imageStrategy: helm: {} @@ -46,11 +46,11 @@ deploy: image: tag: latest settings: dev - defaultDomain: http://substrabac.node-1 + defaultDomain: http://substra-backend.node-1 ingress: enabled: true hosts: - - { host: substrabac.node-1, paths: ["/"] } + - { host: substra-backend.node-1, paths: ["/"] } annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/client-body-buffer-size: 100m @@ -85,7 +85,7 @@ deploy: - { name: MyPeer2MSP, secret: nodeSecret1 } - name: substra-backend-peer-2 - chartPath: charts/substrabac + chartPath: charts/substra-backend namespace: peer-2 imageStrategy: helm: {} @@ -101,11 +101,11 @@ deploy: image: tag: latest settings: dev - defaultDomain: http://substrabac.node-2 + defaultDomain: http://substra-backend.node-2 ingress: enabled: true hosts: - - { host: substrabac.node-2, paths: ["/"] } + - { host: substra-backend.node-2, paths: ["/"] } annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/client-body-buffer-size: 100m diff --git a/substrabackend/manage.py b/substrabackend/manage.py index 570add98a..44c612146 100755 --- a/substrabackend/manage.py +++ b/substrabackend/manage.py @@ -3,7 +3,7 @@ import sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "substrabac.settings.dev") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "substrabackend.settings.dev") try: from django.core.management import execute_from_command_line except ImportError as exc: From 7ab5e3c26a004b30a10d75a0b2f24ad0ce0184cd Mon Sep 17 00:00:00 2001 From: inalgnu Date: Fri, 18 Oct 2019 18:23:42 +0200 Subject: [PATCH 367/457] step2 --- Jenkinsfile | 6 +- README.md | 60 +++++++++---------- .../templates/deployment-backend.yaml | 10 ++-- .../templates/deployment-celerybeat.yaml | 4 +- .../templates/deployment-flower.yaml | 4 +- .../templates/deployment-scheduler.yaml | 8 +-- .../templates/deployment-worker.yaml | 8 +-- .../templates/job-add-incoming-nodes.yaml | 8 +-- .../templates/job-add-outgoing-nodes.yaml | 8 +-- charts/substra-backend/values.yaml | 2 +- docker/celerybeat/Dockerfile | 10 ++-- docker/celeryworker/Dockerfile | 10 ++-- docker/flower/Dockerfile | 10 ++-- docker/postgresql/init.sh | 12 ++-- docker/start.py | 48 +++++++-------- populate.py | 14 ++--- scripts/clean_media_local.sh | 2 +- scripts/generate_nodes_fixtures.py | 2 +- scripts/recreate_db.sh | 24 ++++---- substrabackend/substrabackend/celery.py | 4 +- .../substrabackend/settings/common.py | 6 +- .../substrabackend/settings/deps/ledger.py | 4 +- substrabackend/substrabackend/settings/dev.py | 8 +-- .../substrabackend/settings/prod.py | 10 ++-- 24 files changed, 141 insertions(+), 141 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f78d81747..96747cfa7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -41,7 +41,7 @@ pipeline { stage('Test') { agent { kubernetes { - label 'substrabac-test' + label 'substra-backend-test' defaultContainer 'python' yamlFile '.cicd/agent-python.yaml' } @@ -97,7 +97,7 @@ pipeline { stage('Build celerybeat') { agent { kubernetes { - label 'substrabac-kaniko-celerybeat' + label 'substra-backend-kaniko-celerybeat' yamlFile '.cicd/agent-kaniko.yaml' } } @@ -114,7 +114,7 @@ pipeline { stage('Build celeryworker') { agent { kubernetes { - label 'substrabac-kaniko-celeryworker' + label 'substra-backend-kaniko-celeryworker' yamlFile '.cicd/agent-kaniko.yaml' } } diff --git a/README.md b/README.md index 4756a7d62..064148364 100644 --- a/README.md +++ b/README.md @@ -64,14 +64,14 @@ Do not forget to build the substra-model image as described in the step 9 of thi ```shell $> sudo su postgres $> psql - $ CREATE USER substrabac WITH PASSWORD 'substrabac' CREATEDB CREATEROLE SUPERUSER; + $ CREATE USER substrabackend WITH PASSWORD 'substrabackend' CREATEDB CREATEROLE SUPERUSER; ``` 6. Create two databases for both orgs: owkin and chu-nantes. A shell script is available, do not hesitate to run it. -It will drop the databases if they are already created, then create them and grant all privileges to your main user substrabac. +It will drop the databases if they are already created, then create them and grant all privileges to your main user substrabackend. (If this is the first time you create the databases, you will see some warnings which are pointless): ```shell - $> ./substrabac/scripts/recreate_db.sh + $> ./scripts/recreate_db.sh ``` 7. We will populate data: @@ -79,8 +79,8 @@ It will drop the databases if they are already created, then create them and gra - With django migrations ```shell -SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python substrabac/manage.py migrate --settings=substrabac.settings.dev -SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python substrabac/manage.py migrate --settings=substrabac.settings.dev +SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python substrabackend/manage.py migrate --settings=substrabackend.settings.dev +SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python substrabackend/manage.py migrate --settings=substrabackend.settings.dev ``` ###### With fixtures (fixtures container has been run from substra-network, old behavior for testing) @@ -90,32 +90,32 @@ data in fixtures are relative to the data already set in the ledger if the fixtu Two solutions: - With django migrations + load data ```shell -SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python substrabac/manage.py migrate --settings=substrabac.settings.dev -SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python substrabac/manage.py migrate --settings=substrabac.settings.dev -SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python substrabac/manage.py loaddata ./fixtures/data_owkin.json --settings=substrabac.settings.dev -SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python substrabac/manage.py loaddata ./fixtures/data_chu-nantes.json --settings=substrabac.settings.dev +SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python substrabackend/manage.py migrate --settings=substrabackend.settings.dev +SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python substrabackend/manage.py migrate --settings=substrabackend.settings.dev +SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python substrabackend/manage.py loaddata ./fixtures/data_owkin.json --settings=substrabackend.settings.dev +SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python substrabackend/manage.py loaddata ./fixtures/data_chu-nantes.json --settings=substrabackend.settings.dev ``` - From dumps: ```shell - $> ./substrabac/scripts/populate_db.sh + $> ./scripts/populate_db.sh ``` If you don't want to replicate the data in the ledger, simply run the django migrations. Populate media files ```shell - $> ./substrabac/scripts/load_fixtures.sh + $> ./scripts/load_fixtures.sh ``` It will clean the `medias` folders and create the `owkin` and `chu-nantes` folders in the `medias` folder. 8. Optional: Create a superuser in your databases: ``` -SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python substrabac/manage.py createsuperuser --settings=substrabac.settings.dev -SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python substrabac/manage.py createsuperuser --settings=substrabac.settings.dev +SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python substrabackend/manage.py createsuperuser --settings=substrabackend.settings.dev +SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python substrabackend/manage.py createsuperuser --settings=substrabackend.settings.dev ``` 9. Build the substra-model docker image: -Clone the following git repo https://github.com/SubstraFoundation/substratools and build the docker image +Clone the following git repo https://github.com/SubstraFoundation/substra-tools and build the docker image ``` docker build -t substra-model . ``` @@ -135,32 +135,32 @@ sudo apt-get install rabbitmq-server ### Launch celery workers/scheduler and celery beat -Execute this command in the `substrabac/substrabac` folder. +Execute this command in the `substrabackend/substrabackend` folder. Note the use of the development settings. ```shell -DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 celery -E -A substrabac worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler -DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 celery -E -A substrabac worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker -DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 celery -E -A substrabac worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler -DJANGO_SETTINGS_MODULE=substrabac.settings.dev SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 celery -E -A substrabac worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker -DJANGO_SETTINGS_MODULE=substrabac.settings.common celery -A substrabac beat -l info +DJANGO_SETTINGS_MODULE=substrabackend.settings.dev SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 celery -E -A substrabackend worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler +DJANGO_SETTINGS_MODULE=substrabackend.settings.dev SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 celery -E -A substrabackend worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker +DJANGO_SETTINGS_MODULE=substrabackend.settings.dev SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 celery -E -A substrabackend worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler +DJANGO_SETTINGS_MODULE=substrabackend.settings.dev SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 celery -E -A substrabackend worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker +DJANGO_SETTINGS_MODULE=substrabackend.settings.common celery -A substrabackend beat -l info ``` ## Launch the servers -Go in the `substrabac` folder and run the server locally: +Go in the `substrabackend` folder and run the server locally: :warning:

      Be very careful, --settings is different here, `server` is needed.

      ``` - SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.server.dev - SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.server.dev + SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabackend.settings.server.dev + SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabackend.settings.server.dev ``` If you want to bypass the basic authentication when you browse the server on localhost:8000 or localhost:8001, you can use the `nobasicauth` settings. Simply replace `server.dev` by `nobasicauth`, like: ``` - SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabac.settings.server.nobasicauth - SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabac.settings.server.nobasicauth + SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabackend.settings.server.nobasicauth + SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabackend.settings.server.nobasicauth ``` It allows the substrafront project to work correctly too. @@ -168,14 +168,14 @@ Go in the `substrabac` folder and run the server locally: For working with node to node authentication, you need load some extra fixtures ``` -SUBSTRABAC_ORG=owkin SUBSTRABAC_DEFAULT_PORT=8000 python manage.py loaddata nodes-owkin.yaml --settings=substrabac.settings.server.dev -SUBSTRABAC_ORG=chu-nantes SUBSTRABAC_DEFAULT_PORT=8001 python manage.py loaddata nodes-chunantes.yaml --settings=substrabac.settings.server.dev +SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python manage.py loaddata nodes-owkin.yaml --settings=substrabackend.settings.server.dev +SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python manage.py loaddata nodes-chunantes.yaml --settings=substrabackend.settings.server.dev ``` ## Test with unit and functional tests ``` - DJANGO_SETTINGS_MODULE=substrabac.settings.test coverage run manage.py test + DJANGO_SETTINGS_MODULE=substrabackend.settings.test coverage run manage.py test coverage report # For shell report coverage html # For HTML report ``` @@ -195,7 +195,7 @@ When you want to re-run the testing process: - Rerun `recreate_db.sh` and `clean_media.sh` scripts. - Run the django migrations. - Relaunch your substra-network. -- Run the owkin and chunantes substrabac servers. +- Run the owkin and chunantes substra-backend servers. - Run celery beat and celery owkin and chu-nantes. - Run the `populate.py` python script. @@ -265,7 +265,7 @@ Use these configurations for easier debugging and productivity: Do not hesitate to put breakpoints in your code. Even with periodic celery tasks and hit the `bug` button for launching your pre configurations. -You can even access directly to the databases (password is `substrabac` as described in the beginning of this document): +You can even access directly to the databases (password is `substrabackend` as described in the beginning of this document): ![](assets/database_owkin.png) ![](assets/database_owkin_challenges.png) diff --git a/charts/substra-backend/templates/deployment-backend.yaml b/charts/substra-backend/templates/deployment-backend.yaml index 7fa6e3e7a..7d1ae5e46 100644 --- a/charts/substra-backend/templates/deployment-backend.yaml +++ b/charts/substra-backend/templates/deployment-backend.yaml @@ -37,9 +37,9 @@ spec: {{- end }} command: ["/bin/bash"] {{- if eq .Values.backend.settings "prod" }} - args: ["-c", "python manage.py migrate; python3 manage.py collectstatic --noinput; uwsgi --http :8000 --module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=substrabac.settings.server.{{ .Values.backend.settings }} "] + args: ["-c", "python manage.py migrate; python3 manage.py collectstatic --noinput; uwsgi --http :8000 --module substrabackend.wsgi --static-map /static=/usr/src/app/substrabackend/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=substrabackend.settings.server.{{ .Values.backend.settings }} "] {{- else }} - args: ["-c", "python manage.py migrate; DJANGO_SETTINGS_MODULE=substrabac.settings.server.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] + args: ["-c", "python manage.py migrate; DJANGO_SETTINGS_MODULE=substrabackend.settings.server.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] {{- end }} env: - name: ORG @@ -55,7 +55,7 @@ spec: - name: DATABASE_HOST value: {{ .Release.Name }}-postgresql - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.{{ .Values.backend.settings }} + value: substrabackend.settings.{{ .Values.backend.settings }} - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric_cfg - name: CORE_PEER_ADDRESS_ENV @@ -82,7 +82,7 @@ spec: - name: SUBSTRABAC_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/substrabac/conf.json + value: /conf/{{ .Values.organization.name }}/substrabackend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -94,7 +94,7 @@ spec: volumeMounts: - mountPath: {{ .Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ .Values.organization.name }}/substrabac + - mountPath: /conf/{{ .Values.organization.name }}/substrabackend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substra-backend/templates/deployment-celerybeat.yaml b/charts/substra-backend/templates/deployment-celerybeat.yaml index 147ce810d..15abb78a0 100644 --- a/charts/substra-backend/templates/deployment-celerybeat.yaml +++ b/charts/substra-backend/templates/deployment-celerybeat.yaml @@ -36,12 +36,12 @@ spec: imagePullPolicy: "{{ .Values.celerybeat.image.pullPolicy }}" {{- end }} command: ["celery"] - args: ["-A", "substrabac", "beat", "-l", "debug"] + args: ["-A", "substrabackend", "beat", "-l", "debug"] env: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.common + value: substrabackend.settings.common - name: PYTHONUNBUFFERED value: "1" resources: diff --git a/charts/substra-backend/templates/deployment-flower.yaml b/charts/substra-backend/templates/deployment-flower.yaml index b7a67c6c7..f01378339 100644 --- a/charts/substra-backend/templates/deployment-flower.yaml +++ b/charts/substra-backend/templates/deployment-flower.yaml @@ -37,12 +37,12 @@ spec: imagePullPolicy: "{{ .Values.flower.image.pullPolicy }}" {{- end }} command: ["celery"] - args: ["flower", "-A", "substrabac"] + args: ["flower", "-A", "substrabackend"] env: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.common + value: substrabackend.settings.common - name: PYTHONUNBUFFERED value: "1" resources: diff --git a/charts/substra-backend/templates/deployment-scheduler.yaml b/charts/substra-backend/templates/deployment-scheduler.yaml index 91ed1a9f0..60e0abafd 100644 --- a/charts/substra-backend/templates/deployment-scheduler.yaml +++ b/charts/substra-backend/templates/deployment-scheduler.yaml @@ -36,7 +36,7 @@ spec: imagePullPolicy: "{{ .Values.celeryworker.image.pullPolicy }}" {{- end }} command: ["celery"] - args: ["-A", "substrabac", "worker", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},scheduler,celery", "--hostname", "{{ .Values.organization.name }}.scheduler"] + args: ["-A", "substrabackend", "worker", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},scheduler,celery", "--hostname", "{{ .Values.organization.name }}.scheduler"] env: - name: ORG value: {{ .Values.organization.name }} @@ -47,7 +47,7 @@ spec: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.{{ .Values.backend.settings }} + value: substrabackend.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" {{- with .Values.backend.auth }} @@ -70,9 +70,9 @@ spec: - name: FABRIC_LOGGING_SPEC value: debug - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/substrabac/conf.json + value: /conf/{{ .Values.organization.name }}/substrabackend/conf.json volumeMounts: - - mountPath: /conf/{{ .Values.organization.name }}/substrabac + - mountPath: /conf/{{ .Values.organization.name }}/substrabackend name: config readOnly: true - mountPath: /var/hyperledger/msp/signcerts diff --git a/charts/substra-backend/templates/deployment-worker.yaml b/charts/substra-backend/templates/deployment-worker.yaml index 4e3b0a543..2d592d26b 100644 --- a/charts/substra-backend/templates/deployment-worker.yaml +++ b/charts/substra-backend/templates/deployment-worker.yaml @@ -36,7 +36,7 @@ spec: imagePullPolicy: "{{ .Values.celeryworker.image.pullPolicy }}" {{- end }} command: ["celery"] - args: ["-A", "substrabac", "worker", "-E", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},{{ .Values.organization.name }}.worker,celery", "--hostname", "{{ .Values.organization.name }}.worker"] + args: ["-A", "substrabackend", "worker", "-E", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},{{ .Values.organization.name }}.worker,celery", "--hostname", "{{ .Values.organization.name }}.worker"] env: - name: ORG value: {{ .Values.organization.name }} @@ -47,7 +47,7 @@ spec: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.{{ .Values.backend.settings }} + value: substrabackend.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" {{- with .Values.backend.auth }} @@ -80,13 +80,13 @@ spec: - name: MEDIA_ROOT value: {{ .Values.persistence.hostPath }}/medias/ - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/substrabac/conf.json + value: /conf/{{ .Values.organization.name }}/substrabackend/conf.json volumeMounts: - mountPath: /var/run/docker.sock name: dockersocket - mountPath: {{ .Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ .Values.organization.name }}/substrabac + - mountPath: /conf/{{ .Values.organization.name }}/substrabackend name: config readOnly: true - mountPath: /var/hyperledger/msp/signcerts diff --git a/charts/substra-backend/templates/job-add-incoming-nodes.yaml b/charts/substra-backend/templates/job-add-incoming-nodes.yaml index 650a0401a..658c14cdb 100644 --- a/charts/substra-backend/templates/job-add-incoming-nodes.yaml +++ b/charts/substra-backend/templates/job-add-incoming-nodes.yaml @@ -24,7 +24,7 @@ spec: {{- end }} {{- end }} containers: - - name: substrabac + - name: substra-backend image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" command: ["python3"] @@ -43,7 +43,7 @@ spec: - name: DATABASE_HOST value: {{ $.Release.Name }}-postgresql - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.{{ $.Values.backend.settings }} + value: substrabackend.settings.{{ $.Values.backend.settings }} - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric_cfg - name: CORE_PEER_ADDRESS_ENV @@ -63,7 +63,7 @@ spec: - name: SUBSTRABAC_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ $.Values.organization.name }}/substrabac/conf.json + value: /conf/{{ $.Values.organization.name }}/substrabackend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -71,7 +71,7 @@ spec: volumeMounts: - mountPath: {{ $.Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ $.Values.organization.name }}/substrabac + - mountPath: /conf/{{ $.Values.organization.name }}/substrabackend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substra-backend/templates/job-add-outgoing-nodes.yaml b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml index 29f6521e2..a519ba1c9 100644 --- a/charts/substra-backend/templates/job-add-outgoing-nodes.yaml +++ b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml @@ -24,7 +24,7 @@ spec: {{- end }} {{- end }} containers: - - name: substrabac + - name: substra-backend image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" command: ["python3"] @@ -43,7 +43,7 @@ spec: - name: DATABASE_HOST value: {{ $.Release.Name }}-postgresql - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.{{ $.Values.backend.settings }} + value: substrabackend.settings.{{ $.Values.backend.settings }} - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric_cfg - name: CORE_PEER_ADDRESS_ENV @@ -63,7 +63,7 @@ spec: - name: SUBSTRABAC_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ $.Values.organization.name }}/substrabac/conf.json + value: /conf/{{ $.Values.organization.name }}/substrabackend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -71,7 +71,7 @@ spec: volumeMounts: - mountPath: {{ $.Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ $.Values.organization.name }}/substrabac + - mountPath: /conf/{{ $.Values.organization.name }}/substrabackend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substra-backend/values.yaml b/charts/substra-backend/values.yaml index acbd6109b..402841ea6 100644 --- a/charts/substra-backend/values.yaml +++ b/charts/substra-backend/values.yaml @@ -21,7 +21,7 @@ backend: defaultDomain: localhost image: - repository: eu.gcr.io/substra-208412/substrabac + repository: eu.gcr.io/substra-208412/substra-backend tag: latest pullPolicy: IfNotPresent pullSecrets: [] diff --git a/docker/celerybeat/Dockerfile b/docker/celerybeat/Dockerfile index 43c5f85ea..a2435a281 100644 --- a/docker/celerybeat/Dockerfile +++ b/docker/celerybeat/Dockerfile @@ -7,11 +7,11 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./substrabac/requirements.txt /usr/src/app/. +COPY ./substrabackend/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt -COPY ./substrabac/libs /usr/src/app/libs -COPY ./substrabac/substrapp /usr/src/app/substrapp -COPY ./substrabac/substrabac /usr/src/app/substrabac -COPY ./substrabac/node /usr/src/app/node +COPY ./substrabackend/libs /usr/src/app/libs +COPY ./substrabackend/substrapp /usr/src/app/substrapp +COPY ./substrabackend/substrabackend /usr/src/app/substrabackend +COPY ./substrabackend/node /usr/src/app/node diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index fbc05f4c3..238b13cc1 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -7,11 +7,11 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./substrabac/requirements.txt /usr/src/app/. +COPY ./substrabackend/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt -COPY ./substrabac/libs /usr/src/app/libs -COPY ./substrabac/substrapp /usr/src/app/substrapp -COPY ./substrabac/substrabac /usr/src/app/substrabac -COPY ./substrabac/node /usr/src/app/node +COPY ./substrabackend/libs /usr/src/app/libs +COPY ./substrabackend/substrapp /usr/src/app/substrapp +COPY ./substrabackend/substrabackend /usr/src/app/substrabackend +COPY ./substrabackend/node /usr/src/app/node diff --git a/docker/flower/Dockerfile b/docker/flower/Dockerfile index f5eb80fa7..d2d9f1824 100644 --- a/docker/flower/Dockerfile +++ b/docker/flower/Dockerfile @@ -7,12 +7,12 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./substrabac/requirements.txt /usr/src/app/. +COPY ./substrabackend/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt RUN pip3 install flower -COPY ./substrabac/libs /usr/src/app/libs -COPY ./substrabac/substrapp /usr/src/app/substrapp -COPY ./substrabac/substrabac /usr/src/app/substrabac -COPY ./substrabac/node /usr/src/app/node +COPY ./substrabackend/libs /usr/src/app/libs +COPY ./substrabackend/substrapp /usr/src/app/substrapp +COPY ./substrabackend/substrabackend /usr/src/app/substrabackend +COPY ./substrabackend/node /usr/src/app/node diff --git a/docker/postgresql/init.sh b/docker/postgresql/init.sh index 92590b661..109ea9170 100644 --- a/docker/postgresql/init.sh +++ b/docker/postgresql/init.sh @@ -1,11 +1,11 @@ #!/bin/bash -createdb -U ${USER} -E UTF8 substrabac_owkin -psql -U ${USER} -d substrabac_owkin -c "GRANT ALL PRIVILEGES ON DATABASE substrabac_owkin to substrabac;ALTER ROLE substrabac WITH SUPERUSER CREATEROLE CREATEDB;" +createdb -U ${USER} -E UTF8 substrabackend_owkin +psql -U ${USER} -d substrabackend_owkin -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_owkin to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" -createdb -U ${USER} -E UTF8 substrabac_chunantes -psql -U ${USER} -d substrabac_chunantes -c "GRANT ALL PRIVILEGES ON DATABASE substrabac_chunantes to substrabac;ALTER ROLE substrabac WITH SUPERUSER CREATEROLE CREATEDB;" +createdb -U ${USER} -E UTF8 substrabackend_chunantes +psql -U ${USER} -d substrabackend_chunantes -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_chunantes to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" -createdb -U ${USER} -E UTF8 substrabac_clb -psql -U ${USER} -d substrabac_clb -c "GRANT ALL PRIVILEGES ON DATABASE substrabac_clb to substrabac;ALTER ROLE substrabac WITH SUPERUSER CREATEROLE CREATEDB;" +createdb -U ${USER} -E UTF8 substrabackend_clb +psql -U ${USER} -d substrabackend_clb -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_clb to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" diff --git a/docker/start.py b/docker/start.py index a74f3e39f..ee7f75278 100644 --- a/docker/start.py +++ b/docker/start.py @@ -25,10 +25,10 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): # POSTGRES - POSTGRES_USER = 'substrabac' - USER = 'substrabac' - POSTGRES_PASSWORD = 'substrabac' - POSTGRES_DB = 'substrabac' + POSTGRES_USER = 'substrabackend' + USER = 'substrabackend' + POSTGRES_PASSWORD = 'substrabackend' + POSTGRES_DB = 'substrabackend' # RABBITMQ RABBITMQ_DEFAULT_USER = 'guest' @@ -73,12 +73,12 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'image': 'substra/celerybeat', 'restart': 'unless-stopped', 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - 'celery -A substrabac beat -l info"', + 'celery -A substrabackend beat -l info"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': [ 'PYTHONUNBUFFERED=1', f'CELERY_BROKER_URL={CELERY_BROKER_URL}', - f'DJANGO_SETTINGS_MODULE=substrabac.settings.common'], + f'DJANGO_SETTINGS_MODULE=substrabackend.settings.common'], 'depends_on': ['postgresql', 'rabbit'] }, 'rabbit': { @@ -102,10 +102,10 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'ports': ['5555:5555'], 'image': 'substra/flower', 'restart': 'unless-stopped', - 'command': 'celery flower -A substrabac', + 'command': 'celery flower -A substrabackend', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': [f'CELERY_BROKER_URL={CELERY_BROKER_URL}', - 'DJANGO_SETTINGS_MODULE=substrabac.settings.common'], + 'DJANGO_SETTINGS_MODULE=substrabackend.settings.common'], 'depends_on': ['rabbit', 'postgresql'] } }, @@ -122,13 +122,13 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): if launch_settings == 'prod': django_server = f'python3 manage.py collectstatic --noinput; '\ - f'--module substrabac.wsgi --static-map /static=/usr/src/app/substrabac/statics ' \ + f'--module substrabackend.wsgi --static-map /static=/usr/src/app/substrabackend/statics ' \ f'--master --processes {processes} --threads 2 --need-app' \ - f'--env DJANGO_SETTINGS_MODULE=substrabac.settings.server.prod uwsgi --http :{port} ' + f'--env DJANGO_SETTINGS_MODULE=substrabackend.settings.server.prod uwsgi --http :{port} ' else: print('nobasicauth: ', nobasicauth, flush=True) extra_settings = '.nobasicauth' if nobasicauth is True else '' - django_server = f'DJANGO_SETTINGS_MODULE=substrabac.settings.server{extra_settings}.dev ' \ + django_server = f'DJANGO_SETTINGS_MODULE=substrabackend.settings.server{extra_settings}.dev ' \ f'python3 manage.py runserver --noreload 0.0.0.0:{port}' backend_global_env = [ @@ -137,7 +137,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f'SUBSTRABAC_DEFAULT_PORT={port}', 'SUBSTRABAC_PEER_PORT=internal', - f'LEDGER_CONFIG_FILE={SUBSTRA_FOLDER}/conf/{org_name}/substrabac/conf.json', + f'LEDGER_CONFIG_FILE={SUBSTRA_FOLDER}/conf/{org_name}/substrabackend/conf.json', 'PYTHONUNBUFFERED=1', 'DATABASE_HOST=postgresql', @@ -147,7 +147,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f"TASK_CACHE_DOCKER_IMAGES=False", f'CELERY_BROKER_URL={CELERY_BROKER_URL}', - f'DJANGO_SETTINGS_MODULE=substrabac.settings.{launch_settings}', + f'DJANGO_SETTINGS_MODULE=substrabackend.settings.{launch_settings}', # Basic auth f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', 'admin')}", @@ -157,7 +157,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): ] hlf_volumes = [ - # config (core.yaml + substrabac/conf.json) + # config (core.yaml + substrabackend/conf.json) f'{SUBSTRA_FOLDER}/conf/{org_name}:{SUBSTRA_FOLDER}/conf/{org_name}:ro', # HLF files @@ -174,9 +174,9 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): fixtures_command = f"python manage.py loaddata nodes-{org_name_stripped}" backend = { - 'container_name': f'{org_name_stripped}.substrabac', + 'container_name': f'{org_name_stripped}.substra-backend', 'labels': ['substra'], - 'image': 'substra/substrabac', + 'image': 'substra/substra-backend', 'restart': 'unless-stopped', 'ports': [f'{port}:{port}'], 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' @@ -186,7 +186,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'volumes': [ f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias:rw', f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro', - f'{SUBSTRA_FOLDER}/static:/usr/src/app/substrabac/statics'] + hlf_volumes, + f'{SUBSTRA_FOLDER}/static:/usr/src/app/substrabackend/statics'] + hlf_volumes, 'depends_on': ['postgresql', 'rabbit']} scheduler = { @@ -196,12 +196,12 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'image': 'substra/celeryworker', 'restart': 'unless-stopped', 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - f'celery -A substrabac worker -l info -n {org_name_stripped} ' + f'celery -A substrabackend worker -l info -n {org_name_stripped} ' f'-Q {org_name},scheduler,celery --hostname {org_name}.scheduler"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), 'volumes': hlf_volumes, - 'depends_on': [f'substrabac{org_name_stripped}', 'postgresql', 'rabbit']} + 'depends_on': [f'substrabackend{org_name_stripped}', 'postgresql', 'rabbit']} worker = { 'container_name': f'{org_name_stripped}.worker', @@ -210,7 +210,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'image': 'substra/celeryworker', 'restart': 'unless-stopped', 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - f'celery -A substrabac worker -l info -n {org_name_stripped} ' + f'celery -A substrabackend worker -l info -n {org_name_stripped} ' f'-Q {org_name},{org_name}.worker,celery --hostname {org_name}.worker"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), @@ -218,7 +218,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): '/var/run/docker.sock:/var/run/docker.sock', f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias:rw', f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro'] + hlf_volumes, - 'depends_on': [f'substrabac{org_name_stripped}', 'rabbit']} + 'depends_on': [f'substrabackend{org_name_stripped}', 'rabbit']} # Check if we have nvidia docker if 'nvidia' in check_output(['docker', 'system', 'info', '-f', '"{{.Runtimes}}"']).decode('utf-8'): @@ -238,7 +238,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): scheduler['environment'].append(f"RAVEN_URL={raven_scheduler_url}") worker['environment'].append(f"RAVEN_URL={raven_worker_url}") - docker_compose['substrabac_services']['substrabac' + org_name_stripped] = backend + docker_compose['substrabac_services']['substrabackend' + org_name_stripped] = backend docker_compose['substrabac_services']['scheduler' + org_name_stripped] = scheduler docker_compose['substrabac_services']['worker' + org_name_stripped] = worker # Create all services along to conf @@ -308,9 +308,9 @@ def start(conf, launch_settings, no_backup, nobasicauth=False): no_backup = args['no_backup'] - conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/substrabac/conf.json')] + conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/substrabackend/conf.json')] - print('Build substrabac for : ', flush=True) + print('Build substrabackend for : ', flush=True) print(' Organizations :', flush=True) for org in conf: print(' -', org['name'], flush=True) diff --git a/populate.py b/populate.py index 5944c4272..cb77c63d1 100644 --- a/populate.py +++ b/populate.py @@ -27,21 +27,21 @@ def setup_config(network='docker'): - print('Init config in /tmp/.substrabac for owkin and chunantes') + print('Init config in /tmp/.substrabackend for owkin and chunantes') if network == 'docker': - client.add_profile('owkin', 'http://owkin.substrabac:8000', '0.0', + client.add_profile('owkin', 'http://owkin.substra-backend:8000', '0.0', user=USER, password=PASSWORD) - client.add_profile('chunantes', 'http://chunantes.substrabac:8001', '0.0', + client.add_profile('chunantes', 'http://chunantes.substra-backend:8001', '0.0', user=USER, password=PASSWORD) - client.add_profile('clb', 'http://clb.substrabac:8002', '0.0', + client.add_profile('clb', 'http://clb.substra-backend:8002', '0.0', user=USER, password=PASSWORD) if network == 'skaffold': # the usernames and passwords are defined in the skaffold.yaml file - client.add_profile('owkin', 'http://substrabac.node-1', '0.0', + client.add_profile('owkin', 'http://substra-backend.node-1', '0.0', user='node-1', password='node-1pwd') - client.add_profile('chunantes', 'http://substrabac.node-2', '0.0', + client.add_profile('chunantes', 'http://substra-backend.node-2', '0.0', user='node-2', password='node-2pwd') - client.add_profile('clb', 'http://substrabac.node-3', '0.0', + client.add_profile('clb', 'http://substra-backend.node-3', '0.0', user='node-3', password='node-3pwd') diff --git a/scripts/clean_media_local.sh b/scripts/clean_media_local.sh index c510a598d..9315322c6 100755 --- a/scripts/clean_media_local.sh +++ b/scripts/clean_media_local.sh @@ -4,4 +4,4 @@ BASEDIR="$(dirname $(dirname $0))" echo $BASEDIR # clean medias -rm -rf ${BASEDIR}/substrabac/medias/* +rm -rf ${BASEDIR}/substrabackend/medias/* diff --git a/scripts/generate_nodes_fixtures.py b/scripts/generate_nodes_fixtures.py index 83ff08938..92dfe51c8 100644 --- a/scripts/generate_nodes_fixtures.py +++ b/scripts/generate_nodes_fixtures.py @@ -60,7 +60,7 @@ def create_fixture(node_credentials): print(json.dumps(network_credentials, sort_keys=True, indent=4)) # create fixture files - fixtures_path = 'substrabac/node/fixtures' + fixtures_path = 'substrabackend/node/fixtures' try: os.makedirs(fixtures_path) except OSError: diff --git a/scripts/recreate_db.sh b/scripts/recreate_db.sh index 718684aa2..90a7d8553 100755 --- a/scripts/recreate_db.sh +++ b/scripts/recreate_db.sh @@ -1,17 +1,17 @@ #!/bin/bash -dropdb -U ${USER} substrabac -createdb -U ${USER} -E UTF8 substrabac -psql -U ${USER} -d substrabac -c "CREATE USER substrabac WITH PASSWORD 'substrabac' CREATEDB CREATEROLE SUPERUSER;" +dropdb -U ${USER} substrabackend +createdb -U ${USER} -E UTF8 substrabackend +psql -U ${USER} -d substrabackend -c "CREATE USER substrabackend WITH PASSWORD 'substrabackend' CREATEDB CREATEROLE SUPERUSER;" -dropdb -U ${USER} substrabac_owkin -createdb -U ${USER} -E UTF8 substrabac_owkin -psql -U ${USER} -d substrabac_owkin -c "GRANT ALL PRIVILEGES ON DATABASE substrabac_owkin to substrabac;ALTER ROLE substrabac WITH SUPERUSER CREATEROLE CREATEDB;" +dropdb -U ${USER} substrabackend_owkin +createdb -U ${USER} -E UTF8 substrabackend_owkin +psql -U ${USER} -d substrabackend_owkin -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_owkin to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" -dropdb -U ${USER} substrabac_chunantes -createdb -U ${USER} -E UTF8 substrabac_chunantes -psql -U ${USER} -d substrabac_chunantes -c "GRANT ALL PRIVILEGES ON DATABASE substrabac_chunantes to substrabac;ALTER ROLE substrabac WITH SUPERUSER CREATEROLE CREATEDB;" +dropdb -U ${USER} substrabackend_chunantes +createdb -U ${USER} -E UTF8 substrabackend_chunantes +psql -U ${USER} -d substrabackend_chunantes -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_chunantes to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" -dropdb -U ${USER} substrabac_clb -createdb -U ${USER} -E UTF8 substrabac_clb -psql -U ${USER} -d substrabac_clb -c "GRANT ALL PRIVILEGES ON DATABASE substrabac_chunantes to substrabac;ALTER ROLE substrabac WITH SUPERUSER CREATEROLE CREATEDB;" +dropdb -U ${USER} substrabackend_clb +createdb -U ${USER} -E UTF8 substrabackend_clb +psql -U ${USER} -d substrabackend_clb -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_chunantes to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" diff --git a/substrabackend/substrabackend/celery.py b/substrabackend/substrabackend/celery.py index d2a4c459f..68ec95929 100644 --- a/substrabackend/substrabackend/celery.py +++ b/substrabackend/substrabackend/celery.py @@ -5,9 +5,9 @@ from celery.signals import after_task_publish # set the default Django settings module for the 'celery' program. -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'substrabac.settings.prod') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'substrabackend.settings.prod') -app = Celery('substrabac') +app = Celery('substrabackend') # Using a string here means the worker doesn't have to serialize # the configuration object to child processes. diff --git a/substrabackend/substrabackend/settings/common.py b/substrabackend/substrabackend/settings/common.py index 799aca2b7..7a9b10307 100644 --- a/substrabackend/substrabackend/settings/common.py +++ b/substrabackend/substrabackend/settings/common.py @@ -1,5 +1,5 @@ """ -Django settings for substrabac project. +Django settings for substrabackend project. Generated by 'django-admin startproject' using Django 2.0.5. @@ -80,7 +80,7 @@ 'libs.SQLPrintingMiddleware.SQLPrintingMiddleware', ] -ROOT_URLCONF = 'substrabac.urls' +ROOT_URLCONF = 'substrabackend.urls' TEMPLATES = [ { @@ -98,7 +98,7 @@ }, ] -WSGI_APPLICATION = 'substrabac.wsgi.application' +WSGI_APPLICATION = 'substrabackend.wsgi.application' # Database # https://docs.djangoproject.com/en/1.9/ref/settings/#databases diff --git a/substrabackend/substrabackend/settings/deps/ledger.py b/substrabackend/substrabackend/settings/deps/ledger.py index dfe8f2b74..cf79134a8 100644 --- a/substrabackend/substrabackend/settings/deps/ledger.py +++ b/substrabackend/substrabackend/settings/deps/ledger.py @@ -16,7 +16,7 @@ from hfc.fabric.block_decoder import decode_fabric_MSP_config, decode_fabric_peers_info, decode_fabric_endpoints -LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/substrabac/conf.json') +LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/substrabackend/conf.json') LEDGER = json.load(open(LEDGER_CONFIG_FILE, 'r')) LEDGER_SYNC_ENABLED = True @@ -41,7 +41,7 @@ def get_hfc_client(): client = Client() - # Add peer from substrabac ledger config file + # Add peer from substrabackend ledger config file peer = Peer(name=LEDGER['peer']['name']) peer.init_with_bundle({ 'url': f'{LEDGER["peer"]["host"]}:{PEER_PORT}', diff --git a/substrabackend/substrabackend/settings/dev.py b/substrabackend/substrabackend/settings/dev.py index 61ffd3840..2388cf385 100644 --- a/substrabackend/substrabackend/settings/dev.py +++ b/substrabackend/substrabackend/settings/dev.py @@ -27,8 +27,8 @@ 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': os.environ.get(f'SUBSTRABAC_{ORG_DB_NAME}_DB_NAME', f'substrabac_{ORG_NAME}'), - 'USER': os.environ.get('SUBSTRABAC_DB_USER', 'substrabac'), - 'PASSWORD': os.environ.get('SUBSTRABAC_DB_PWD', 'substrabac'), + 'USER': os.environ.get('SUBSTRABAC_DB_USER', 'substrabackend'), + 'PASSWORD': os.environ.get('SUBSTRABAC_DB_PWD', 'substrabackend'), 'HOST': os.environ.get('DATABASE_HOST', 'localhost'), 'PORT': 5432, } @@ -37,7 +37,7 @@ MEDIA_ROOT = os.environ.get('MEDIA_ROOT', os.path.join(PROJECT_ROOT, f'medias/{ORG_NAME}')) -SITE_HOST = f'{ORG_NAME}.substrabac' +SITE_HOST = f'{ORG_NAME}.substrabackend' SITE_PORT = DEFAULT_PORT DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') @@ -70,7 +70,7 @@ }, 'error_file': { 'level': 'INFO', - 'filename': os.path.join(PROJECT_ROOT, 'substrabac.log'), + 'filename': os.path.join(PROJECT_ROOT, 'substrabackend.log'), 'class': 'logging.handlers.RotatingFileHandler', 'maxBytes': 1 * 1024 * 1024, 'backupCount': 2, diff --git a/substrabackend/substrabackend/settings/prod.py b/substrabackend/substrabackend/settings/prod.py index 17b3f2973..2cd88984c 100644 --- a/substrabackend/substrabackend/settings/prod.py +++ b/substrabackend/substrabackend/settings/prod.py @@ -34,15 +34,15 @@ 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': os.environ.get(f'SUBSTRABAC_{ORG_DB_NAME}_DB_NAME', f'substrabac_{ORG_NAME}'), - 'USER': os.environ.get('SUBSTRABAC_DB_USER', 'substrabac'), - 'PASSWORD': os.environ.get('SUBSTRABAC_DB_PWD', 'substrabac'), + 'USER': os.environ.get('SUBSTRABAC_DB_USER', 'substrabackend'), + 'PASSWORD': os.environ.get('SUBSTRABAC_DB_PWD', 'substrabackend'), 'HOST': os.environ.get('DATABASE_HOST', 'localhost'), 'PORT': 5432, } } MEDIA_ROOT = os.environ.get('MEDIA_ROOT', f'/substra/medias/{ORG_NAME}') -SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substrabac') +SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substrabackend') SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') @@ -77,12 +77,12 @@ 'error_file': { 'class': 'logging.FileHandler', 'formatter': 'generic', - 'filename': '/var/log/substrabac.error.log', + 'filename': '/var/log/substra-backend.error.log', }, 'access_file': { 'class': 'logging.FileHandler', 'formatter': 'generic', - 'filename': '/var/log/substrabac.access.log', + 'filename': '/var/log/substra-backend.access.log', }, }, 'loggers': { From bb91be2aaec5eb160f15bad47cb497536d7842b2 Mon Sep 17 00:00:00 2001 From: inalgnu Date: Fri, 18 Oct 2019 18:34:07 +0200 Subject: [PATCH 368/457] step 3 --- .../templates/deployment-backend.yaml | 12 +++++----- .../templates/deployment-scheduler.yaml | 4 ++-- .../templates/deployment-worker.yaml | 10 ++++----- .../templates/job-add-incoming-nodes.yaml | 12 +++++----- .../templates/job-add-outgoing-nodes.yaml | 12 +++++----- docker/start.py | 22 +++++++++---------- scripts/populate_db.sh | 4 ++-- substrabackend/events/apps.py | 2 +- .../substrabackend/settings/deps/ledger.py | 4 ++-- .../substrabackend/settings/deps/org.py | 4 ++-- substrabackend/substrabackend/settings/dev.py | 6 ++--- .../substrabackend/settings/prod.py | 6 ++--- substrabackend/substrabackend/views.py | 2 +- 13 files changed, 50 insertions(+), 50 deletions(-) diff --git a/charts/substra-backend/templates/deployment-backend.yaml b/charts/substra-backend/templates/deployment-backend.yaml index 7d1ae5e46..fea3d028d 100644 --- a/charts/substra-backend/templates/deployment-backend.yaml +++ b/charts/substra-backend/templates/deployment-backend.yaml @@ -44,13 +44,13 @@ spec: env: - name: ORG value: {{ .Values.organization.name }} - - name: SUBSTRABAC_ORG + - name: SUBSTRABACKEND_ORG value: {{ .Values.organization.name }} - - name: SUBSTRABAC_{{ .Values.organization.name | upper }}_DB_NAME + - name: SUBSTRABACKEND_{{ .Values.organization.name | upper }}_DB_NAME value: {{ .Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABAC_DB_USER + - name: SUBSTRABACKEND_DB_USER value: {{ .Values.postgresql.postgresqlUsername }} - - name: SUBSTRABAC_DB_PWD + - name: SUBSTRABACKEND_DB_PWD value: {{ .Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ .Release.Name }}-postgresql @@ -77,9 +77,9 @@ spec: - name: BACK_AUTH_PASSWORD value: "" {{- end }} - - name: SUBSTRABAC_DEFAULT_PORT + - name: SUBSTRABACKEND_DEFAULT_PORT value: {{ .Values.backend.service.port | quote}} - - name: SUBSTRABAC_PEER_PORT + - name: SUBSTRABACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE value: /conf/{{ .Values.organization.name }}/substrabackend/conf.json diff --git a/charts/substra-backend/templates/deployment-scheduler.yaml b/charts/substra-backend/templates/deployment-scheduler.yaml index 60e0abafd..e39d9cf63 100644 --- a/charts/substra-backend/templates/deployment-scheduler.yaml +++ b/charts/substra-backend/templates/deployment-scheduler.yaml @@ -40,9 +40,9 @@ spec: env: - name: ORG value: {{ .Values.organization.name }} - - name: SUBSTRABAC_ORG + - name: SUBSTRABACKEND_ORG value: {{ .Values.organization.name }} - - name: SUBSTRABAC_DEFAULT_PORT + - name: SUBSTRABACKEND_DEFAULT_PORT value: "8000" - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" diff --git a/charts/substra-backend/templates/deployment-worker.yaml b/charts/substra-backend/templates/deployment-worker.yaml index 2d592d26b..aa9aea088 100644 --- a/charts/substra-backend/templates/deployment-worker.yaml +++ b/charts/substra-backend/templates/deployment-worker.yaml @@ -40,9 +40,9 @@ spec: env: - name: ORG value: {{ .Values.organization.name }} - - name: SUBSTRABAC_ORG + - name: SUBSTRABACKEND_ORG value: {{ .Values.organization.name }} - - name: SUBSTRABAC_DEFAULT_PORT + - name: SUBSTRABACKEND_DEFAULT_PORT value: "8000" - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" @@ -63,11 +63,11 @@ spec: {{- end }} - name: DEFAULT_DOMAIN value: "{{ .Values.backend.defaultDomain }}" - - name: SUBSTRABAC_{{ .Values.organization.name | upper }}_DB_NAME + - name: SUBSTRABACKEND_{{ .Values.organization.name | upper }}_DB_NAME value: {{ .Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABAC_DB_USER + - name: SUBSTRABACKEND_DB_USER value: {{ .Values.postgresql.postgresqlUsername }} - - name: SUBSTRABAC_DB_PWD + - name: SUBSTRABACKEND_DB_PWD value: {{ .Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ .Release.Name }}-postgresql diff --git a/charts/substra-backend/templates/job-add-incoming-nodes.yaml b/charts/substra-backend/templates/job-add-incoming-nodes.yaml index 658c14cdb..2196ba7e0 100644 --- a/charts/substra-backend/templates/job-add-incoming-nodes.yaml +++ b/charts/substra-backend/templates/job-add-incoming-nodes.yaml @@ -32,13 +32,13 @@ spec: env: - name: ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABAC_ORG + - name: SUBSTRABACKEND_ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABAC_{{ $.Values.organization.name | upper }}_DB_NAME + - name: SUBSTRABACKEND_{{ $.Values.organization.name | upper }}_DB_NAME value: {{ $.Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABAC_DB_USER + - name: SUBSTRABACKEND_DB_USER value: {{ $.Values.postgresql.postgresqlUsername }} - - name: SUBSTRABAC_DB_PWD + - name: SUBSTRABACKEND_DB_PWD value: {{ $.Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ $.Release.Name }}-postgresql @@ -58,9 +58,9 @@ spec: value: {{ $.user | quote }} - name: BACK_AUTH_PASSWORD value: {{ $.password | quote }} - - name: SUBSTRABAC_DEFAULT_PORT + - name: SUBSTRABACKEND_DEFAULT_PORT value: {{ $.Values.backend.service.port | quote}} - - name: SUBSTRABAC_PEER_PORT + - name: SUBSTRABACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE value: /conf/{{ $.Values.organization.name }}/substrabackend/conf.json diff --git a/charts/substra-backend/templates/job-add-outgoing-nodes.yaml b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml index a519ba1c9..08473e7a6 100644 --- a/charts/substra-backend/templates/job-add-outgoing-nodes.yaml +++ b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml @@ -32,13 +32,13 @@ spec: env: - name: ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABAC_ORG + - name: SUBSTRABACKEND_ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABAC_{{ $.Values.organization.name | upper }}_DB_NAME + - name: SUBSTRABACKEND_{{ $.Values.organization.name | upper }}_DB_NAME value: {{ $.Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABAC_DB_USER + - name: SUBSTRABACKEND_DB_USER value: {{ $.Values.postgresql.postgresqlUsername }} - - name: SUBSTRABAC_DB_PWD + - name: SUBSTRABACKEND_DB_PWD value: {{ $.Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ $.Release.Name }}-postgresql @@ -58,9 +58,9 @@ spec: value: {{ $.user | quote }} - name: BACK_AUTH_PASSWORD value: {{ $.password | quote }} - - name: SUBSTRABAC_DEFAULT_PORT + - name: SUBSTRABACKEND_DEFAULT_PORT value: {{ $.Values.backend.service.port | quote}} - - name: SUBSTRABAC_PEER_PORT + - name: SUBSTRABACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE value: /conf/{{ $.Values.organization.name }}/substrabackend/conf.json diff --git a/docker/start.py b/docker/start.py index ee7f75278..e330d0ff0 100644 --- a/docker/start.py +++ b/docker/start.py @@ -50,8 +50,8 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): # Docker compose config docker_compose = { - 'substrabac_services': {}, - 'substrabac_tools': { + 'substrabackend_services': {}, + 'substrabackend_tools': { 'postgresql': { 'container_name': 'postgresql', 'labels': ['substra'], @@ -133,9 +133,9 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): backend_global_env = [ f'ORG={org_name_stripped}', - f'SUBSTRABAC_ORG={org_name}', - f'SUBSTRABAC_DEFAULT_PORT={port}', - 'SUBSTRABAC_PEER_PORT=internal', + f'SUBSTRABACKEND_ORG={org_name}', + f'SUBSTRABACKEND_DEFAULT_PORT={port}', + 'SUBSTRABACKEND_PEER_PORT=internal', f'LEDGER_CONFIG_FILE={SUBSTRA_FOLDER}/conf/{org_name}/substrabackend/conf.json', @@ -229,7 +229,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): worker['environment'].append(media_root) backend['environment'].append(media_root) else: - default_domain = os.environ.get('SUBSTRABAC_DEFAULT_DOMAIN', '') + default_domain = os.environ.get('SUBSTRABACKEND_DEFAULT_DOMAIN', '') if default_domain: backend['environment'].append(f"DEFAULT_DOMAIN={default_domain}") worker['environment'].append(f"DEFAULT_DOMAIN={default_domain}") @@ -238,17 +238,17 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): scheduler['environment'].append(f"RAVEN_URL={raven_scheduler_url}") worker['environment'].append(f"RAVEN_URL={raven_worker_url}") - docker_compose['substrabac_services']['substrabackend' + org_name_stripped] = backend - docker_compose['substrabac_services']['scheduler' + org_name_stripped] = scheduler - docker_compose['substrabac_services']['worker' + org_name_stripped] = worker + docker_compose['substrabackend_services']['substrabackend' + org_name_stripped] = backend + docker_compose['substrabackend_services']['scheduler' + org_name_stripped] = scheduler + docker_compose['substrabackend_services']['worker' + org_name_stripped] = worker # Create all services along to conf COMPOSITION = {'services': {}, 'version': '2.3', 'networks': {'default': {'external': {'name': 'net_substra'}}}} - for name, dconfig in docker_compose['substrabac_services'].items(): + for name, dconfig in docker_compose['substrabackend_services'].items(): COMPOSITION['services'][name] = dconfig - for name, dconfig in docker_compose['substrabac_tools'].items(): + for name, dconfig in docker_compose['substrabackend_tools'].items(): COMPOSITION['services'][name] = dconfig with open(docker_compose['path'], 'w+') as f: diff --git a/scripts/populate_db.sh b/scripts/populate_db.sh index e0560c955..8c52301e9 100755 --- a/scripts/populate_db.sh +++ b/scripts/populate_db.sh @@ -2,5 +2,5 @@ # load dumps BASEDIR=$(dirname "$0") -psql -U ${USER} -d substrabac_chunantes < ${BASEDIR}/../fixtures/dump_substrabac_chunantes.sql -psql -U ${USER} -d substrabac_owkin < ${BASEDIR}/../fixtures/dump_substrabac_owkin.sql +psql -U ${USER} -d substrabackend_chunantes < ${BASEDIR}/../fixtures/dump_substrabackend_chunantes.sql +psql -U ${USER} -d substrabackend_owkin < ${BASEDIR}/../fixtures/dump_substrabackend_owkin.sql diff --git a/substrabackend/events/apps.py b/substrabackend/events/apps.py index 97d2acf37..531e0d2ed 100644 --- a/substrabackend/events/apps.py +++ b/substrabackend/events/apps.py @@ -82,7 +82,7 @@ def wait(): chaincode_name = LEDGER['chaincode_name'] peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] + peer_port = peer["port"][os.environ.get('SUBSTRABACKEND_PEER_PORT', 'external')] client = Client() diff --git a/substrabackend/substrabackend/settings/deps/ledger.py b/substrabackend/substrabackend/settings/deps/ledger.py index cf79134a8..23e87db3c 100644 --- a/substrabackend/substrabackend/settings/deps/ledger.py +++ b/substrabackend/substrabackend/settings/deps/ledger.py @@ -22,7 +22,7 @@ LEDGER_SYNC_ENABLED = True LEDGER_CALL_RETRY = True -PEER_PORT = LEDGER['peer']['port'][os.environ.get('SUBSTRABAC_PEER_PORT', 'external')] +PEER_PORT = LEDGER['peer']['port'][os.environ.get('SUBSTRABACKEND_PEER_PORT', 'external')] LEDGER['requestor'] = create_user( name=LEDGER['client']['name'], @@ -130,7 +130,7 @@ def update_client_with_discovery(client, discovery_results): tls_root_cert.flush() url = peer_info['endpoint'] - external_port = os.environ.get('SUBSTRABAC_PEER_PORT_EXTERNAL', None) + external_port = os.environ.get('SUBSTRABACKEND_PEER_PORT_EXTERNAL', None) # use case for external development if external_port: url = f"{peer_info['endpoint'].split(':')[0]}:{external_port}" diff --git a/substrabackend/substrabackend/settings/deps/org.py b/substrabackend/substrabackend/settings/deps/org.py index 2de6039f7..c31d302cb 100644 --- a/substrabackend/substrabackend/settings/deps/org.py +++ b/substrabackend/substrabackend/settings/deps/org.py @@ -1,6 +1,6 @@ import os -ORG = os.environ.get('SUBSTRABAC_ORG', 'substra') -DEFAULT_PORT = os.environ.get('SUBSTRABAC_DEFAULT_PORT', '8000') +ORG = os.environ.get('SUBSTRABACKEND_ORG', 'substra') +DEFAULT_PORT = os.environ.get('SUBSTRABACKEND_DEFAULT_PORT', '8000') ORG_NAME = ORG.replace('-', '') ORG_DB_NAME = ORG.replace('-', '_').upper() diff --git a/substrabackend/substrabackend/settings/dev.py b/substrabackend/substrabackend/settings/dev.py index 2388cf385..b7c8aa9a8 100644 --- a/substrabackend/substrabackend/settings/dev.py +++ b/substrabackend/substrabackend/settings/dev.py @@ -26,9 +26,9 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': os.environ.get(f'SUBSTRABAC_{ORG_DB_NAME}_DB_NAME', f'substrabac_{ORG_NAME}'), - 'USER': os.environ.get('SUBSTRABAC_DB_USER', 'substrabackend'), - 'PASSWORD': os.environ.get('SUBSTRABAC_DB_PWD', 'substrabackend'), + 'NAME': os.environ.get(f'SUBSTRABACKEND_{ORG_DB_NAME}_DB_NAME', f'substrabackend_{ORG_NAME}'), + 'USER': os.environ.get('SUBSTRABACKEND_DB_USER', 'substrabackend'), + 'PASSWORD': os.environ.get('SUBSTRABACKEND_DB_PWD', 'substrabackend'), 'HOST': os.environ.get('DATABASE_HOST', 'localhost'), 'PORT': 5432, } diff --git a/substrabackend/substrabackend/settings/prod.py b/substrabackend/substrabackend/settings/prod.py index 2cd88984c..863a7ab7e 100644 --- a/substrabackend/substrabackend/settings/prod.py +++ b/substrabackend/substrabackend/settings/prod.py @@ -33,9 +33,9 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': os.environ.get(f'SUBSTRABAC_{ORG_DB_NAME}_DB_NAME', f'substrabac_{ORG_NAME}'), - 'USER': os.environ.get('SUBSTRABAC_DB_USER', 'substrabackend'), - 'PASSWORD': os.environ.get('SUBSTRABAC_DB_PWD', 'substrabackend'), + 'NAME': os.environ.get(f'SUBSTRABACKEND_{ORG_DB_NAME}_DB_NAME', f'substrabackend_{ORG_NAME}'), + 'USER': os.environ.get('SUBSTRABACKEND_DB_USER', 'substrabackend'), + 'PASSWORD': os.environ.get('SUBSTRABACKEND_DB_PWD', 'substrabackend'), 'HOST': os.environ.get('DATABASE_HOST', 'localhost'), 'PORT': 5432, } diff --git a/substrabackend/substrabackend/views.py b/substrabackend/substrabackend/views.py index 727060cf7..aac766106 100644 --- a/substrabackend/substrabackend/views.py +++ b/substrabackend/substrabackend/views.py @@ -102,6 +102,6 @@ def get_link(self, path, method, view): @renderer_classes([OpenAPIRenderer, SwaggerUIRenderer]) def schema_view(request): generator = SchemaGenerator( - title='Substrabac API', + title='Substra Backend API', patterns=[url(r'^/', include([url(r'^', include(router.urls))]))]) return response.Response(generator.get_schema(request=request)) From 3e3cfdb69ad40a5e3bd8f91b1aeb58d33a731076 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Sat, 19 Oct 2019 19:58:51 +0200 Subject: [PATCH 369/457] fix urls module --- charts/substrabac/charts/postgresql-6.2.1.tgz | Bin 22419 -> 0 bytes charts/substrabac/charts/rabbitmq-6.2.6.tgz | Bin 19254 -> 0 bytes substrabackend/substrabackend/urls.py | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 charts/substrabac/charts/postgresql-6.2.1.tgz delete mode 100644 charts/substrabac/charts/rabbitmq-6.2.6.tgz diff --git a/charts/substrabac/charts/postgresql-6.2.1.tgz b/charts/substrabac/charts/postgresql-6.2.1.tgz deleted file mode 100644 index 15d7581f09db4b7c535cd716c03da0410e1f1d78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22419 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,A=stmY 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
        $3HcJ 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

        v6OsBfzj;*X1@*Y6ItUqbUze;5Phn^Px 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 diff --git a/substrabackend/substrabackend/urls.py b/substrabackend/substrabackend/urls.py index d72a8cc3a..57585ee8b 100644 --- a/substrabackend/substrabackend/urls.py +++ b/substrabackend/substrabackend/urls.py @@ -1,4 +1,4 @@ -"""substrabac URL Configuration +"""substrabackend URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ @@ -19,7 +19,7 @@ from django.conf.urls.static import static from django.urls import include -from substrabac.views import schema_view +from substrabackend.views import schema_view from substrapp.urls import router from node.urls import router as nodeRouter From cfabe78a101e4c4b6c9f5a99c621d46b5834df87 Mon Sep 17 00:00:00 2001 From: Inal DJAFAR Date: Sun, 20 Oct 2019 22:45:14 +0200 Subject: [PATCH 370/457] update --- docker/start.py | 4 ++-- docker/{substra-backend => substrabackend}/Dockerfile | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename docker/{substra-backend => substrabackend}/Dockerfile (100%) diff --git a/docker/start.py b/docker/start.py index e330d0ff0..907ac3826 100644 --- a/docker/start.py +++ b/docker/start.py @@ -174,9 +174,9 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): fixtures_command = f"python manage.py loaddata nodes-{org_name_stripped}" backend = { - 'container_name': f'{org_name_stripped}.substra-backend', + 'container_name': f'{org_name_stripped}.substrabackend', 'labels': ['substra'], - 'image': 'substra/substra-backend', + 'image': 'substra/substrabackend', 'restart': 'unless-stopped', 'ports': [f'{port}:{port}'], 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' diff --git a/docker/substra-backend/Dockerfile b/docker/substrabackend/Dockerfile similarity index 100% rename from docker/substra-backend/Dockerfile rename to docker/substrabackend/Dockerfile From c0670b1d830724e9025cfa7a99694de3110bff8e Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Mon, 21 Oct 2019 08:38:09 +0200 Subject: [PATCH 371/457] rename docker folder --- docker/{substrabackend => substra-backend}/Dockerfile | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docker/{substrabackend => substra-backend}/Dockerfile (100%) diff --git a/docker/substrabackend/Dockerfile b/docker/substra-backend/Dockerfile similarity index 100% rename from docker/substrabackend/Dockerfile rename to docker/substra-backend/Dockerfile From 896ac074b2551f442372e1f1636a5be0fcedfe4b Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Mon, 21 Oct 2019 09:37:45 +0200 Subject: [PATCH 372/457] Fixup skaffold --- .../templates/deployment-backend.yaml | 4 ++-- skaffold.yaml | 20 ------------------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/charts/substra-backend/templates/deployment-backend.yaml b/charts/substra-backend/templates/deployment-backend.yaml index fea3d028d..7c3dd2269 100644 --- a/charts/substra-backend/templates/deployment-backend.yaml +++ b/charts/substra-backend/templates/deployment-backend.yaml @@ -37,9 +37,9 @@ spec: {{- end }} command: ["/bin/bash"] {{- if eq .Values.backend.settings "prod" }} - args: ["-c", "python manage.py migrate; python3 manage.py collectstatic --noinput; uwsgi --http :8000 --module substrabackend.wsgi --static-map /static=/usr/src/app/substrabackend/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=substrabackend.settings.server.{{ .Values.backend.settings }} "] + args: ["-c", "python manage.py migrate && python3 manage.py collectstatic --noinput && uwsgi --http :8000 --module substrabackend.wsgi --static-map /static=/usr/src/app/substrabackend/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=substrabackend.settings.server.{{ .Values.backend.settings }} "] {{- else }} - args: ["-c", "python manage.py migrate; DJANGO_SETTINGS_MODULE=substrabackend.settings.server.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] + args: ["-c", "python manage.py migrate && DJANGO_SETTINGS_MODULE=substrabackend.settings.server.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] {{- end }} env: - name: ORG diff --git a/skaffold.yaml b/skaffold.yaml index f7f623199..e819de845 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -1,10 +1,6 @@ apiVersion: skaffold/v1beta13 kind: Config build: - tagPolicy: - envTemplate: - template: "{{ .IMAGE_NAME}}:latest" - artifacts: - image: eu.gcr.io/substra-208412/substra-backend context: . @@ -43,8 +39,6 @@ deploy: secrets: fabricConfigmap: network-peer-1-hlf-k8s-fabric backend: - image: - tag: latest settings: dev defaultDomain: http://substra-backend.node-1 ingress: @@ -59,12 +53,6 @@ deploy: user: node-1 password: node-1pwd header: "Basic bm9kZS0xOm5vZGUtMXB3ZA==" - celerybeat: - image: - tag: latest - celeryworker: - image: - tag: latest organization: name: MyPeer1 peer: @@ -98,8 +86,6 @@ deploy: secrets: fabricConfigmap: network-peer-2-hlf-k8s-fabric backend: - image: - tag: latest settings: dev defaultDomain: http://substra-backend.node-2 ingress: @@ -114,12 +100,6 @@ deploy: user: node-2 password: node-2pwd header: "Basic bm9kZS0yOm5vZGUtMnB3ZA==" - celerybeat: - image: - tag: latest - celeryworker: - image: - tag: latest organization: name: MyPeer1 peer: From 32c65c9197cbafac84749938df6747b8d58c4317 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 21 Oct 2019 15:41:09 +0200 Subject: [PATCH 373/457] Fix renaming for consistency. --- .gitignore | 29 +++++-------------- Jenkinsfile | 2 +- docker/start.py | 4 +-- scripts/generate_nodes_fixtures.py | 4 +-- substrabackend/substrabackend/settings/dev.py | 2 +- .../substrabackend/settings/prod.py | 2 +- 6 files changed, 14 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index 497aa5f05..23ee7eeab 100644 --- a/.gitignore +++ b/.gitignore @@ -106,29 +106,14 @@ venv.bak/ # idea files .idea -#secret files -SECRET - -# conf from substra-network -substra-backend/substrapp/**/conf +# vscode files +.vscode/ -**/medias/* +# secret files +SECRET -# ledger binary files +# substra files bin - - -# test files -substra-backend/substra-backend/description.md -substra-backend/substra-backend/metrics.py - -# docker database dir -postgres-data +**/medias/* +substrabackend/substrapp/**/conf docker/docker-compose-dynamic.yaml - -network.json -benin_malin -# file for testing data creation with django command -data.json - -.vscode/ diff --git a/Jenkinsfile b/Jenkinsfile index 96747cfa7..0962b7743 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -69,7 +69,7 @@ pipeline { allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true, - reportDir: 'substra-backend/htmlcov', + reportDir: 'substrabackend/htmlcov', reportFiles: 'index.html', reportName: 'Coverage Report' ] diff --git a/docker/start.py b/docker/start.py index 907ac3826..e330d0ff0 100644 --- a/docker/start.py +++ b/docker/start.py @@ -174,9 +174,9 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): fixtures_command = f"python manage.py loaddata nodes-{org_name_stripped}" backend = { - 'container_name': f'{org_name_stripped}.substrabackend', + 'container_name': f'{org_name_stripped}.substra-backend', 'labels': ['substra'], - 'image': 'substra/substrabackend', + 'image': 'substra/substra-backend', 'restart': 'unless-stopped', 'ports': [f'{port}:{port}'], 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' diff --git a/scripts/generate_nodes_fixtures.py b/scripts/generate_nodes_fixtures.py index 92dfe51c8..87b05eb01 100644 --- a/scripts/generate_nodes_fixtures.py +++ b/scripts/generate_nodes_fixtures.py @@ -19,14 +19,14 @@ def generate_network_credentials(nodes): network_creds[node_id]['name'] = node_name network_creds[node_id]['outgoing'] = { other_id: create_random_secret() - for other_id in node_ids if other_id != node_id + for other_id in node_ids } # parse outgoing credentials to set incoming credentials for node_id, node_creds in network_creds.items(): node_creds['incoming'] = { other_id: network_creds[other_id]['outgoing'][node_id] - for other_id in node_ids if other_id != node_id + for other_id in node_ids } return network_creds diff --git a/substrabackend/substrabackend/settings/dev.py b/substrabackend/substrabackend/settings/dev.py index b7c8aa9a8..910ea8767 100644 --- a/substrabackend/substrabackend/settings/dev.py +++ b/substrabackend/substrabackend/settings/dev.py @@ -37,7 +37,7 @@ MEDIA_ROOT = os.environ.get('MEDIA_ROOT', os.path.join(PROJECT_ROOT, f'medias/{ORG_NAME}')) -SITE_HOST = f'{ORG_NAME}.substrabackend' +SITE_HOST = f'{ORG_NAME}.substra-backend' SITE_PORT = DEFAULT_PORT DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') diff --git a/substrabackend/substrabackend/settings/prod.py b/substrabackend/substrabackend/settings/prod.py index 863a7ab7e..c01251610 100644 --- a/substrabackend/substrabackend/settings/prod.py +++ b/substrabackend/substrabackend/settings/prod.py @@ -42,7 +42,7 @@ } MEDIA_ROOT = os.environ.get('MEDIA_ROOT', f'/substra/medias/{ORG_NAME}') -SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substrabackend') +SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substra-backend') SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') From d65927cc087527f4f1bc14c5dd1b87a5de605905 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 21 Oct 2019 18:03:29 +0200 Subject: [PATCH 374/457] Fix jenkins --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 0962b7743..7fcdab8cb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -53,7 +53,7 @@ pipeline { sh "docker login -u _json_key --password-stdin https://eu.gcr.io/substra-208412/ < /secret/kaniko-secret.json" sh "apt install -y python3-pip python3-dev build-essential gfortran musl-dev postgresql-contrib git curl netcat" - dir("substra-backend") { + dir("substrabackend") { sh "pip install flake8" sh "flake8" sh "pip install -r requirements.txt" From 593e612d11ee4ce40413c27f3f3a6cec302bf417 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 22 Oct 2019 10:42:55 +0200 Subject: [PATCH 375/457] Final projet name for substra-backend --- .flake8 | 8 +-- .gitignore | 2 +- Jenkinsfile | 8 +-- README.md | 50 +++++++------- {substrabackend => backend}/.coveragerc | 0 .../backend}/__init__.py | 0 .../backend}/celery.py | 4 +- .../backend/settings}/__init__.py | 0 .../backend}/settings/common.py | 6 +- .../backend/settings/deps}/__init__.py | 0 .../backend}/settings/deps/cors.py | 0 .../backend}/settings/deps/ledger.py | 8 +-- backend/backend/settings/deps/org.py | 6 ++ .../backend}/settings/deps/raven.py | 0 .../backend}/settings/deps/restframework.py | 0 .../backend}/settings/dev.py | 8 +-- .../backend}/settings/prod.py | 6 +- .../backend/settings/server}/__init__.py | 0 .../backend}/settings/server/dev.py | 0 .../settings/server/nobasicauth}/__init__.py | 0 .../settings/server/nobasicauth/dev.py | 0 .../settings/server/nobasicauth/prod.py | 0 .../backend}/settings/server/prod.py | 0 .../backend}/settings/test.py | 0 .../backend}/urls.py | 4 +- .../backend}/views.py | 0 .../backend}/wsgi.py | 4 +- .../events/__init__.py | 0 {substrabackend => backend}/events/apps.py | 2 +- .../libs/SQLPrintingMiddleware.py | 0 .../node/tests => backend/libs}/__init__.py | 0 .../libs/authentication.py | 0 .../libs/gen_secret_key.py | 0 .../libs/pagination.py | 0 .../libs/serializers.py | 0 .../libs/timestampModel.py | 0 .../libs/versioning.py | 0 {substrabackend => backend}/manage.py | 2 +- .../node-register/__init__.py | 0 .../node-register/apps.py | 0 {substrabackend => backend}/node/__init__.py | 0 {substrabackend => backend}/node/apps.py | 0 .../node/authentication.py | 0 .../node/fixtures/nodes-chunantes.yaml | 0 .../node/fixtures/nodes-clb.yaml | 0 .../node/fixtures/nodes-owkin.yaml | 0 .../commands/create_incoming_node.py | 0 .../commands/create_outgoing_node.py | 0 .../management/commands/get_incoming_node.py | 0 .../management/commands/get_outgoing_node.py | 0 .../node/migrations/0001_initial.py | 0 .../node/migrations/0002_nodeuser.py | 0 .../node/migrations}/__init__.py | 0 {substrabackend => backend}/node/models.py | 0 .../node/signals}/__init__.py | 0 .../node/signals/node}/__init__.py | 0 .../node/signals/node/pre_save.py | 0 .../server => backend/node/tests}/__init__.py | 0 .../node/tests/views}/__init__.py | 0 .../node/tests/views/tests_views_node.py | 0 {substrabackend => backend}/node/urls.py | 0 .../node/views/__init__.py | 0 .../node/views/node.py | 0 {substrabackend => backend}/requirements.txt | 0 .../substrapp/__init__.py | 0 .../substrapp/admin.py | 0 {substrabackend => backend}/substrapp/apps.py | 0 .../substrapp/ledger_utils.py | 0 .../commands/bulkcreatedatasample.py | 0 .../management/commands/createdataset.py | 0 .../management/commands/createobjective.py | 0 .../tests/tests_bulkcreatedatasample.py | 0 .../tests/tests_createdatamanager.py | 0 .../management/tests/tests_createobjective.py | 0 .../substrapp/management/utils/__init__.py | 0 .../management/utils/localRequest.py | 0 .../substrapp/migrations/0001_initial.py | 0 .../substrapp/migrations/__init__.py | 0 .../substrapp/models/__init__.py | 0 .../substrapp/models/algo.py | 0 .../substrapp/models/datamanager.py | 0 .../substrapp/models/datasample.py | 0 .../substrapp/models/model.py | 0 .../substrapp/models/objective.py | 0 .../substrapp/serializers/__init__.py | 0 .../substrapp/serializers/algo.py | 0 .../substrapp/serializers/datamanager.py | 0 .../substrapp/serializers/datasample.py | 0 .../substrapp/serializers/ledger/__init__.py | 0 .../serializers/ledger/algo/__init__.py | 0 .../serializers/ledger/algo/serializer.py | 0 .../serializers/ledger/algo/tasks.py | 0 .../substrapp/serializers/ledger/algo/util.py | 0 .../ledger/computeplan/__init__.py | 0 .../ledger/computeplan/serializer.py | 0 .../serializers/ledger/computeplan/tasks.py | 0 .../serializers/ledger/computeplan/util.py | 0 .../ledger/datamanager/__init__.py | 0 .../ledger/datamanager/serializer.py | 0 .../serializers/ledger/datamanager/tasks.py | 0 .../serializers/ledger/datamanager/util.py | 0 .../serializers/ledger/datasample/__init__.py | 0 .../ledger/datasample/serializer.py | 0 .../serializers/ledger/datasample/tasks.py | 0 .../serializers/ledger/datasample/util.py | 0 .../serializers/ledger/model/__init__.py | 0 .../serializers/ledger/model/serializer.py | 0 .../serializers/ledger/objective/__init__.py | 0 .../ledger/objective/serializer.py | 0 .../serializers/ledger/objective/tasks.py | 0 .../serializers/ledger/objective/util.py | 0 .../serializers/ledger/testtuple/__init__.py | 0 .../ledger/testtuple/serializer.py | 0 .../serializers/ledger/testtuple/tasks.py | 0 .../serializers/ledger/testtuple/util.py | 0 .../serializers/ledger/traintuple/__init__.py | 0 .../ledger/traintuple/serializer.py | 0 .../serializers/ledger/traintuple/tasks.py | 0 .../serializers/ledger/traintuple/util.py | 0 .../substrapp/serializers/ledger/utils.py | 0 .../substrapp/serializers/model.py | 0 .../substrapp/serializers/objective.py | 0 .../substrapp/serializers/utils.py | 0 .../substrapp/signals/__init__.py | 0 .../substrapp/signals/algo/__init__.py | 0 .../substrapp/signals/algo/post_delete.py | 0 .../substrapp/signals/datamanager/__init__.py | 0 .../signals/datamanager/post_delete.py | 0 .../substrapp/signals/datasample/__init__.py | 0 .../signals/datasample/post_delete.py | 0 .../substrapp/signals/datasample/pre_save.py | 0 .../substrapp/signals/model/__init__.py | 0 .../substrapp/signals/model/post_delete.py | 0 .../substrapp/signals/objective/__init__.py | 0 .../signals/objective/post_delete.py | 0 .../substrapp/tasks/__init__.py | 0 .../substrapp/tasks/exception_handler.py | 4 +- .../substrapp/tasks/exceptions.json | 0 .../substrapp/tasks/tasks.py | 2 +- .../substrapp/tasks/utils.py | 0 .../substrapp/tests/__init__.py | 0 .../substrapp/tests/assets.py | 0 .../substrapp/tests/common.py | 0 .../substrapp/tests/generate_assets.py | 0 .../substrapp/tests/query/__init__.py | 0 .../substrapp/tests/query/tests_query_algo.py | 0 .../tests/query/tests_query_datamanager.py | 0 .../tests/query/tests_query_datasample.py | 0 .../tests/query/tests_query_objective.py | 0 .../tests/query/tests_query_tuples.py | 0 .../substrapp/tests/tests_exception.py | 0 .../substrapp/tests/tests_misc.py | 0 .../substrapp/tests/tests_model.py | 0 .../substrapp/tests/tests_tasks.py | 0 .../substrapp/tests/views/__init__.py | 0 .../tests/views/test_views_authentication.py | 0 .../substrapp/tests/views/tests_utils.py | 0 .../substrapp/tests/views/tests_views.py | 0 .../substrapp/tests/views/tests_views_algo.py | 0 .../tests/views/tests_views_computeplan.py | 0 .../tests/views/tests_views_datamanager.py | 0 .../tests/views/tests_views_datasample.py | 0 .../tests/views/tests_views_model.py | 0 .../tests/views/tests_views_objective.py | 0 .../substrapp/tests/views/tests_views_task.py | 0 .../tests/views/tests_views_tuples.py | 0 {substrabackend => backend}/substrapp/urls.py | 0 .../substrapp/utils.py | 0 .../substrapp/views/__init__.py | 0 .../substrapp/views/algo.py | 0 .../substrapp/views/computeplan.py | 0 .../substrapp/views/datamanager.py | 0 .../substrapp/views/datasample.py | 0 .../substrapp/views/filters_utils.py | 0 .../substrapp/views/model.py | 0 .../substrapp/views/objective.py | 0 .../substrapp/views/task.py | 0 .../substrapp/views/testtuple.py | 0 .../substrapp/views/traintuple.py | 0 .../substrapp/views/utils.py | 0 .../templates/deployment-backend.yaml | 22 +++--- .../templates/deployment-celerybeat.yaml | 4 +- .../templates/deployment-flower.yaml | 4 +- .../templates/deployment-scheduler.yaml | 12 ++-- .../templates/deployment-worker.yaml | 18 ++--- .../templates/job-add-incoming-nodes.yaml | 18 ++--- .../templates/job-add-outgoing-nodes.yaml | 18 ++--- charts/substra-backend/values.yaml | 2 +- docker/celerybeat/Dockerfile | 10 +-- docker/celeryworker/Dockerfile | 10 +-- docker/flower/Dockerfile | 10 +-- docker/postgresql/init.sh | 12 ++-- docker/start.py | 64 +++++++++--------- docker/substra-backend/Dockerfile | 16 ++--- .../chunantes/algos/algo0/description.md~ | 5 -- fixtures/chunantes/algos/algo3/algo.tar.gz | Bin 1189 -> 1571 bytes .../chunantes/algos/algo4/description.md~ | 5 -- .../objectives/objective0/Dockerfile | 2 +- .../objectives/objective0/metrics.zip | Bin 610 -> 682 bytes .../owkin/objectives/objective0/Dockerfile | 2 +- .../owkin/objectives/objective0/metrics.zip | Bin 626 -> 682 bytes populate.py | 2 +- scripts/clean_media_local.sh | 2 +- scripts/generate_nodes_fixtures.py | 2 +- scripts/populate_db.sh | 4 +- scripts/recreate_db.sh | 24 +++---- .../substrabackend/settings/deps/org.py | 6 -- 207 files changed, 194 insertions(+), 204 deletions(-) rename {substrabackend => backend}/.coveragerc (100%) rename {substrabackend/substrabackend => backend/backend}/__init__.py (100%) rename {substrabackend/substrabackend => backend/backend}/celery.py (93%) rename {substrabackend/libs => backend/backend/settings}/__init__.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/common.py (97%) rename {substrabackend/node/migrations => backend/backend/settings/deps}/__init__.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/deps/cors.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/deps/ledger.py (96%) create mode 100644 backend/backend/settings/deps/org.py rename {substrabackend/substrabackend => backend/backend}/settings/deps/raven.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/deps/restframework.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/dev.py (88%) rename {substrabackend/substrabackend => backend/backend}/settings/prod.py (92%) rename {substrabackend/node/signals => backend/backend/settings/server}/__init__.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/server/dev.py (100%) rename {substrabackend/node/signals/node => backend/backend/settings/server/nobasicauth}/__init__.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/server/nobasicauth/dev.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/server/nobasicauth/prod.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/server/prod.py (100%) rename {substrabackend/substrabackend => backend/backend}/settings/test.py (100%) rename {substrabackend/substrabackend => backend/backend}/urls.py (93%) rename {substrabackend/substrabackend => backend/backend}/views.py (100%) rename {substrabackend/substrabackend => backend/backend}/wsgi.py (70%) rename {substrabackend => backend}/events/__init__.py (100%) rename {substrabackend => backend}/events/apps.py (98%) rename {substrabackend => backend}/libs/SQLPrintingMiddleware.py (100%) rename {substrabackend/node/tests => backend/libs}/__init__.py (100%) rename {substrabackend => backend}/libs/authentication.py (100%) rename {substrabackend => backend}/libs/gen_secret_key.py (100%) rename {substrabackend => backend}/libs/pagination.py (100%) rename {substrabackend => backend}/libs/serializers.py (100%) rename {substrabackend => backend}/libs/timestampModel.py (100%) rename {substrabackend => backend}/libs/versioning.py (100%) rename {substrabackend => backend}/manage.py (84%) rename {substrabackend => backend}/node-register/__init__.py (100%) rename {substrabackend => backend}/node-register/apps.py (100%) rename {substrabackend => backend}/node/__init__.py (100%) rename {substrabackend => backend}/node/apps.py (100%) rename {substrabackend => backend}/node/authentication.py (100%) rename {substrabackend => backend}/node/fixtures/nodes-chunantes.yaml (100%) rename {substrabackend => backend}/node/fixtures/nodes-clb.yaml (100%) rename {substrabackend => backend}/node/fixtures/nodes-owkin.yaml (100%) rename {substrabackend => backend}/node/management/commands/create_incoming_node.py (100%) rename {substrabackend => backend}/node/management/commands/create_outgoing_node.py (100%) rename {substrabackend => backend}/node/management/commands/get_incoming_node.py (100%) rename {substrabackend => backend}/node/management/commands/get_outgoing_node.py (100%) rename {substrabackend => backend}/node/migrations/0001_initial.py (100%) rename {substrabackend => backend}/node/migrations/0002_nodeuser.py (100%) rename {substrabackend/node/tests/views => backend/node/migrations}/__init__.py (100%) rename {substrabackend => backend}/node/models.py (100%) rename {substrabackend/substrabackend/settings => backend/node/signals}/__init__.py (100%) rename {substrabackend/substrabackend/settings/deps => backend/node/signals/node}/__init__.py (100%) rename {substrabackend => backend}/node/signals/node/pre_save.py (100%) rename {substrabackend/substrabackend/settings/server => backend/node/tests}/__init__.py (100%) rename {substrabackend/substrabackend/settings/server/nobasicauth => backend/node/tests/views}/__init__.py (100%) rename {substrabackend => backend}/node/tests/views/tests_views_node.py (100%) rename {substrabackend => backend}/node/urls.py (100%) rename {substrabackend => backend}/node/views/__init__.py (100%) rename {substrabackend => backend}/node/views/node.py (100%) rename {substrabackend => backend}/requirements.txt (100%) rename {substrabackend => backend}/substrapp/__init__.py (100%) rename {substrabackend => backend}/substrapp/admin.py (100%) rename {substrabackend => backend}/substrapp/apps.py (100%) rename {substrabackend => backend}/substrapp/ledger_utils.py (100%) rename {substrabackend => backend}/substrapp/management/commands/bulkcreatedatasample.py (100%) rename {substrabackend => backend}/substrapp/management/commands/createdataset.py (100%) rename {substrabackend => backend}/substrapp/management/commands/createobjective.py (100%) rename {substrabackend => backend}/substrapp/management/tests/tests_bulkcreatedatasample.py (100%) rename {substrabackend => backend}/substrapp/management/tests/tests_createdatamanager.py (100%) rename {substrabackend => backend}/substrapp/management/tests/tests_createobjective.py (100%) rename {substrabackend => backend}/substrapp/management/utils/__init__.py (100%) rename {substrabackend => backend}/substrapp/management/utils/localRequest.py (100%) rename {substrabackend => backend}/substrapp/migrations/0001_initial.py (100%) rename {substrabackend => backend}/substrapp/migrations/__init__.py (100%) rename {substrabackend => backend}/substrapp/models/__init__.py (100%) rename {substrabackend => backend}/substrapp/models/algo.py (100%) rename {substrabackend => backend}/substrapp/models/datamanager.py (100%) rename {substrabackend => backend}/substrapp/models/datasample.py (100%) rename {substrabackend => backend}/substrapp/models/model.py (100%) rename {substrabackend => backend}/substrapp/models/objective.py (100%) rename {substrabackend => backend}/substrapp/serializers/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/algo.py (100%) rename {substrabackend => backend}/substrapp/serializers/datamanager.py (100%) rename {substrabackend => backend}/substrapp/serializers/datasample.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/algo/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/algo/serializer.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/algo/tasks.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/algo/util.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/computeplan/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/computeplan/serializer.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/computeplan/tasks.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/computeplan/util.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/datamanager/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/datamanager/serializer.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/datamanager/tasks.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/datamanager/util.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/datasample/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/datasample/serializer.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/datasample/tasks.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/datasample/util.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/model/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/model/serializer.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/objective/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/objective/serializer.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/objective/tasks.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/objective/util.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/testtuple/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/testtuple/serializer.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/testtuple/tasks.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/testtuple/util.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/traintuple/__init__.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/traintuple/serializer.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/traintuple/tasks.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/traintuple/util.py (100%) rename {substrabackend => backend}/substrapp/serializers/ledger/utils.py (100%) rename {substrabackend => backend}/substrapp/serializers/model.py (100%) rename {substrabackend => backend}/substrapp/serializers/objective.py (100%) rename {substrabackend => backend}/substrapp/serializers/utils.py (100%) rename {substrabackend => backend}/substrapp/signals/__init__.py (100%) rename {substrabackend => backend}/substrapp/signals/algo/__init__.py (100%) rename {substrabackend => backend}/substrapp/signals/algo/post_delete.py (100%) rename {substrabackend => backend}/substrapp/signals/datamanager/__init__.py (100%) rename {substrabackend => backend}/substrapp/signals/datamanager/post_delete.py (100%) rename {substrabackend => backend}/substrapp/signals/datasample/__init__.py (100%) rename {substrabackend => backend}/substrapp/signals/datasample/post_delete.py (100%) rename {substrabackend => backend}/substrapp/signals/datasample/pre_save.py (100%) rename {substrabackend => backend}/substrapp/signals/model/__init__.py (100%) rename {substrabackend => backend}/substrapp/signals/model/post_delete.py (100%) rename {substrabackend => backend}/substrapp/signals/objective/__init__.py (100%) rename {substrabackend => backend}/substrapp/signals/objective/post_delete.py (100%) rename {substrabackend => backend}/substrapp/tasks/__init__.py (100%) rename {substrabackend => backend}/substrapp/tasks/exception_handler.py (96%) rename {substrabackend => backend}/substrapp/tasks/exceptions.json (100%) rename {substrabackend => backend}/substrapp/tasks/tasks.py (99%) rename {substrabackend => backend}/substrapp/tasks/utils.py (100%) rename {substrabackend => backend}/substrapp/tests/__init__.py (100%) rename {substrabackend => backend}/substrapp/tests/assets.py (100%) rename {substrabackend => backend}/substrapp/tests/common.py (100%) rename {substrabackend => backend}/substrapp/tests/generate_assets.py (100%) rename {substrabackend => backend}/substrapp/tests/query/__init__.py (100%) rename {substrabackend => backend}/substrapp/tests/query/tests_query_algo.py (100%) rename {substrabackend => backend}/substrapp/tests/query/tests_query_datamanager.py (100%) rename {substrabackend => backend}/substrapp/tests/query/tests_query_datasample.py (100%) rename {substrabackend => backend}/substrapp/tests/query/tests_query_objective.py (100%) rename {substrabackend => backend}/substrapp/tests/query/tests_query_tuples.py (100%) rename {substrabackend => backend}/substrapp/tests/tests_exception.py (100%) rename {substrabackend => backend}/substrapp/tests/tests_misc.py (100%) rename {substrabackend => backend}/substrapp/tests/tests_model.py (100%) rename {substrabackend => backend}/substrapp/tests/tests_tasks.py (100%) rename {substrabackend => backend}/substrapp/tests/views/__init__.py (100%) rename {substrabackend => backend}/substrapp/tests/views/test_views_authentication.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_utils.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views_algo.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views_computeplan.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views_datamanager.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views_datasample.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views_model.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views_objective.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views_task.py (100%) rename {substrabackend => backend}/substrapp/tests/views/tests_views_tuples.py (100%) rename {substrabackend => backend}/substrapp/urls.py (100%) rename {substrabackend => backend}/substrapp/utils.py (100%) rename {substrabackend => backend}/substrapp/views/__init__.py (100%) rename {substrabackend => backend}/substrapp/views/algo.py (100%) rename {substrabackend => backend}/substrapp/views/computeplan.py (100%) rename {substrabackend => backend}/substrapp/views/datamanager.py (100%) rename {substrabackend => backend}/substrapp/views/datasample.py (100%) rename {substrabackend => backend}/substrapp/views/filters_utils.py (100%) rename {substrabackend => backend}/substrapp/views/model.py (100%) rename {substrabackend => backend}/substrapp/views/objective.py (100%) rename {substrabackend => backend}/substrapp/views/task.py (100%) rename {substrabackend => backend}/substrapp/views/testtuple.py (100%) rename {substrabackend => backend}/substrapp/views/traintuple.py (100%) rename {substrabackend => backend}/substrapp/views/utils.py (100%) delete mode 100644 fixtures/chunantes/algos/algo0/description.md~ delete mode 100644 fixtures/chunantes/algos/algo4/description.md~ delete mode 100644 substrabackend/substrabackend/settings/deps/org.py diff --git a/.flake8 b/.flake8 index b40fbc9e5..7a28d7359 100644 --- a/.flake8 +++ b/.flake8 @@ -1,8 +1,8 @@ [flake8] max-line-length = 120 ignore = E402, W504, F403, F405 -exclude = substrabackend/substrapp/migrations/*, - substrabackend/substrapp/tests/assets.py, - substrabackend/substrabackend/settings/*, - substrabackend/node/migrations/*, +exclude = backend/substrapp/migrations/*, + backend/substrapp/tests/assets.py, + backend/backend/settings/*, + backend/node/migrations/*, .env, .venv diff --git a/.gitignore b/.gitignore index 23ee7eeab..5c7c4df25 100644 --- a/.gitignore +++ b/.gitignore @@ -115,5 +115,5 @@ SECRET # substra files bin **/medias/* -substrabackend/substrapp/**/conf +backend/substrapp/**/conf docker/docker-compose-dynamic.yaml diff --git a/Jenkinsfile b/Jenkinsfile index 7fcdab8cb..a5420343c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -53,11 +53,11 @@ pipeline { sh "docker login -u _json_key --password-stdin https://eu.gcr.io/substra-208412/ < /secret/kaniko-secret.json" sh "apt install -y python3-pip python3-dev build-essential gfortran musl-dev postgresql-contrib git curl netcat" - dir("substrabackend") { + dir("backend") { sh "pip install flake8" sh "flake8" sh "pip install -r requirements.txt" - sh "DJANGO_SETTINGS_MODULE=substrabackend.settings.test coverage run manage.py test" + sh "DJANGO_SETTINGS_MODULE=backend.settings.test coverage run manage.py test" sh "coverage report" sh "coverage html" } @@ -69,7 +69,7 @@ pipeline { allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true, - reportDir: 'substrabackend/htmlcov', + reportDir: 'backend/htmlcov', reportFiles: 'index.html', reportName: 'Coverage Report' ] @@ -80,7 +80,7 @@ pipeline { stage('Build substra-backend') { agent { kubernetes { - label 'substra-backend-kaniko-substrabackend' + label 'substra-backend-kaniko-substra-backend' yamlFile '.cicd/agent-kaniko.yaml' } } diff --git a/README.md b/README.md index 064148364..47f36f310 100644 --- a/README.md +++ b/README.md @@ -64,10 +64,10 @@ Do not forget to build the substra-model image as described in the step 9 of thi ```shell $> sudo su postgres $> psql - $ CREATE USER substrabackend WITH PASSWORD 'substrabackend' CREATEDB CREATEROLE SUPERUSER; + $ CREATE USER backend WITH PASSWORD 'backend' CREATEDB CREATEROLE SUPERUSER; ``` 6. Create two databases for both orgs: owkin and chu-nantes. A shell script is available, do not hesitate to run it. -It will drop the databases if they are already created, then create them and grant all privileges to your main user substrabackend. +It will drop the databases if they are already created, then create them and grant all privileges to your main user backend. (If this is the first time you create the databases, you will see some warnings which are pointless): ```shell @@ -79,8 +79,8 @@ It will drop the databases if they are already created, then create them and gra - With django migrations ```shell -SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python substrabackend/manage.py migrate --settings=substrabackend.settings.dev -SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python substrabackend/manage.py migrate --settings=substrabackend.settings.dev +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python backend/manage.py migrate --settings=backend.settings.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python backend/manage.py migrate --settings=backend.settings.dev ``` ###### With fixtures (fixtures container has been run from substra-network, old behavior for testing) @@ -90,10 +90,10 @@ data in fixtures are relative to the data already set in the ledger if the fixtu Two solutions: - With django migrations + load data ```shell -SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python substrabackend/manage.py migrate --settings=substrabackend.settings.dev -SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python substrabackend/manage.py migrate --settings=substrabackend.settings.dev -SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python substrabackend/manage.py loaddata ./fixtures/data_owkin.json --settings=substrabackend.settings.dev -SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python substrabackend/manage.py loaddata ./fixtures/data_chu-nantes.json --settings=substrabackend.settings.dev +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python backend/manage.py migrate --settings=backend.settings.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python backend/manage.py migrate --settings=backend.settings.dev +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python backend/manage.py loaddata ./fixtures/data_owkin.json --settings=backend.settings.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python backend/manage.py loaddata ./fixtures/data_chu-nantes.json --settings=backend.settings.dev ``` - From dumps: ```shell @@ -110,8 +110,8 @@ It will clean the `medias` folders and create the `owkin` and `chu-nantes` folde 8. Optional: Create a superuser in your databases: ``` -SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python substrabackend/manage.py createsuperuser --settings=substrabackend.settings.dev -SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python substrabackend/manage.py createsuperuser --settings=substrabackend.settings.dev +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python backend/manage.py createsuperuser --settings=backend.settings.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python backend/manage.py createsuperuser --settings=backend.settings.dev ``` 9. Build the substra-model docker image: @@ -135,32 +135,32 @@ sudo apt-get install rabbitmq-server ### Launch celery workers/scheduler and celery beat -Execute this command in the `substrabackend/substrabackend` folder. +Execute this command in the `backend/backend` folder. Note the use of the development settings. ```shell -DJANGO_SETTINGS_MODULE=substrabackend.settings.dev SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 celery -E -A substrabackend worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler -DJANGO_SETTINGS_MODULE=substrabackend.settings.dev SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 celery -E -A substrabackend worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker -DJANGO_SETTINGS_MODULE=substrabackend.settings.dev SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 celery -E -A substrabackend worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler -DJANGO_SETTINGS_MODULE=substrabackend.settings.dev SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 celery -E -A substrabackend worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker -DJANGO_SETTINGS_MODULE=substrabackend.settings.common celery -A substrabackend beat -l info +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 celery -E -A backend worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 celery -E -A backend worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker +DJANGO_SETTINGS_MODULE=backend.settings.common celery -A backend beat -l info ``` ## Launch the servers -Go in the `substrabackend` folder and run the server locally: +Go in the `backend` folder and run the server locally: :warning:

        Be very careful, --settings is different here, `server` is needed.

        ``` - SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabackend.settings.server.dev - SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabackend.settings.server.dev + BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=backend.settings.server.dev + BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=backend.settings.server.dev ``` If you want to bypass the basic authentication when you browse the server on localhost:8000 or localhost:8001, you can use the `nobasicauth` settings. Simply replace `server.dev` by `nobasicauth`, like: ``` - SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=substrabackend.settings.server.nobasicauth - SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=substrabackend.settings.server.nobasicauth + BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=backend.settings.server.nobasicauth + BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=backend.settings.server.nobasicauth ``` It allows the substrafront project to work correctly too. @@ -168,14 +168,14 @@ Go in the `substrabackend` folder and run the server locally: For working with node to node authentication, you need load some extra fixtures ``` -SUBSTRABACKEND_ORG=owkin SUBSTRABACKEND_DEFAULT_PORT=8000 python manage.py loaddata nodes-owkin.yaml --settings=substrabackend.settings.server.dev -SUBSTRABACKEND_ORG=chu-nantes SUBSTRABACKEND_DEFAULT_PORT=8001 python manage.py loaddata nodes-chunantes.yaml --settings=substrabackend.settings.server.dev +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python manage.py loaddata nodes-owkin.yaml --settings=backend.settings.server.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python manage.py loaddata nodes-chunantes.yaml --settings=backend.settings.server.dev ``` ## Test with unit and functional tests ``` - DJANGO_SETTINGS_MODULE=substrabackend.settings.test coverage run manage.py test + DJANGO_SETTINGS_MODULE=backend.settings.test coverage run manage.py test coverage report # For shell report coverage html # For HTML report ``` @@ -265,7 +265,7 @@ Use these configurations for easier debugging and productivity: Do not hesitate to put breakpoints in your code. Even with periodic celery tasks and hit the `bug` button for launching your pre configurations. -You can even access directly to the databases (password is `substrabackend` as described in the beginning of this document): +You can even access directly to the databases (password is `backend` as described in the beginning of this document): ![](assets/database_owkin.png) ![](assets/database_owkin_challenges.png) diff --git a/substrabackend/.coveragerc b/backend/.coveragerc similarity index 100% rename from substrabackend/.coveragerc rename to backend/.coveragerc diff --git a/substrabackend/substrabackend/__init__.py b/backend/backend/__init__.py similarity index 100% rename from substrabackend/substrabackend/__init__.py rename to backend/backend/__init__.py diff --git a/substrabackend/substrabackend/celery.py b/backend/backend/celery.py similarity index 93% rename from substrabackend/substrabackend/celery.py rename to backend/backend/celery.py index 68ec95929..df260609a 100644 --- a/substrabackend/substrabackend/celery.py +++ b/backend/backend/celery.py @@ -5,9 +5,9 @@ from celery.signals import after_task_publish # set the default Django settings module for the 'celery' program. -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'substrabackend.settings.prod') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings.prod') -app = Celery('substrabackend') +app = Celery('backend') # Using a string here means the worker doesn't have to serialize # the configuration object to child processes. diff --git a/substrabackend/libs/__init__.py b/backend/backend/settings/__init__.py similarity index 100% rename from substrabackend/libs/__init__.py rename to backend/backend/settings/__init__.py diff --git a/substrabackend/substrabackend/settings/common.py b/backend/backend/settings/common.py similarity index 97% rename from substrabackend/substrabackend/settings/common.py rename to backend/backend/settings/common.py index 7a9b10307..a2f230791 100644 --- a/substrabackend/substrabackend/settings/common.py +++ b/backend/backend/settings/common.py @@ -1,5 +1,5 @@ """ -Django settings for substrabackend project. +Django settings for backend project. Generated by 'django-admin startproject' using Django 2.0.5. @@ -80,7 +80,7 @@ 'libs.SQLPrintingMiddleware.SQLPrintingMiddleware', ] -ROOT_URLCONF = 'substrabackend.urls' +ROOT_URLCONF = 'backend.urls' TEMPLATES = [ { @@ -98,7 +98,7 @@ }, ] -WSGI_APPLICATION = 'substrabackend.wsgi.application' +WSGI_APPLICATION = 'backend.wsgi.application' # Database # https://docs.djangoproject.com/en/1.9/ref/settings/#databases diff --git a/substrabackend/node/migrations/__init__.py b/backend/backend/settings/deps/__init__.py similarity index 100% rename from substrabackend/node/migrations/__init__.py rename to backend/backend/settings/deps/__init__.py diff --git a/substrabackend/substrabackend/settings/deps/cors.py b/backend/backend/settings/deps/cors.py similarity index 100% rename from substrabackend/substrabackend/settings/deps/cors.py rename to backend/backend/settings/deps/cors.py diff --git a/substrabackend/substrabackend/settings/deps/ledger.py b/backend/backend/settings/deps/ledger.py similarity index 96% rename from substrabackend/substrabackend/settings/deps/ledger.py rename to backend/backend/settings/deps/ledger.py index 23e87db3c..0e2bdaa2d 100644 --- a/substrabackend/substrabackend/settings/deps/ledger.py +++ b/backend/backend/settings/deps/ledger.py @@ -16,13 +16,13 @@ from hfc.fabric.block_decoder import decode_fabric_MSP_config, decode_fabric_peers_info, decode_fabric_endpoints -LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/substrabackend/conf.json') +LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/backend/conf.json') LEDGER = json.load(open(LEDGER_CONFIG_FILE, 'r')) LEDGER_SYNC_ENABLED = True LEDGER_CALL_RETRY = True -PEER_PORT = LEDGER['peer']['port'][os.environ.get('SUBSTRABACKEND_PEER_PORT', 'external')] +PEER_PORT = LEDGER['peer']['port'][os.environ.get('BACKEND_PEER_PORT', 'external')] LEDGER['requestor'] = create_user( name=LEDGER['client']['name'], @@ -41,7 +41,7 @@ def get_hfc_client(): client = Client() - # Add peer from substrabackend ledger config file + # Add peer from backend ledger config file peer = Peer(name=LEDGER['peer']['name']) peer.init_with_bundle({ 'url': f'{LEDGER["peer"]["host"]}:{PEER_PORT}', @@ -130,7 +130,7 @@ def update_client_with_discovery(client, discovery_results): tls_root_cert.flush() url = peer_info['endpoint'] - external_port = os.environ.get('SUBSTRABACKEND_PEER_PORT_EXTERNAL', None) + external_port = os.environ.get('BACKEND_PEER_PORT_EXTERNAL', None) # use case for external development if external_port: url = f"{peer_info['endpoint'].split(':')[0]}:{external_port}" diff --git a/backend/backend/settings/deps/org.py b/backend/backend/settings/deps/org.py new file mode 100644 index 000000000..ffe75c9b9 --- /dev/null +++ b/backend/backend/settings/deps/org.py @@ -0,0 +1,6 @@ +import os + +ORG = os.environ.get('BACKEND_ORG', 'substra') +DEFAULT_PORT = os.environ.get('BACKEND_DEFAULT_PORT', '8000') +ORG_NAME = ORG.replace('-', '') +ORG_DB_NAME = ORG.replace('-', '_').upper() diff --git a/substrabackend/substrabackend/settings/deps/raven.py b/backend/backend/settings/deps/raven.py similarity index 100% rename from substrabackend/substrabackend/settings/deps/raven.py rename to backend/backend/settings/deps/raven.py diff --git a/substrabackend/substrabackend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py similarity index 100% rename from substrabackend/substrabackend/settings/deps/restframework.py rename to backend/backend/settings/deps/restframework.py diff --git a/substrabackend/substrabackend/settings/dev.py b/backend/backend/settings/dev.py similarity index 88% rename from substrabackend/substrabackend/settings/dev.py rename to backend/backend/settings/dev.py index 910ea8767..d776c3cf3 100644 --- a/substrabackend/substrabackend/settings/dev.py +++ b/backend/backend/settings/dev.py @@ -26,9 +26,9 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': os.environ.get(f'SUBSTRABACKEND_{ORG_DB_NAME}_DB_NAME', f'substrabackend_{ORG_NAME}'), - 'USER': os.environ.get('SUBSTRABACKEND_DB_USER', 'substrabackend'), - 'PASSWORD': os.environ.get('SUBSTRABACKEND_DB_PWD', 'substrabackend'), + 'NAME': os.environ.get(f'BACKEND_{ORG_DB_NAME}_DB_NAME', f'backend_{ORG_NAME}'), + 'USER': os.environ.get('BACKEND_DB_USER', 'backend'), + 'PASSWORD': os.environ.get('BACKEND_DB_PWD', 'backend'), 'HOST': os.environ.get('DATABASE_HOST', 'localhost'), 'PORT': 5432, } @@ -70,7 +70,7 @@ }, 'error_file': { 'level': 'INFO', - 'filename': os.path.join(PROJECT_ROOT, 'substrabackend.log'), + 'filename': os.path.join(PROJECT_ROOT, 'backend.log'), 'class': 'logging.handlers.RotatingFileHandler', 'maxBytes': 1 * 1024 * 1024, 'backupCount': 2, diff --git a/substrabackend/substrabackend/settings/prod.py b/backend/backend/settings/prod.py similarity index 92% rename from substrabackend/substrabackend/settings/prod.py rename to backend/backend/settings/prod.py index c01251610..755097d88 100644 --- a/substrabackend/substrabackend/settings/prod.py +++ b/backend/backend/settings/prod.py @@ -33,9 +33,9 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': os.environ.get(f'SUBSTRABACKEND_{ORG_DB_NAME}_DB_NAME', f'substrabackend_{ORG_NAME}'), - 'USER': os.environ.get('SUBSTRABACKEND_DB_USER', 'substrabackend'), - 'PASSWORD': os.environ.get('SUBSTRABACKEND_DB_PWD', 'substrabackend'), + 'NAME': os.environ.get(f'BACKEND_{ORG_DB_NAME}_DB_NAME', f'backend_{ORG_NAME}'), + 'USER': os.environ.get('BACKEND_DB_USER', 'backend'), + 'PASSWORD': os.environ.get('BACKEND_DB_PWD', 'backend'), 'HOST': os.environ.get('DATABASE_HOST', 'localhost'), 'PORT': 5432, } diff --git a/substrabackend/node/signals/__init__.py b/backend/backend/settings/server/__init__.py similarity index 100% rename from substrabackend/node/signals/__init__.py rename to backend/backend/settings/server/__init__.py diff --git a/substrabackend/substrabackend/settings/server/dev.py b/backend/backend/settings/server/dev.py similarity index 100% rename from substrabackend/substrabackend/settings/server/dev.py rename to backend/backend/settings/server/dev.py diff --git a/substrabackend/node/signals/node/__init__.py b/backend/backend/settings/server/nobasicauth/__init__.py similarity index 100% rename from substrabackend/node/signals/node/__init__.py rename to backend/backend/settings/server/nobasicauth/__init__.py diff --git a/substrabackend/substrabackend/settings/server/nobasicauth/dev.py b/backend/backend/settings/server/nobasicauth/dev.py similarity index 100% rename from substrabackend/substrabackend/settings/server/nobasicauth/dev.py rename to backend/backend/settings/server/nobasicauth/dev.py diff --git a/substrabackend/substrabackend/settings/server/nobasicauth/prod.py b/backend/backend/settings/server/nobasicauth/prod.py similarity index 100% rename from substrabackend/substrabackend/settings/server/nobasicauth/prod.py rename to backend/backend/settings/server/nobasicauth/prod.py diff --git a/substrabackend/substrabackend/settings/server/prod.py b/backend/backend/settings/server/prod.py similarity index 100% rename from substrabackend/substrabackend/settings/server/prod.py rename to backend/backend/settings/server/prod.py diff --git a/substrabackend/substrabackend/settings/test.py b/backend/backend/settings/test.py similarity index 100% rename from substrabackend/substrabackend/settings/test.py rename to backend/backend/settings/test.py diff --git a/substrabackend/substrabackend/urls.py b/backend/backend/urls.py similarity index 93% rename from substrabackend/substrabackend/urls.py rename to backend/backend/urls.py index 57585ee8b..0ffe8eb38 100644 --- a/substrabackend/substrabackend/urls.py +++ b/backend/backend/urls.py @@ -1,4 +1,4 @@ -"""substrabackend URL Configuration +"""backend URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.0/topics/http/urls/ @@ -19,7 +19,7 @@ from django.conf.urls.static import static from django.urls import include -from substrabackend.views import schema_view +from backend.views import schema_view from substrapp.urls import router from node.urls import router as nodeRouter diff --git a/substrabackend/substrabackend/views.py b/backend/backend/views.py similarity index 100% rename from substrabackend/substrabackend/views.py rename to backend/backend/views.py diff --git a/substrabackend/substrabackend/wsgi.py b/backend/backend/wsgi.py similarity index 70% rename from substrabackend/substrabackend/wsgi.py rename to backend/backend/wsgi.py index 25cb3a547..7bd8cebfc 100644 --- a/substrabackend/substrabackend/wsgi.py +++ b/backend/backend/wsgi.py @@ -1,5 +1,5 @@ """ -WSGI config for substrabackend project. +WSGI config for backend project. It exposes the WSGI callable as a module-level variable named ``application``. @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "substrabackend.settings.prod") +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings.prod") application = get_wsgi_application() diff --git a/substrabackend/events/__init__.py b/backend/events/__init__.py similarity index 100% rename from substrabackend/events/__init__.py rename to backend/events/__init__.py diff --git a/substrabackend/events/apps.py b/backend/events/apps.py similarity index 98% rename from substrabackend/events/apps.py rename to backend/events/apps.py index 531e0d2ed..cc5a10a4c 100644 --- a/substrabackend/events/apps.py +++ b/backend/events/apps.py @@ -82,7 +82,7 @@ def wait(): chaincode_name = LEDGER['chaincode_name'] peer = LEDGER['peer'] - peer_port = peer["port"][os.environ.get('SUBSTRABACKEND_PEER_PORT', 'external')] + peer_port = peer["port"][os.environ.get('BACKEND_PEER_PORT', 'external')] client = Client() diff --git a/substrabackend/libs/SQLPrintingMiddleware.py b/backend/libs/SQLPrintingMiddleware.py similarity index 100% rename from substrabackend/libs/SQLPrintingMiddleware.py rename to backend/libs/SQLPrintingMiddleware.py diff --git a/substrabackend/node/tests/__init__.py b/backend/libs/__init__.py similarity index 100% rename from substrabackend/node/tests/__init__.py rename to backend/libs/__init__.py diff --git a/substrabackend/libs/authentication.py b/backend/libs/authentication.py similarity index 100% rename from substrabackend/libs/authentication.py rename to backend/libs/authentication.py diff --git a/substrabackend/libs/gen_secret_key.py b/backend/libs/gen_secret_key.py similarity index 100% rename from substrabackend/libs/gen_secret_key.py rename to backend/libs/gen_secret_key.py diff --git a/substrabackend/libs/pagination.py b/backend/libs/pagination.py similarity index 100% rename from substrabackend/libs/pagination.py rename to backend/libs/pagination.py diff --git a/substrabackend/libs/serializers.py b/backend/libs/serializers.py similarity index 100% rename from substrabackend/libs/serializers.py rename to backend/libs/serializers.py diff --git a/substrabackend/libs/timestampModel.py b/backend/libs/timestampModel.py similarity index 100% rename from substrabackend/libs/timestampModel.py rename to backend/libs/timestampModel.py diff --git a/substrabackend/libs/versioning.py b/backend/libs/versioning.py similarity index 100% rename from substrabackend/libs/versioning.py rename to backend/libs/versioning.py diff --git a/substrabackend/manage.py b/backend/manage.py similarity index 84% rename from substrabackend/manage.py rename to backend/manage.py index 44c612146..09333153a 100755 --- a/substrabackend/manage.py +++ b/backend/manage.py @@ -3,7 +3,7 @@ import sys if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "substrabackend.settings.dev") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "backend.settings.dev") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/substrabackend/node-register/__init__.py b/backend/node-register/__init__.py similarity index 100% rename from substrabackend/node-register/__init__.py rename to backend/node-register/__init__.py diff --git a/substrabackend/node-register/apps.py b/backend/node-register/apps.py similarity index 100% rename from substrabackend/node-register/apps.py rename to backend/node-register/apps.py diff --git a/substrabackend/node/__init__.py b/backend/node/__init__.py similarity index 100% rename from substrabackend/node/__init__.py rename to backend/node/__init__.py diff --git a/substrabackend/node/apps.py b/backend/node/apps.py similarity index 100% rename from substrabackend/node/apps.py rename to backend/node/apps.py diff --git a/substrabackend/node/authentication.py b/backend/node/authentication.py similarity index 100% rename from substrabackend/node/authentication.py rename to backend/node/authentication.py diff --git a/substrabackend/node/fixtures/nodes-chunantes.yaml b/backend/node/fixtures/nodes-chunantes.yaml similarity index 100% rename from substrabackend/node/fixtures/nodes-chunantes.yaml rename to backend/node/fixtures/nodes-chunantes.yaml diff --git a/substrabackend/node/fixtures/nodes-clb.yaml b/backend/node/fixtures/nodes-clb.yaml similarity index 100% rename from substrabackend/node/fixtures/nodes-clb.yaml rename to backend/node/fixtures/nodes-clb.yaml diff --git a/substrabackend/node/fixtures/nodes-owkin.yaml b/backend/node/fixtures/nodes-owkin.yaml similarity index 100% rename from substrabackend/node/fixtures/nodes-owkin.yaml rename to backend/node/fixtures/nodes-owkin.yaml diff --git a/substrabackend/node/management/commands/create_incoming_node.py b/backend/node/management/commands/create_incoming_node.py similarity index 100% rename from substrabackend/node/management/commands/create_incoming_node.py rename to backend/node/management/commands/create_incoming_node.py diff --git a/substrabackend/node/management/commands/create_outgoing_node.py b/backend/node/management/commands/create_outgoing_node.py similarity index 100% rename from substrabackend/node/management/commands/create_outgoing_node.py rename to backend/node/management/commands/create_outgoing_node.py diff --git a/substrabackend/node/management/commands/get_incoming_node.py b/backend/node/management/commands/get_incoming_node.py similarity index 100% rename from substrabackend/node/management/commands/get_incoming_node.py rename to backend/node/management/commands/get_incoming_node.py diff --git a/substrabackend/node/management/commands/get_outgoing_node.py b/backend/node/management/commands/get_outgoing_node.py similarity index 100% rename from substrabackend/node/management/commands/get_outgoing_node.py rename to backend/node/management/commands/get_outgoing_node.py diff --git a/substrabackend/node/migrations/0001_initial.py b/backend/node/migrations/0001_initial.py similarity index 100% rename from substrabackend/node/migrations/0001_initial.py rename to backend/node/migrations/0001_initial.py diff --git a/substrabackend/node/migrations/0002_nodeuser.py b/backend/node/migrations/0002_nodeuser.py similarity index 100% rename from substrabackend/node/migrations/0002_nodeuser.py rename to backend/node/migrations/0002_nodeuser.py diff --git a/substrabackend/node/tests/views/__init__.py b/backend/node/migrations/__init__.py similarity index 100% rename from substrabackend/node/tests/views/__init__.py rename to backend/node/migrations/__init__.py diff --git a/substrabackend/node/models.py b/backend/node/models.py similarity index 100% rename from substrabackend/node/models.py rename to backend/node/models.py diff --git a/substrabackend/substrabackend/settings/__init__.py b/backend/node/signals/__init__.py similarity index 100% rename from substrabackend/substrabackend/settings/__init__.py rename to backend/node/signals/__init__.py diff --git a/substrabackend/substrabackend/settings/deps/__init__.py b/backend/node/signals/node/__init__.py similarity index 100% rename from substrabackend/substrabackend/settings/deps/__init__.py rename to backend/node/signals/node/__init__.py diff --git a/substrabackend/node/signals/node/pre_save.py b/backend/node/signals/node/pre_save.py similarity index 100% rename from substrabackend/node/signals/node/pre_save.py rename to backend/node/signals/node/pre_save.py diff --git a/substrabackend/substrabackend/settings/server/__init__.py b/backend/node/tests/__init__.py similarity index 100% rename from substrabackend/substrabackend/settings/server/__init__.py rename to backend/node/tests/__init__.py diff --git a/substrabackend/substrabackend/settings/server/nobasicauth/__init__.py b/backend/node/tests/views/__init__.py similarity index 100% rename from substrabackend/substrabackend/settings/server/nobasicauth/__init__.py rename to backend/node/tests/views/__init__.py diff --git a/substrabackend/node/tests/views/tests_views_node.py b/backend/node/tests/views/tests_views_node.py similarity index 100% rename from substrabackend/node/tests/views/tests_views_node.py rename to backend/node/tests/views/tests_views_node.py diff --git a/substrabackend/node/urls.py b/backend/node/urls.py similarity index 100% rename from substrabackend/node/urls.py rename to backend/node/urls.py diff --git a/substrabackend/node/views/__init__.py b/backend/node/views/__init__.py similarity index 100% rename from substrabackend/node/views/__init__.py rename to backend/node/views/__init__.py diff --git a/substrabackend/node/views/node.py b/backend/node/views/node.py similarity index 100% rename from substrabackend/node/views/node.py rename to backend/node/views/node.py diff --git a/substrabackend/requirements.txt b/backend/requirements.txt similarity index 100% rename from substrabackend/requirements.txt rename to backend/requirements.txt diff --git a/substrabackend/substrapp/__init__.py b/backend/substrapp/__init__.py similarity index 100% rename from substrabackend/substrapp/__init__.py rename to backend/substrapp/__init__.py diff --git a/substrabackend/substrapp/admin.py b/backend/substrapp/admin.py similarity index 100% rename from substrabackend/substrapp/admin.py rename to backend/substrapp/admin.py diff --git a/substrabackend/substrapp/apps.py b/backend/substrapp/apps.py similarity index 100% rename from substrabackend/substrapp/apps.py rename to backend/substrapp/apps.py diff --git a/substrabackend/substrapp/ledger_utils.py b/backend/substrapp/ledger_utils.py similarity index 100% rename from substrabackend/substrapp/ledger_utils.py rename to backend/substrapp/ledger_utils.py diff --git a/substrabackend/substrapp/management/commands/bulkcreatedatasample.py b/backend/substrapp/management/commands/bulkcreatedatasample.py similarity index 100% rename from substrabackend/substrapp/management/commands/bulkcreatedatasample.py rename to backend/substrapp/management/commands/bulkcreatedatasample.py diff --git a/substrabackend/substrapp/management/commands/createdataset.py b/backend/substrapp/management/commands/createdataset.py similarity index 100% rename from substrabackend/substrapp/management/commands/createdataset.py rename to backend/substrapp/management/commands/createdataset.py diff --git a/substrabackend/substrapp/management/commands/createobjective.py b/backend/substrapp/management/commands/createobjective.py similarity index 100% rename from substrabackend/substrapp/management/commands/createobjective.py rename to backend/substrapp/management/commands/createobjective.py diff --git a/substrabackend/substrapp/management/tests/tests_bulkcreatedatasample.py b/backend/substrapp/management/tests/tests_bulkcreatedatasample.py similarity index 100% rename from substrabackend/substrapp/management/tests/tests_bulkcreatedatasample.py rename to backend/substrapp/management/tests/tests_bulkcreatedatasample.py diff --git a/substrabackend/substrapp/management/tests/tests_createdatamanager.py b/backend/substrapp/management/tests/tests_createdatamanager.py similarity index 100% rename from substrabackend/substrapp/management/tests/tests_createdatamanager.py rename to backend/substrapp/management/tests/tests_createdatamanager.py diff --git a/substrabackend/substrapp/management/tests/tests_createobjective.py b/backend/substrapp/management/tests/tests_createobjective.py similarity index 100% rename from substrabackend/substrapp/management/tests/tests_createobjective.py rename to backend/substrapp/management/tests/tests_createobjective.py diff --git a/substrabackend/substrapp/management/utils/__init__.py b/backend/substrapp/management/utils/__init__.py similarity index 100% rename from substrabackend/substrapp/management/utils/__init__.py rename to backend/substrapp/management/utils/__init__.py diff --git a/substrabackend/substrapp/management/utils/localRequest.py b/backend/substrapp/management/utils/localRequest.py similarity index 100% rename from substrabackend/substrapp/management/utils/localRequest.py rename to backend/substrapp/management/utils/localRequest.py diff --git a/substrabackend/substrapp/migrations/0001_initial.py b/backend/substrapp/migrations/0001_initial.py similarity index 100% rename from substrabackend/substrapp/migrations/0001_initial.py rename to backend/substrapp/migrations/0001_initial.py diff --git a/substrabackend/substrapp/migrations/__init__.py b/backend/substrapp/migrations/__init__.py similarity index 100% rename from substrabackend/substrapp/migrations/__init__.py rename to backend/substrapp/migrations/__init__.py diff --git a/substrabackend/substrapp/models/__init__.py b/backend/substrapp/models/__init__.py similarity index 100% rename from substrabackend/substrapp/models/__init__.py rename to backend/substrapp/models/__init__.py diff --git a/substrabackend/substrapp/models/algo.py b/backend/substrapp/models/algo.py similarity index 100% rename from substrabackend/substrapp/models/algo.py rename to backend/substrapp/models/algo.py diff --git a/substrabackend/substrapp/models/datamanager.py b/backend/substrapp/models/datamanager.py similarity index 100% rename from substrabackend/substrapp/models/datamanager.py rename to backend/substrapp/models/datamanager.py diff --git a/substrabackend/substrapp/models/datasample.py b/backend/substrapp/models/datasample.py similarity index 100% rename from substrabackend/substrapp/models/datasample.py rename to backend/substrapp/models/datasample.py diff --git a/substrabackend/substrapp/models/model.py b/backend/substrapp/models/model.py similarity index 100% rename from substrabackend/substrapp/models/model.py rename to backend/substrapp/models/model.py diff --git a/substrabackend/substrapp/models/objective.py b/backend/substrapp/models/objective.py similarity index 100% rename from substrabackend/substrapp/models/objective.py rename to backend/substrapp/models/objective.py diff --git a/substrabackend/substrapp/serializers/__init__.py b/backend/substrapp/serializers/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/__init__.py rename to backend/substrapp/serializers/__init__.py diff --git a/substrabackend/substrapp/serializers/algo.py b/backend/substrapp/serializers/algo.py similarity index 100% rename from substrabackend/substrapp/serializers/algo.py rename to backend/substrapp/serializers/algo.py diff --git a/substrabackend/substrapp/serializers/datamanager.py b/backend/substrapp/serializers/datamanager.py similarity index 100% rename from substrabackend/substrapp/serializers/datamanager.py rename to backend/substrapp/serializers/datamanager.py diff --git a/substrabackend/substrapp/serializers/datasample.py b/backend/substrapp/serializers/datasample.py similarity index 100% rename from substrabackend/substrapp/serializers/datasample.py rename to backend/substrapp/serializers/datasample.py diff --git a/substrabackend/substrapp/serializers/ledger/__init__.py b/backend/substrapp/serializers/ledger/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/__init__.py rename to backend/substrapp/serializers/ledger/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/algo/__init__.py b/backend/substrapp/serializers/ledger/algo/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/algo/__init__.py rename to backend/substrapp/serializers/ledger/algo/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/algo/serializer.py b/backend/substrapp/serializers/ledger/algo/serializer.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/algo/serializer.py rename to backend/substrapp/serializers/ledger/algo/serializer.py diff --git a/substrabackend/substrapp/serializers/ledger/algo/tasks.py b/backend/substrapp/serializers/ledger/algo/tasks.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/algo/tasks.py rename to backend/substrapp/serializers/ledger/algo/tasks.py diff --git a/substrabackend/substrapp/serializers/ledger/algo/util.py b/backend/substrapp/serializers/ledger/algo/util.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/algo/util.py rename to backend/substrapp/serializers/ledger/algo/util.py diff --git a/substrabackend/substrapp/serializers/ledger/computeplan/__init__.py b/backend/substrapp/serializers/ledger/computeplan/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/computeplan/__init__.py rename to backend/substrapp/serializers/ledger/computeplan/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/computeplan/serializer.py b/backend/substrapp/serializers/ledger/computeplan/serializer.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/computeplan/serializer.py rename to backend/substrapp/serializers/ledger/computeplan/serializer.py diff --git a/substrabackend/substrapp/serializers/ledger/computeplan/tasks.py b/backend/substrapp/serializers/ledger/computeplan/tasks.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/computeplan/tasks.py rename to backend/substrapp/serializers/ledger/computeplan/tasks.py diff --git a/substrabackend/substrapp/serializers/ledger/computeplan/util.py b/backend/substrapp/serializers/ledger/computeplan/util.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/computeplan/util.py rename to backend/substrapp/serializers/ledger/computeplan/util.py diff --git a/substrabackend/substrapp/serializers/ledger/datamanager/__init__.py b/backend/substrapp/serializers/ledger/datamanager/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/datamanager/__init__.py rename to backend/substrapp/serializers/ledger/datamanager/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/datamanager/serializer.py b/backend/substrapp/serializers/ledger/datamanager/serializer.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/datamanager/serializer.py rename to backend/substrapp/serializers/ledger/datamanager/serializer.py diff --git a/substrabackend/substrapp/serializers/ledger/datamanager/tasks.py b/backend/substrapp/serializers/ledger/datamanager/tasks.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/datamanager/tasks.py rename to backend/substrapp/serializers/ledger/datamanager/tasks.py diff --git a/substrabackend/substrapp/serializers/ledger/datamanager/util.py b/backend/substrapp/serializers/ledger/datamanager/util.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/datamanager/util.py rename to backend/substrapp/serializers/ledger/datamanager/util.py diff --git a/substrabackend/substrapp/serializers/ledger/datasample/__init__.py b/backend/substrapp/serializers/ledger/datasample/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/datasample/__init__.py rename to backend/substrapp/serializers/ledger/datasample/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/datasample/serializer.py b/backend/substrapp/serializers/ledger/datasample/serializer.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/datasample/serializer.py rename to backend/substrapp/serializers/ledger/datasample/serializer.py diff --git a/substrabackend/substrapp/serializers/ledger/datasample/tasks.py b/backend/substrapp/serializers/ledger/datasample/tasks.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/datasample/tasks.py rename to backend/substrapp/serializers/ledger/datasample/tasks.py diff --git a/substrabackend/substrapp/serializers/ledger/datasample/util.py b/backend/substrapp/serializers/ledger/datasample/util.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/datasample/util.py rename to backend/substrapp/serializers/ledger/datasample/util.py diff --git a/substrabackend/substrapp/serializers/ledger/model/__init__.py b/backend/substrapp/serializers/ledger/model/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/model/__init__.py rename to backend/substrapp/serializers/ledger/model/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/model/serializer.py b/backend/substrapp/serializers/ledger/model/serializer.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/model/serializer.py rename to backend/substrapp/serializers/ledger/model/serializer.py diff --git a/substrabackend/substrapp/serializers/ledger/objective/__init__.py b/backend/substrapp/serializers/ledger/objective/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/objective/__init__.py rename to backend/substrapp/serializers/ledger/objective/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/objective/serializer.py b/backend/substrapp/serializers/ledger/objective/serializer.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/objective/serializer.py rename to backend/substrapp/serializers/ledger/objective/serializer.py diff --git a/substrabackend/substrapp/serializers/ledger/objective/tasks.py b/backend/substrapp/serializers/ledger/objective/tasks.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/objective/tasks.py rename to backend/substrapp/serializers/ledger/objective/tasks.py diff --git a/substrabackend/substrapp/serializers/ledger/objective/util.py b/backend/substrapp/serializers/ledger/objective/util.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/objective/util.py rename to backend/substrapp/serializers/ledger/objective/util.py diff --git a/substrabackend/substrapp/serializers/ledger/testtuple/__init__.py b/backend/substrapp/serializers/ledger/testtuple/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/testtuple/__init__.py rename to backend/substrapp/serializers/ledger/testtuple/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/testtuple/serializer.py b/backend/substrapp/serializers/ledger/testtuple/serializer.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/testtuple/serializer.py rename to backend/substrapp/serializers/ledger/testtuple/serializer.py diff --git a/substrabackend/substrapp/serializers/ledger/testtuple/tasks.py b/backend/substrapp/serializers/ledger/testtuple/tasks.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/testtuple/tasks.py rename to backend/substrapp/serializers/ledger/testtuple/tasks.py diff --git a/substrabackend/substrapp/serializers/ledger/testtuple/util.py b/backend/substrapp/serializers/ledger/testtuple/util.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/testtuple/util.py rename to backend/substrapp/serializers/ledger/testtuple/util.py diff --git a/substrabackend/substrapp/serializers/ledger/traintuple/__init__.py b/backend/substrapp/serializers/ledger/traintuple/__init__.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/traintuple/__init__.py rename to backend/substrapp/serializers/ledger/traintuple/__init__.py diff --git a/substrabackend/substrapp/serializers/ledger/traintuple/serializer.py b/backend/substrapp/serializers/ledger/traintuple/serializer.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/traintuple/serializer.py rename to backend/substrapp/serializers/ledger/traintuple/serializer.py diff --git a/substrabackend/substrapp/serializers/ledger/traintuple/tasks.py b/backend/substrapp/serializers/ledger/traintuple/tasks.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/traintuple/tasks.py rename to backend/substrapp/serializers/ledger/traintuple/tasks.py diff --git a/substrabackend/substrapp/serializers/ledger/traintuple/util.py b/backend/substrapp/serializers/ledger/traintuple/util.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/traintuple/util.py rename to backend/substrapp/serializers/ledger/traintuple/util.py diff --git a/substrabackend/substrapp/serializers/ledger/utils.py b/backend/substrapp/serializers/ledger/utils.py similarity index 100% rename from substrabackend/substrapp/serializers/ledger/utils.py rename to backend/substrapp/serializers/ledger/utils.py diff --git a/substrabackend/substrapp/serializers/model.py b/backend/substrapp/serializers/model.py similarity index 100% rename from substrabackend/substrapp/serializers/model.py rename to backend/substrapp/serializers/model.py diff --git a/substrabackend/substrapp/serializers/objective.py b/backend/substrapp/serializers/objective.py similarity index 100% rename from substrabackend/substrapp/serializers/objective.py rename to backend/substrapp/serializers/objective.py diff --git a/substrabackend/substrapp/serializers/utils.py b/backend/substrapp/serializers/utils.py similarity index 100% rename from substrabackend/substrapp/serializers/utils.py rename to backend/substrapp/serializers/utils.py diff --git a/substrabackend/substrapp/signals/__init__.py b/backend/substrapp/signals/__init__.py similarity index 100% rename from substrabackend/substrapp/signals/__init__.py rename to backend/substrapp/signals/__init__.py diff --git a/substrabackend/substrapp/signals/algo/__init__.py b/backend/substrapp/signals/algo/__init__.py similarity index 100% rename from substrabackend/substrapp/signals/algo/__init__.py rename to backend/substrapp/signals/algo/__init__.py diff --git a/substrabackend/substrapp/signals/algo/post_delete.py b/backend/substrapp/signals/algo/post_delete.py similarity index 100% rename from substrabackend/substrapp/signals/algo/post_delete.py rename to backend/substrapp/signals/algo/post_delete.py diff --git a/substrabackend/substrapp/signals/datamanager/__init__.py b/backend/substrapp/signals/datamanager/__init__.py similarity index 100% rename from substrabackend/substrapp/signals/datamanager/__init__.py rename to backend/substrapp/signals/datamanager/__init__.py diff --git a/substrabackend/substrapp/signals/datamanager/post_delete.py b/backend/substrapp/signals/datamanager/post_delete.py similarity index 100% rename from substrabackend/substrapp/signals/datamanager/post_delete.py rename to backend/substrapp/signals/datamanager/post_delete.py diff --git a/substrabackend/substrapp/signals/datasample/__init__.py b/backend/substrapp/signals/datasample/__init__.py similarity index 100% rename from substrabackend/substrapp/signals/datasample/__init__.py rename to backend/substrapp/signals/datasample/__init__.py diff --git a/substrabackend/substrapp/signals/datasample/post_delete.py b/backend/substrapp/signals/datasample/post_delete.py similarity index 100% rename from substrabackend/substrapp/signals/datasample/post_delete.py rename to backend/substrapp/signals/datasample/post_delete.py diff --git a/substrabackend/substrapp/signals/datasample/pre_save.py b/backend/substrapp/signals/datasample/pre_save.py similarity index 100% rename from substrabackend/substrapp/signals/datasample/pre_save.py rename to backend/substrapp/signals/datasample/pre_save.py diff --git a/substrabackend/substrapp/signals/model/__init__.py b/backend/substrapp/signals/model/__init__.py similarity index 100% rename from substrabackend/substrapp/signals/model/__init__.py rename to backend/substrapp/signals/model/__init__.py diff --git a/substrabackend/substrapp/signals/model/post_delete.py b/backend/substrapp/signals/model/post_delete.py similarity index 100% rename from substrabackend/substrapp/signals/model/post_delete.py rename to backend/substrapp/signals/model/post_delete.py diff --git a/substrabackend/substrapp/signals/objective/__init__.py b/backend/substrapp/signals/objective/__init__.py similarity index 100% rename from substrabackend/substrapp/signals/objective/__init__.py rename to backend/substrapp/signals/objective/__init__.py diff --git a/substrabackend/substrapp/signals/objective/post_delete.py b/backend/substrapp/signals/objective/post_delete.py similarity index 100% rename from substrabackend/substrapp/signals/objective/post_delete.py rename to backend/substrapp/signals/objective/post_delete.py diff --git a/substrabackend/substrapp/tasks/__init__.py b/backend/substrapp/tasks/__init__.py similarity index 100% rename from substrabackend/substrapp/tasks/__init__.py rename to backend/substrapp/tasks/__init__.py diff --git a/substrabackend/substrapp/tasks/exception_handler.py b/backend/substrapp/tasks/exception_handler.py similarity index 96% rename from substrabackend/substrapp/tasks/exception_handler.py rename to backend/substrapp/tasks/exception_handler.py index b2eed83ce..e97288240 100644 --- a/substrabackend/substrapp/tasks/exception_handler.py +++ b/backend/substrapp/tasks/exception_handler.py @@ -91,7 +91,7 @@ def find_exception(module): def generate_exceptions_map(append=True): - os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabackend.settings.prod' + os.environ['DJANGO_SETTINGS_MODULE'] = 'backend.settings.prod' import requests.exceptions import celery.exceptions @@ -144,7 +144,7 @@ def generate_exceptions_map(append=True): if __name__ == '__main__': - os.environ['DJANGO_SETTINGS_MODULE'] = 'substrabackend.settings.common' + os.environ['DJANGO_SETTINGS_MODULE'] = 'backend.settings.common' json_exceptions = generate_exceptions_map() with open(EXCEPTION_PATH, 'w') as outfile: json.dump(json_exceptions, outfile, indent=4) diff --git a/substrabackend/substrapp/tasks/exceptions.json b/backend/substrapp/tasks/exceptions.json similarity index 100% rename from substrabackend/substrapp/tasks/exceptions.json rename to backend/substrapp/tasks/exceptions.json diff --git a/substrabackend/substrapp/tasks/tasks.py b/backend/substrapp/tasks/tasks.py similarity index 99% rename from substrabackend/substrapp/tasks/tasks.py rename to backend/substrapp/tasks/tasks.py index 4949f654a..203a7b00d 100644 --- a/substrabackend/substrapp/tasks/tasks.py +++ b/backend/substrapp/tasks/tasks.py @@ -16,7 +16,7 @@ from celery.result import AsyncResult from celery.exceptions import Ignore -from substrabackend.celery import app +from backend.celery import app from substrapp.utils import get_hash, get_owner, create_directory, uncompress_content from substrapp.ledger_utils import (log_start_tuple, log_success_tuple, log_fail_tuple, query_tuples, LedgerError, LedgerStatusError, get_object_from_ledger) diff --git a/substrabackend/substrapp/tasks/utils.py b/backend/substrapp/tasks/utils.py similarity index 100% rename from substrabackend/substrapp/tasks/utils.py rename to backend/substrapp/tasks/utils.py diff --git a/substrabackend/substrapp/tests/__init__.py b/backend/substrapp/tests/__init__.py similarity index 100% rename from substrabackend/substrapp/tests/__init__.py rename to backend/substrapp/tests/__init__.py diff --git a/substrabackend/substrapp/tests/assets.py b/backend/substrapp/tests/assets.py similarity index 100% rename from substrabackend/substrapp/tests/assets.py rename to backend/substrapp/tests/assets.py diff --git a/substrabackend/substrapp/tests/common.py b/backend/substrapp/tests/common.py similarity index 100% rename from substrabackend/substrapp/tests/common.py rename to backend/substrapp/tests/common.py diff --git a/substrabackend/substrapp/tests/generate_assets.py b/backend/substrapp/tests/generate_assets.py similarity index 100% rename from substrabackend/substrapp/tests/generate_assets.py rename to backend/substrapp/tests/generate_assets.py diff --git a/substrabackend/substrapp/tests/query/__init__.py b/backend/substrapp/tests/query/__init__.py similarity index 100% rename from substrabackend/substrapp/tests/query/__init__.py rename to backend/substrapp/tests/query/__init__.py diff --git a/substrabackend/substrapp/tests/query/tests_query_algo.py b/backend/substrapp/tests/query/tests_query_algo.py similarity index 100% rename from substrabackend/substrapp/tests/query/tests_query_algo.py rename to backend/substrapp/tests/query/tests_query_algo.py diff --git a/substrabackend/substrapp/tests/query/tests_query_datamanager.py b/backend/substrapp/tests/query/tests_query_datamanager.py similarity index 100% rename from substrabackend/substrapp/tests/query/tests_query_datamanager.py rename to backend/substrapp/tests/query/tests_query_datamanager.py diff --git a/substrabackend/substrapp/tests/query/tests_query_datasample.py b/backend/substrapp/tests/query/tests_query_datasample.py similarity index 100% rename from substrabackend/substrapp/tests/query/tests_query_datasample.py rename to backend/substrapp/tests/query/tests_query_datasample.py diff --git a/substrabackend/substrapp/tests/query/tests_query_objective.py b/backend/substrapp/tests/query/tests_query_objective.py similarity index 100% rename from substrabackend/substrapp/tests/query/tests_query_objective.py rename to backend/substrapp/tests/query/tests_query_objective.py diff --git a/substrabackend/substrapp/tests/query/tests_query_tuples.py b/backend/substrapp/tests/query/tests_query_tuples.py similarity index 100% rename from substrabackend/substrapp/tests/query/tests_query_tuples.py rename to backend/substrapp/tests/query/tests_query_tuples.py diff --git a/substrabackend/substrapp/tests/tests_exception.py b/backend/substrapp/tests/tests_exception.py similarity index 100% rename from substrabackend/substrapp/tests/tests_exception.py rename to backend/substrapp/tests/tests_exception.py diff --git a/substrabackend/substrapp/tests/tests_misc.py b/backend/substrapp/tests/tests_misc.py similarity index 100% rename from substrabackend/substrapp/tests/tests_misc.py rename to backend/substrapp/tests/tests_misc.py diff --git a/substrabackend/substrapp/tests/tests_model.py b/backend/substrapp/tests/tests_model.py similarity index 100% rename from substrabackend/substrapp/tests/tests_model.py rename to backend/substrapp/tests/tests_model.py diff --git a/substrabackend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py similarity index 100% rename from substrabackend/substrapp/tests/tests_tasks.py rename to backend/substrapp/tests/tests_tasks.py diff --git a/substrabackend/substrapp/tests/views/__init__.py b/backend/substrapp/tests/views/__init__.py similarity index 100% rename from substrabackend/substrapp/tests/views/__init__.py rename to backend/substrapp/tests/views/__init__.py diff --git a/substrabackend/substrapp/tests/views/test_views_authentication.py b/backend/substrapp/tests/views/test_views_authentication.py similarity index 100% rename from substrabackend/substrapp/tests/views/test_views_authentication.py rename to backend/substrapp/tests/views/test_views_authentication.py diff --git a/substrabackend/substrapp/tests/views/tests_utils.py b/backend/substrapp/tests/views/tests_utils.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_utils.py rename to backend/substrapp/tests/views/tests_utils.py diff --git a/substrabackend/substrapp/tests/views/tests_views.py b/backend/substrapp/tests/views/tests_views.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views.py rename to backend/substrapp/tests/views/tests_views.py diff --git a/substrabackend/substrapp/tests/views/tests_views_algo.py b/backend/substrapp/tests/views/tests_views_algo.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views_algo.py rename to backend/substrapp/tests/views/tests_views_algo.py diff --git a/substrabackend/substrapp/tests/views/tests_views_computeplan.py b/backend/substrapp/tests/views/tests_views_computeplan.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views_computeplan.py rename to backend/substrapp/tests/views/tests_views_computeplan.py diff --git a/substrabackend/substrapp/tests/views/tests_views_datamanager.py b/backend/substrapp/tests/views/tests_views_datamanager.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views_datamanager.py rename to backend/substrapp/tests/views/tests_views_datamanager.py diff --git a/substrabackend/substrapp/tests/views/tests_views_datasample.py b/backend/substrapp/tests/views/tests_views_datasample.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views_datasample.py rename to backend/substrapp/tests/views/tests_views_datasample.py diff --git a/substrabackend/substrapp/tests/views/tests_views_model.py b/backend/substrapp/tests/views/tests_views_model.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views_model.py rename to backend/substrapp/tests/views/tests_views_model.py diff --git a/substrabackend/substrapp/tests/views/tests_views_objective.py b/backend/substrapp/tests/views/tests_views_objective.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views_objective.py rename to backend/substrapp/tests/views/tests_views_objective.py diff --git a/substrabackend/substrapp/tests/views/tests_views_task.py b/backend/substrapp/tests/views/tests_views_task.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views_task.py rename to backend/substrapp/tests/views/tests_views_task.py diff --git a/substrabackend/substrapp/tests/views/tests_views_tuples.py b/backend/substrapp/tests/views/tests_views_tuples.py similarity index 100% rename from substrabackend/substrapp/tests/views/tests_views_tuples.py rename to backend/substrapp/tests/views/tests_views_tuples.py diff --git a/substrabackend/substrapp/urls.py b/backend/substrapp/urls.py similarity index 100% rename from substrabackend/substrapp/urls.py rename to backend/substrapp/urls.py diff --git a/substrabackend/substrapp/utils.py b/backend/substrapp/utils.py similarity index 100% rename from substrabackend/substrapp/utils.py rename to backend/substrapp/utils.py diff --git a/substrabackend/substrapp/views/__init__.py b/backend/substrapp/views/__init__.py similarity index 100% rename from substrabackend/substrapp/views/__init__.py rename to backend/substrapp/views/__init__.py diff --git a/substrabackend/substrapp/views/algo.py b/backend/substrapp/views/algo.py similarity index 100% rename from substrabackend/substrapp/views/algo.py rename to backend/substrapp/views/algo.py diff --git a/substrabackend/substrapp/views/computeplan.py b/backend/substrapp/views/computeplan.py similarity index 100% rename from substrabackend/substrapp/views/computeplan.py rename to backend/substrapp/views/computeplan.py diff --git a/substrabackend/substrapp/views/datamanager.py b/backend/substrapp/views/datamanager.py similarity index 100% rename from substrabackend/substrapp/views/datamanager.py rename to backend/substrapp/views/datamanager.py diff --git a/substrabackend/substrapp/views/datasample.py b/backend/substrapp/views/datasample.py similarity index 100% rename from substrabackend/substrapp/views/datasample.py rename to backend/substrapp/views/datasample.py diff --git a/substrabackend/substrapp/views/filters_utils.py b/backend/substrapp/views/filters_utils.py similarity index 100% rename from substrabackend/substrapp/views/filters_utils.py rename to backend/substrapp/views/filters_utils.py diff --git a/substrabackend/substrapp/views/model.py b/backend/substrapp/views/model.py similarity index 100% rename from substrabackend/substrapp/views/model.py rename to backend/substrapp/views/model.py diff --git a/substrabackend/substrapp/views/objective.py b/backend/substrapp/views/objective.py similarity index 100% rename from substrabackend/substrapp/views/objective.py rename to backend/substrapp/views/objective.py diff --git a/substrabackend/substrapp/views/task.py b/backend/substrapp/views/task.py similarity index 100% rename from substrabackend/substrapp/views/task.py rename to backend/substrapp/views/task.py diff --git a/substrabackend/substrapp/views/testtuple.py b/backend/substrapp/views/testtuple.py similarity index 100% rename from substrabackend/substrapp/views/testtuple.py rename to backend/substrapp/views/testtuple.py diff --git a/substrabackend/substrapp/views/traintuple.py b/backend/substrapp/views/traintuple.py similarity index 100% rename from substrabackend/substrapp/views/traintuple.py rename to backend/substrapp/views/traintuple.py diff --git a/substrabackend/substrapp/views/utils.py b/backend/substrapp/views/utils.py similarity index 100% rename from substrabackend/substrapp/views/utils.py rename to backend/substrapp/views/utils.py diff --git a/charts/substra-backend/templates/deployment-backend.yaml b/charts/substra-backend/templates/deployment-backend.yaml index 7c3dd2269..de4565c2e 100644 --- a/charts/substra-backend/templates/deployment-backend.yaml +++ b/charts/substra-backend/templates/deployment-backend.yaml @@ -37,25 +37,25 @@ spec: {{- end }} command: ["/bin/bash"] {{- if eq .Values.backend.settings "prod" }} - args: ["-c", "python manage.py migrate && python3 manage.py collectstatic --noinput && uwsgi --http :8000 --module substrabackend.wsgi --static-map /static=/usr/src/app/substrabackend/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=substrabackend.settings.server.{{ .Values.backend.settings }} "] + args: ["-c", "python manage.py migrate && python3 manage.py collectstatic --noinput && uwsgi --http :8000 --module backend.wsgi --static-map /static=/usr/src/app/backend/statics --master --processes 4 --threads 2 --need-app --env DJANGO_SETTINGS_MODULE=backend.settings.server.{{ .Values.backend.settings }} "] {{- else }} - args: ["-c", "python manage.py migrate && DJANGO_SETTINGS_MODULE=substrabackend.settings.server.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] + args: ["-c", "python manage.py migrate && DJANGO_SETTINGS_MODULE=backend.settings.server.{{ .Values.backend.settings }} python3 manage.py runserver --noreload 0.0.0.0:8000"] {{- end }} env: - name: ORG value: {{ .Values.organization.name }} - - name: SUBSTRABACKEND_ORG + - name: BACKEND_ORG value: {{ .Values.organization.name }} - - name: SUBSTRABACKEND_{{ .Values.organization.name | upper }}_DB_NAME + - name: BACKEND_{{ .Values.organization.name | upper }}_DB_NAME value: {{ .Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABACKEND_DB_USER + - name: BACKEND_DB_USER value: {{ .Values.postgresql.postgresqlUsername }} - - name: SUBSTRABACKEND_DB_PWD + - name: BACKEND_DB_PWD value: {{ .Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ .Release.Name }}-postgresql - name: DJANGO_SETTINGS_MODULE - value: substrabackend.settings.{{ .Values.backend.settings }} + value: backend.settings.{{ .Values.backend.settings }} - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric_cfg - name: CORE_PEER_ADDRESS_ENV @@ -77,12 +77,12 @@ spec: - name: BACK_AUTH_PASSWORD value: "" {{- end }} - - name: SUBSTRABACKEND_DEFAULT_PORT + - name: BACKEND_DEFAULT_PORT value: {{ .Values.backend.service.port | quote}} - - name: SUBSTRABACKEND_PEER_PORT + - name: BACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/substrabackend/conf.json + value: /conf/{{ .Values.organization.name }}/backend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -94,7 +94,7 @@ spec: volumeMounts: - mountPath: {{ .Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ .Values.organization.name }}/substrabackend + - mountPath: /conf/{{ .Values.organization.name }}/backend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substra-backend/templates/deployment-celerybeat.yaml b/charts/substra-backend/templates/deployment-celerybeat.yaml index 15abb78a0..3f5715ac7 100644 --- a/charts/substra-backend/templates/deployment-celerybeat.yaml +++ b/charts/substra-backend/templates/deployment-celerybeat.yaml @@ -36,12 +36,12 @@ spec: imagePullPolicy: "{{ .Values.celerybeat.image.pullPolicy }}" {{- end }} command: ["celery"] - args: ["-A", "substrabackend", "beat", "-l", "debug"] + args: ["-A", "backend", "beat", "-l", "debug"] env: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: substrabackend.settings.common + value: backend.settings.common - name: PYTHONUNBUFFERED value: "1" resources: diff --git a/charts/substra-backend/templates/deployment-flower.yaml b/charts/substra-backend/templates/deployment-flower.yaml index f01378339..30c10c97c 100644 --- a/charts/substra-backend/templates/deployment-flower.yaml +++ b/charts/substra-backend/templates/deployment-flower.yaml @@ -37,12 +37,12 @@ spec: imagePullPolicy: "{{ .Values.flower.image.pullPolicy }}" {{- end }} command: ["celery"] - args: ["flower", "-A", "substrabackend"] + args: ["flower", "-A", "backend"] env: - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: substrabackend.settings.common + value: backend.settings.common - name: PYTHONUNBUFFERED value: "1" resources: diff --git a/charts/substra-backend/templates/deployment-scheduler.yaml b/charts/substra-backend/templates/deployment-scheduler.yaml index e39d9cf63..987ca19fc 100644 --- a/charts/substra-backend/templates/deployment-scheduler.yaml +++ b/charts/substra-backend/templates/deployment-scheduler.yaml @@ -36,18 +36,18 @@ spec: imagePullPolicy: "{{ .Values.celeryworker.image.pullPolicy }}" {{- end }} command: ["celery"] - args: ["-A", "substrabackend", "worker", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},scheduler,celery", "--hostname", "{{ .Values.organization.name }}.scheduler"] + args: ["-A", "backend", "worker", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},scheduler,celery", "--hostname", "{{ .Values.organization.name }}.scheduler"] env: - name: ORG value: {{ .Values.organization.name }} - - name: SUBSTRABACKEND_ORG + - name: BACKEND_ORG value: {{ .Values.organization.name }} - - name: SUBSTRABACKEND_DEFAULT_PORT + - name: BACKEND_DEFAULT_PORT value: "8000" - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: substrabackend.settings.{{ .Values.backend.settings }} + value: backend.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" {{- with .Values.backend.auth }} @@ -70,9 +70,9 @@ spec: - name: FABRIC_LOGGING_SPEC value: debug - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/substrabackend/conf.json + value: /conf/{{ .Values.organization.name }}/backend/conf.json volumeMounts: - - mountPath: /conf/{{ .Values.organization.name }}/substrabackend + - mountPath: /conf/{{ .Values.organization.name }}/backend name: config readOnly: true - mountPath: /var/hyperledger/msp/signcerts diff --git a/charts/substra-backend/templates/deployment-worker.yaml b/charts/substra-backend/templates/deployment-worker.yaml index aa9aea088..1f8924d3b 100644 --- a/charts/substra-backend/templates/deployment-worker.yaml +++ b/charts/substra-backend/templates/deployment-worker.yaml @@ -36,18 +36,18 @@ spec: imagePullPolicy: "{{ .Values.celeryworker.image.pullPolicy }}" {{- end }} command: ["celery"] - args: ["-A", "substrabackend", "worker", "-E", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},{{ .Values.organization.name }}.worker,celery", "--hostname", "{{ .Values.organization.name }}.worker"] + args: ["-A", "backend", "worker", "-E", "-l", "info", "-n", "{{ .Values.organization.name }}", "-Q", "{{ .Values.organization.name }},{{ .Values.organization.name }}.worker,celery", "--hostname", "{{ .Values.organization.name }}.worker"] env: - name: ORG value: {{ .Values.organization.name }} - - name: SUBSTRABACKEND_ORG + - name: BACKEND_ORG value: {{ .Values.organization.name }} - - name: SUBSTRABACKEND_DEFAULT_PORT + - name: BACKEND_DEFAULT_PORT value: "8000" - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - name: DJANGO_SETTINGS_MODULE - value: substrabackend.settings.{{ .Values.backend.settings }} + value: backend.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" {{- with .Values.backend.auth }} @@ -63,11 +63,11 @@ spec: {{- end }} - name: DEFAULT_DOMAIN value: "{{ .Values.backend.defaultDomain }}" - - name: SUBSTRABACKEND_{{ .Values.organization.name | upper }}_DB_NAME + - name: BACKEND_{{ .Values.organization.name | upper }}_DB_NAME value: {{ .Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABACKEND_DB_USER + - name: BACKEND_DB_USER value: {{ .Values.postgresql.postgresqlUsername }} - - name: SUBSTRABACKEND_DB_PWD + - name: BACKEND_DB_PWD value: {{ .Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ .Release.Name }}-postgresql @@ -80,13 +80,13 @@ spec: - name: MEDIA_ROOT value: {{ .Values.persistence.hostPath }}/medias/ - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/substrabackend/conf.json + value: /conf/{{ .Values.organization.name }}/backend/conf.json volumeMounts: - mountPath: /var/run/docker.sock name: dockersocket - mountPath: {{ .Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ .Values.organization.name }}/substrabackend + - mountPath: /conf/{{ .Values.organization.name }}/backend name: config readOnly: true - mountPath: /var/hyperledger/msp/signcerts diff --git a/charts/substra-backend/templates/job-add-incoming-nodes.yaml b/charts/substra-backend/templates/job-add-incoming-nodes.yaml index 2196ba7e0..6ef9daab5 100644 --- a/charts/substra-backend/templates/job-add-incoming-nodes.yaml +++ b/charts/substra-backend/templates/job-add-incoming-nodes.yaml @@ -32,18 +32,18 @@ spec: env: - name: ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABACKEND_ORG + - name: BACKEND_ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABACKEND_{{ $.Values.organization.name | upper }}_DB_NAME + - name: BACKEND_{{ $.Values.organization.name | upper }}_DB_NAME value: {{ $.Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABACKEND_DB_USER + - name: BACKEND_DB_USER value: {{ $.Values.postgresql.postgresqlUsername }} - - name: SUBSTRABACKEND_DB_PWD + - name: BACKEND_DB_PWD value: {{ $.Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ $.Release.Name }}-postgresql - name: DJANGO_SETTINGS_MODULE - value: substrabackend.settings.{{ $.Values.backend.settings }} + value: backend.settings.{{ $.Values.backend.settings }} - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric_cfg - name: CORE_PEER_ADDRESS_ENV @@ -58,12 +58,12 @@ spec: value: {{ $.user | quote }} - name: BACK_AUTH_PASSWORD value: {{ $.password | quote }} - - name: SUBSTRABACKEND_DEFAULT_PORT + - name: BACKEND_DEFAULT_PORT value: {{ $.Values.backend.service.port | quote}} - - name: SUBSTRABACKEND_PEER_PORT + - name: BACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ $.Values.organization.name }}/substrabackend/conf.json + value: /conf/{{ $.Values.organization.name }}/backend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -71,7 +71,7 @@ spec: volumeMounts: - mountPath: {{ $.Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ $.Values.organization.name }}/substrabackend + - mountPath: /conf/{{ $.Values.organization.name }}/backend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substra-backend/templates/job-add-outgoing-nodes.yaml b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml index 08473e7a6..68e2d9989 100644 --- a/charts/substra-backend/templates/job-add-outgoing-nodes.yaml +++ b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml @@ -32,18 +32,18 @@ spec: env: - name: ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABACKEND_ORG + - name: BACKEND_ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABACKEND_{{ $.Values.organization.name | upper }}_DB_NAME + - name: BACKEND_{{ $.Values.organization.name | upper }}_DB_NAME value: {{ $.Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABACKEND_DB_USER + - name: BACKEND_DB_USER value: {{ $.Values.postgresql.postgresqlUsername }} - - name: SUBSTRABACKEND_DB_PWD + - name: BACKEND_DB_PWD value: {{ $.Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ $.Release.Name }}-postgresql - name: DJANGO_SETTINGS_MODULE - value: substrabackend.settings.{{ $.Values.backend.settings }} + value: backend.settings.{{ $.Values.backend.settings }} - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric_cfg - name: CORE_PEER_ADDRESS_ENV @@ -58,12 +58,12 @@ spec: value: {{ $.user | quote }} - name: BACK_AUTH_PASSWORD value: {{ $.password | quote }} - - name: SUBSTRABACKEND_DEFAULT_PORT + - name: BACKEND_DEFAULT_PORT value: {{ $.Values.backend.service.port | quote}} - - name: SUBSTRABACKEND_PEER_PORT + - name: BACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ $.Values.organization.name }}/substrabackend/conf.json + value: /conf/{{ $.Values.organization.name }}/backend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -71,7 +71,7 @@ spec: volumeMounts: - mountPath: {{ $.Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ $.Values.organization.name }}/substrabackend + - mountPath: /conf/{{ $.Values.organization.name }}/backend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substra-backend/values.yaml b/charts/substra-backend/values.yaml index 402841ea6..61c70353f 100644 --- a/charts/substra-backend/values.yaml +++ b/charts/substra-backend/values.yaml @@ -9,7 +9,7 @@ docker: config: null # Images to pull pullImages: [] - # - eu.gcr.io/substra-208412/substratools:0.0.1 + # - eu.gcr.io/substra-208412/substra-tools:0.0.1 # Inline secrets used to pull images of pods (base64'd) pullSecretsInline: [] diff --git a/docker/celerybeat/Dockerfile b/docker/celerybeat/Dockerfile index a2435a281..18ce90983 100644 --- a/docker/celerybeat/Dockerfile +++ b/docker/celerybeat/Dockerfile @@ -7,11 +7,11 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./substrabackend/requirements.txt /usr/src/app/. +COPY ./backend/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt -COPY ./substrabackend/libs /usr/src/app/libs -COPY ./substrabackend/substrapp /usr/src/app/substrapp -COPY ./substrabackend/substrabackend /usr/src/app/substrabackend -COPY ./substrabackend/node /usr/src/app/node +COPY ./backend/libs /usr/src/app/libs +COPY ./backend/substrapp /usr/src/app/substrapp +COPY ./backend/backend /usr/src/app/backend +COPY ./backend/node /usr/src/app/node diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index 238b13cc1..fdbc9f497 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -7,11 +7,11 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./substrabackend/requirements.txt /usr/src/app/. +COPY ./backend/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt -COPY ./substrabackend/libs /usr/src/app/libs -COPY ./substrabackend/substrapp /usr/src/app/substrapp -COPY ./substrabackend/substrabackend /usr/src/app/substrabackend -COPY ./substrabackend/node /usr/src/app/node +COPY ./backend/libs /usr/src/app/libs +COPY ./backend/substrapp /usr/src/app/substrapp +COPY ./backend/backend /usr/src/app/backend +COPY ./backend/node /usr/src/app/node diff --git a/docker/flower/Dockerfile b/docker/flower/Dockerfile index d2d9f1824..2d0371344 100644 --- a/docker/flower/Dockerfile +++ b/docker/flower/Dockerfile @@ -7,12 +7,12 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./substrabackend/requirements.txt /usr/src/app/. +COPY ./backend/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt RUN pip3 install flower -COPY ./substrabackend/libs /usr/src/app/libs -COPY ./substrabackend/substrapp /usr/src/app/substrapp -COPY ./substrabackend/substrabackend /usr/src/app/substrabackend -COPY ./substrabackend/node /usr/src/app/node +COPY ./backend/libs /usr/src/app/libs +COPY ./backend/substrapp /usr/src/app/substrapp +COPY ./backend/backend /usr/src/app/backend +COPY ./backend/node /usr/src/app/node diff --git a/docker/postgresql/init.sh b/docker/postgresql/init.sh index 109ea9170..bde4e6a69 100644 --- a/docker/postgresql/init.sh +++ b/docker/postgresql/init.sh @@ -1,11 +1,11 @@ #!/bin/bash -createdb -U ${USER} -E UTF8 substrabackend_owkin -psql -U ${USER} -d substrabackend_owkin -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_owkin to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" +createdb -U ${USER} -E UTF8 backend_owkin +psql -U ${USER} -d backend_owkin -c "GRANT ALL PRIVILEGES ON DATABASE backend_owkin to backend;ALTER ROLE backend WITH SUPERUSER CREATEROLE CREATEDB;" -createdb -U ${USER} -E UTF8 substrabackend_chunantes -psql -U ${USER} -d substrabackend_chunantes -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_chunantes to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" +createdb -U ${USER} -E UTF8 backend_chunantes +psql -U ${USER} -d backend_chunantes -c "GRANT ALL PRIVILEGES ON DATABASE backend_chunantes to backend;ALTER ROLE backend WITH SUPERUSER CREATEROLE CREATEDB;" -createdb -U ${USER} -E UTF8 substrabackend_clb -psql -U ${USER} -d substrabackend_clb -c "GRANT ALL PRIVILEGES ON DATABASE substrabackend_clb to substrabackend;ALTER ROLE substrabackend WITH SUPERUSER CREATEROLE CREATEDB;" +createdb -U ${USER} -E UTF8 backend_clb +psql -U ${USER} -d backend_clb -c "GRANT ALL PRIVILEGES ON DATABASE backend_clb to backend;ALTER ROLE backend WITH SUPERUSER CREATEROLE CREATEDB;" diff --git a/docker/start.py b/docker/start.py index e330d0ff0..9fbe13925 100644 --- a/docker/start.py +++ b/docker/start.py @@ -25,10 +25,10 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): # POSTGRES - POSTGRES_USER = 'substrabackend' - USER = 'substrabackend' - POSTGRES_PASSWORD = 'substrabackend' - POSTGRES_DB = 'substrabackend' + POSTGRES_USER = 'backend' + USER = 'backend' + POSTGRES_PASSWORD = 'backend' + POSTGRES_DB = 'backend' # RABBITMQ RABBITMQ_DEFAULT_USER = 'guest' @@ -50,8 +50,8 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): # Docker compose config docker_compose = { - 'substrabackend_services': {}, - 'substrabackend_tools': { + 'backend_services': {}, + 'backend_tools': { 'postgresql': { 'container_name': 'postgresql', 'labels': ['substra'], @@ -73,12 +73,12 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'image': 'substra/celerybeat', 'restart': 'unless-stopped', 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - 'celery -A substrabackend beat -l info"', + 'celery -A backend beat -l info"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': [ 'PYTHONUNBUFFERED=1', f'CELERY_BROKER_URL={CELERY_BROKER_URL}', - f'DJANGO_SETTINGS_MODULE=substrabackend.settings.common'], + f'DJANGO_SETTINGS_MODULE=backend.settings.common'], 'depends_on': ['postgresql', 'rabbit'] }, 'rabbit': { @@ -102,10 +102,10 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'ports': ['5555:5555'], 'image': 'substra/flower', 'restart': 'unless-stopped', - 'command': 'celery flower -A substrabackend', + 'command': 'celery flower -A backend', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': [f'CELERY_BROKER_URL={CELERY_BROKER_URL}', - 'DJANGO_SETTINGS_MODULE=substrabackend.settings.common'], + 'DJANGO_SETTINGS_MODULE=backend.settings.common'], 'depends_on': ['rabbit', 'postgresql'] } }, @@ -122,22 +122,22 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): if launch_settings == 'prod': django_server = f'python3 manage.py collectstatic --noinput; '\ - f'--module substrabackend.wsgi --static-map /static=/usr/src/app/substrabackend/statics ' \ + f'--module backend.wsgi --static-map /static=/usr/src/app/backend/statics ' \ f'--master --processes {processes} --threads 2 --need-app' \ - f'--env DJANGO_SETTINGS_MODULE=substrabackend.settings.server.prod uwsgi --http :{port} ' + f'--env DJANGO_SETTINGS_MODULE=backend.settings.server.prod uwsgi --http :{port} ' else: print('nobasicauth: ', nobasicauth, flush=True) extra_settings = '.nobasicauth' if nobasicauth is True else '' - django_server = f'DJANGO_SETTINGS_MODULE=substrabackend.settings.server{extra_settings}.dev ' \ + django_server = f'DJANGO_SETTINGS_MODULE=backend.settings.server{extra_settings}.dev ' \ f'python3 manage.py runserver --noreload 0.0.0.0:{port}' backend_global_env = [ f'ORG={org_name_stripped}', - f'SUBSTRABACKEND_ORG={org_name}', - f'SUBSTRABACKEND_DEFAULT_PORT={port}', - 'SUBSTRABACKEND_PEER_PORT=internal', + f'BACKEND_ORG={org_name}', + f'BACKEND_DEFAULT_PORT={port}', + 'BACKEND_PEER_PORT=internal', - f'LEDGER_CONFIG_FILE={SUBSTRA_FOLDER}/conf/{org_name}/substrabackend/conf.json', + f'LEDGER_CONFIG_FILE={SUBSTRA_FOLDER}/conf/{org_name}/backend/conf.json', 'PYTHONUNBUFFERED=1', 'DATABASE_HOST=postgresql', @@ -147,7 +147,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f"TASK_CACHE_DOCKER_IMAGES=False", f'CELERY_BROKER_URL={CELERY_BROKER_URL}', - f'DJANGO_SETTINGS_MODULE=substrabackend.settings.{launch_settings}', + f'DJANGO_SETTINGS_MODULE=backend.settings.{launch_settings}', # Basic auth f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', 'admin')}", @@ -157,7 +157,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): ] hlf_volumes = [ - # config (core.yaml + substrabackend/conf.json) + # config (core.yaml + backend/conf.json) f'{SUBSTRA_FOLDER}/conf/{org_name}:{SUBSTRA_FOLDER}/conf/{org_name}:ro', # HLF files @@ -186,7 +186,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'volumes': [ f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias:rw', f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro', - f'{SUBSTRA_FOLDER}/static:/usr/src/app/substrabackend/statics'] + hlf_volumes, + f'{SUBSTRA_FOLDER}/static:/usr/src/app/backend/statics'] + hlf_volumes, 'depends_on': ['postgresql', 'rabbit']} scheduler = { @@ -196,12 +196,12 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'image': 'substra/celeryworker', 'restart': 'unless-stopped', 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - f'celery -A substrabackend worker -l info -n {org_name_stripped} ' + f'celery -A backend worker -l info -n {org_name_stripped} ' f'-Q {org_name},scheduler,celery --hostname {org_name}.scheduler"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), 'volumes': hlf_volumes, - 'depends_on': [f'substrabackend{org_name_stripped}', 'postgresql', 'rabbit']} + 'depends_on': [f'backend{org_name_stripped}', 'postgresql', 'rabbit']} worker = { 'container_name': f'{org_name_stripped}.worker', @@ -210,7 +210,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'image': 'substra/celeryworker', 'restart': 'unless-stopped', 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - f'celery -A substrabackend worker -l info -n {org_name_stripped} ' + f'celery -A backend worker -l info -n {org_name_stripped} ' f'-Q {org_name},{org_name}.worker,celery --hostname {org_name}.worker"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), @@ -218,7 +218,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): '/var/run/docker.sock:/var/run/docker.sock', f'{SUBSTRA_FOLDER}/medias:{SUBSTRA_FOLDER}/medias:rw', f'{SUBSTRA_FOLDER}/servermedias:{SUBSTRA_FOLDER}/servermedias:ro'] + hlf_volumes, - 'depends_on': [f'substrabackend{org_name_stripped}', 'rabbit']} + 'depends_on': [f'backend{org_name_stripped}', 'rabbit']} # Check if we have nvidia docker if 'nvidia' in check_output(['docker', 'system', 'info', '-f', '"{{.Runtimes}}"']).decode('utf-8'): @@ -229,7 +229,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): worker['environment'].append(media_root) backend['environment'].append(media_root) else: - default_domain = os.environ.get('SUBSTRABACKEND_DEFAULT_DOMAIN', '') + default_domain = os.environ.get('BACKEND_DEFAULT_DOMAIN', '') if default_domain: backend['environment'].append(f"DEFAULT_DOMAIN={default_domain}") worker['environment'].append(f"DEFAULT_DOMAIN={default_domain}") @@ -238,17 +238,17 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): scheduler['environment'].append(f"RAVEN_URL={raven_scheduler_url}") worker['environment'].append(f"RAVEN_URL={raven_worker_url}") - docker_compose['substrabackend_services']['substrabackend' + org_name_stripped] = backend - docker_compose['substrabackend_services']['scheduler' + org_name_stripped] = scheduler - docker_compose['substrabackend_services']['worker' + org_name_stripped] = worker + docker_compose['backend_services']['backend' + org_name_stripped] = backend + docker_compose['backend_services']['scheduler' + org_name_stripped] = scheduler + docker_compose['backend_services']['worker' + org_name_stripped] = worker # Create all services along to conf COMPOSITION = {'services': {}, 'version': '2.3', 'networks': {'default': {'external': {'name': 'net_substra'}}}} - for name, dconfig in docker_compose['substrabackend_services'].items(): + for name, dconfig in docker_compose['backend_services'].items(): COMPOSITION['services'][name] = dconfig - for name, dconfig in docker_compose['substrabackend_tools'].items(): + for name, dconfig in docker_compose['backend_tools'].items(): COMPOSITION['services'][name] = dconfig with open(docker_compose['path'], 'w+') as f: @@ -308,9 +308,9 @@ def start(conf, launch_settings, no_backup, nobasicauth=False): no_backup = args['no_backup'] - conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/substrabackend/conf.json')] + conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/backend/conf.json')] - print('Build substrabackend for : ', flush=True) + print('Build backend for : ', flush=True) print(' Organizations :', flush=True) for org in conf: print(' -', org['name'], flush=True) diff --git a/docker/substra-backend/Dockerfile b/docker/substra-backend/Dockerfile index 97499ccc9..48d624fc0 100644 --- a/docker/substra-backend/Dockerfile +++ b/docker/substra-backend/Dockerfile @@ -7,14 +7,14 @@ RUN apt-get install -y git curl netcat RUN mkdir -p /usr/src/app WORKDIR /usr/src/app -COPY ./substrabackend/requirements.txt /usr/src/app/. +COPY ./backend/requirements.txt /usr/src/app/. RUN pip3 install -r requirements.txt -COPY ./substrabackend/manage.py /usr/src/app/manage.py -COPY ./substrabackend/libs /usr/src/app/libs -COPY ./substrabackend/substrapp /usr/src/app/substrapp -COPY ./substrabackend/events /usr/src/app/events -COPY ./substrabackend/substrabackend /usr/src/app/substrabackend -COPY ./substrabackend/node /usr/src/app/node -COPY ./substrabackend/node-register /usr/src/app/node-register +COPY ./backend/manage.py /usr/src/app/manage.py +COPY ./backend/libs /usr/src/app/libs +COPY ./backend/substrapp /usr/src/app/substrapp +COPY ./backend/events /usr/src/app/events +COPY ./backend/backend /usr/src/app/backend +COPY ./backend/node /usr/src/app/node +COPY ./backend/node-register /usr/src/app/node-register diff --git a/fixtures/chunantes/algos/algo0/description.md~ b/fixtures/chunantes/algos/algo0/description.md~ deleted file mode 100644 index dd420e7e8..000000000 --- a/fixtures/chunantes/algos/algo0/description.md~ +++ /dev/null @@ -1,5 +0,0 @@ -# My top unefficient algo 2 - -Set of one-vs-all logistic regression using sklearn (SGD classfier with loss=log) - -Performance are very bad, since the metrics is the macro average recall score and elements of two classes are very bad predicted... diff --git a/fixtures/chunantes/algos/algo3/algo.tar.gz b/fixtures/chunantes/algos/algo3/algo.tar.gz index fabc8499557a3931203015c89f4c3e0e5a2dd572..a5f48c539bdfa9ed009bf64a07180790968f1f90 100644 GIT binary patch literal 1571 zcmV+;2Hg1{iwFQuz^+{Y1ML?(Y#c>&4FZytP(Ua|qCkUF>|VHA@7~9kI68?CJBcAV zNA@K+vaHSA?d*ASdppa{oP9@xpg>53PXP@`NJK)SND!ib=y2jVSdfEfml8c1{9I6!@_?>Q1O^&B(>gPI8rO+u zJ8PwKIiTxh!CH+x_rl(#GI_nzayr1=5pM4AQL9kQTje8%ixWS5vnmC@vj6Ina=h8Q z@m{c8eg8)7#=QB}2fv2&3*LUwLkxP>yJZ!|NF(&*5uP)*Z=zbm%9zy{{?4p z_Y}bn38!|h4{TTeW}z@v|D|GaT0!GUvm@}3*MGi@+Jd%8#VVDpa-mSNiblS4qg3-~YvOY4`rW7jR;6;S3@jquB@z%BFay&P9lGdGm15%J-Lo zF^|ufhG|%;x_GXNa3FF`B2Xug_wdpFn)=`;&qKK$s&}a8YMG zv$M#U!d{aZKxnAyT(!1%;q1bEwT4zE6BUzLG?|c0u0G^#F7d;T>e#0Kiv=sHf2&j| z6sFCxtbh31t^a!gnx-vv>TSw7Wj-QZ+=j<9+Mr@BEi<4{X**z{Kpty0;c1>OFLCCl z^SClGM}DBXA#11HhDUuE?KX3WhZ5qYle5R+9nYytNvNhGl4cY28YwB7sH%DponRsI z*+w=s0PKUF;4^{h1cgL$69;+)T8c#=7Z^BcbV4e6K!Cwet|rVz9dp_^&U}|Pb$Rjm z7@j{`WZ)Fg#HJcB(?B6vCtfAxoSl35+{p}>)R5MrV^BMKWThdenHg1;pH2>Okpu3q z6Bon+bxu4ti=sJDrr%juh!9m`v|-y0Z3x@$@5&Dt*uC6GNNADX3|hxthZur+lnXtB zsEa6%nx)?$dbF8^P#C_0!w~l}hYY3XIM4=a8=`qf2x8pYiNQp^ty0|$xxN_mt*RpyhKZJZ+MQ>Tp5CIUA* zUj}9iS_vFJO~K20bf|2s3St#SDrV1QHZjTo-nqC~%DC?%iZSO8J3YW+ZOG=R3$TFr zy4=VjEz~lyFx^o*65+BN7*eF}W(GPqUMHIiV0%>?TdIn5$l6K|JFE%{pZbZG|?MM+M<8mL@>*IPuI%GmX z{Wxj-wUYHZOg;&wVrY=C`(10;cg+G@6OSC7tP4WFlH2O-=Ym55bNWdjaER>!H3 zA>t&{W1ehm)E1o{L=B~7B6N_L<5vLaAzX~)(*PAshJ!Dcw~T$vv^n$=KN5LB+#>KJ zJL=tq;r31i4VyYs%mFtmq=IeB8`-wwYsPLv3~XDA{T1J~(W8}g;er=Lk8WWw^?tvk Vc3~HGVHX}O_z$JK%a8yZ006y{`*i>S literal 1189 zcmV;W1X}waiwFQD(>7fI1MOE^Pvb@u-e>=cQ})4*lsI-0prXpdcC(<>s!#!|QXynb z;>_&sd%bkXHTgJu_n`4hc|IqSaROy?8F?Hs>;PO!B!1%jLVbL=;5_qY>!u;laN7 zMgu$77!BhA#KZk~e>fZ-M28T?!}xIY4x%@;s>VVpQlTl56gicPXX%hE%U+OU&jPFO zHv-@HFBa2+Ny!8U`bdg0r|`hkEy%l^l8PgR$BI%^3UV=@Gd^#oze&NHF<%tr5{Lv| zdRZlkhC9p|$8S=Il;%(qUz|)n<^)w{j8oOlFk+tQ%fWuXsGmR=5R_Rn|%~KWAh+mIpw6FW8WCq zM;dEth$9~r(tDbZ8_vn6AHSY-(4?8R9zJ001jfox4?9Pm2Z)qrkfJ-1+67i%AZea; z!Hkg-Y7nI=7~ADANm4dbNwV5ai6XfB$7(_2jxLYjp5zM}Dv>j(f)20@m}DH2l+S2j zHoF*#kf)@o$g%@8m(((C$kL8Nd0o4uU8oHTnWBXZIvb>@0x7S1@ePc};3qy1p6Vs| z4yU=0GRYQvrZA5Zf5rLdYE)6RsJJ=O+E2M4=}tdsvX+}{`iwU-CwL%Lk?8tW(~erW zz70YxGRQh>9g^JB?E-jR)x%CzMu)Dg=CEy5SonK?!eGx6qK11ubL^QQ*qk~7#1!O1on$i`yqMqd$((0&&J1z@*owkWX zv~PWYIxtvU^MX7E<~(uxJjrA&iU2D{in;u2A(y|u1 zPRyrI0P3MqZRFE>$qd@T*VAWXZ<)43uh%ysj|3F68k48~! z`~Us@coYwH|9@~WaQ*+kf#dVDpMWmH`3$>0(XV^(-XQvZ6c76Cmi#CRqcHZo^RK5s zO4XZF1&b0N0Q$pfZkix$&3j9jE?A!SsFai|MsnAH`~1~)*OgI zbZG@Q10%~VpgCA~Un%x4_4>AK`x@x^9+;mN#CXng5sU=03 z$;EmFm0;7&qsn4i^k>I{XjIcDnjfxbWD;RUI273ukWnzOq!Gj-+Sxz{BFqIjQTY51 kvkgEKU`~Xa>)Ln+$R^swK!aJ?K$@9=5MAH`u){7K$gD z=rI;gOip)W=Xkh@X?6=x14t9XIMsShxN(|{5aV)FONug+i}eaB!N!?KmBqH`&yEGs z6aO4CX6Fz-|HEtp&=ipR0B=Sn5oUzbkZl1u4GbnfWE4$9by#d^1vdjD%U7TgK#!rC h19B6x9dL7i>XtO#0g|{~IN66uh707lCqR=K7y!<^N5KF9 delta 302 zcmZ3*`iaFPz?+#xgn@y9gCVS()t}=^&y*G*Zw3%^F~~5ukX^tEaY1PXHv=QfSD+fO%LBYo%|mqvvUw+f<^i2$3U?PS16kQX PRx<(N0wBEy Date: Thu, 24 Oct 2019 10:14:05 +0200 Subject: [PATCH 376/457] Update conf directory name. --- backend/backend/settings/deps/ledger.py | 2 +- charts/substra-backend/templates/deployment-backend.yaml | 4 ++-- charts/substra-backend/templates/deployment-scheduler.yaml | 4 ++-- charts/substra-backend/templates/deployment-worker.yaml | 4 ++-- .../substra-backend/templates/job-add-incoming-nodes.yaml | 4 ++-- .../substra-backend/templates/job-add-outgoing-nodes.yaml | 4 ++-- docker/start.py | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/backend/settings/deps/ledger.py b/backend/backend/settings/deps/ledger.py index 0e2bdaa2d..a5e7a2b90 100644 --- a/backend/backend/settings/deps/ledger.py +++ b/backend/backend/settings/deps/ledger.py @@ -16,7 +16,7 @@ from hfc.fabric.block_decoder import decode_fabric_MSP_config, decode_fabric_peers_info, decode_fabric_endpoints -LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/backend/conf.json') +LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/substra-backend/conf.json') LEDGER = json.load(open(LEDGER_CONFIG_FILE, 'r')) LEDGER_SYNC_ENABLED = True diff --git a/charts/substra-backend/templates/deployment-backend.yaml b/charts/substra-backend/templates/deployment-backend.yaml index de4565c2e..5be64f8b5 100644 --- a/charts/substra-backend/templates/deployment-backend.yaml +++ b/charts/substra-backend/templates/deployment-backend.yaml @@ -82,7 +82,7 @@ spec: - name: BACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/backend/conf.json + value: /conf/{{ .Values.organization.name }}/substra-backend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -94,7 +94,7 @@ spec: volumeMounts: - mountPath: {{ .Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ .Values.organization.name }}/backend + - mountPath: /conf/{{ .Values.organization.name }}/substra-backend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substra-backend/templates/deployment-scheduler.yaml b/charts/substra-backend/templates/deployment-scheduler.yaml index 987ca19fc..54e5c3128 100644 --- a/charts/substra-backend/templates/deployment-scheduler.yaml +++ b/charts/substra-backend/templates/deployment-scheduler.yaml @@ -70,9 +70,9 @@ spec: - name: FABRIC_LOGGING_SPEC value: debug - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/backend/conf.json + value: /conf/{{ .Values.organization.name }}/substra-backend/conf.json volumeMounts: - - mountPath: /conf/{{ .Values.organization.name }}/backend + - mountPath: /conf/{{ .Values.organization.name }}/substra-backend name: config readOnly: true - mountPath: /var/hyperledger/msp/signcerts diff --git a/charts/substra-backend/templates/deployment-worker.yaml b/charts/substra-backend/templates/deployment-worker.yaml index 1f8924d3b..62dddda88 100644 --- a/charts/substra-backend/templates/deployment-worker.yaml +++ b/charts/substra-backend/templates/deployment-worker.yaml @@ -80,13 +80,13 @@ spec: - name: MEDIA_ROOT value: {{ .Values.persistence.hostPath }}/medias/ - name: LEDGER_CONFIG_FILE - value: /conf/{{ .Values.organization.name }}/backend/conf.json + value: /conf/{{ .Values.organization.name }}/substra-backend/conf.json volumeMounts: - mountPath: /var/run/docker.sock name: dockersocket - mountPath: {{ .Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ .Values.organization.name }}/backend + - mountPath: /conf/{{ .Values.organization.name }}/substra-backend name: config readOnly: true - mountPath: /var/hyperledger/msp/signcerts diff --git a/charts/substra-backend/templates/job-add-incoming-nodes.yaml b/charts/substra-backend/templates/job-add-incoming-nodes.yaml index 6ef9daab5..f2494bb34 100644 --- a/charts/substra-backend/templates/job-add-incoming-nodes.yaml +++ b/charts/substra-backend/templates/job-add-incoming-nodes.yaml @@ -63,7 +63,7 @@ spec: - name: BACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ $.Values.organization.name }}/backend/conf.json + value: /conf/{{ $.Values.organization.name }}/substra-backend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -71,7 +71,7 @@ spec: volumeMounts: - mountPath: {{ $.Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ $.Values.organization.name }}/backend + - mountPath: /conf/{{ $.Values.organization.name }}/substra-backend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substra-backend/templates/job-add-outgoing-nodes.yaml b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml index 68e2d9989..dbf606e8f 100644 --- a/charts/substra-backend/templates/job-add-outgoing-nodes.yaml +++ b/charts/substra-backend/templates/job-add-outgoing-nodes.yaml @@ -63,7 +63,7 @@ spec: - name: BACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ $.Values.organization.name }}/backend/conf.json + value: /conf/{{ $.Values.organization.name }}/substra-backend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -71,7 +71,7 @@ spec: volumeMounts: - mountPath: {{ $.Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ $.Values.organization.name }}/backend + - mountPath: /conf/{{ $.Values.organization.name }}/substra-backend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/docker/start.py b/docker/start.py index 9fbe13925..13c499673 100644 --- a/docker/start.py +++ b/docker/start.py @@ -137,7 +137,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f'BACKEND_DEFAULT_PORT={port}', 'BACKEND_PEER_PORT=internal', - f'LEDGER_CONFIG_FILE={SUBSTRA_FOLDER}/conf/{org_name}/backend/conf.json', + f'LEDGER_CONFIG_FILE={SUBSTRA_FOLDER}/conf/{org_name}/substra-backend/conf.json', 'PYTHONUNBUFFERED=1', 'DATABASE_HOST=postgresql', @@ -157,7 +157,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): ] hlf_volumes = [ - # config (core.yaml + backend/conf.json) + # config (core.yaml + substra-backend/conf.json) f'{SUBSTRA_FOLDER}/conf/{org_name}:{SUBSTRA_FOLDER}/conf/{org_name}:ro', # HLF files @@ -308,7 +308,7 @@ def start(conf, launch_settings, no_backup, nobasicauth=False): no_backup = args['no_backup'] - conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/backend/conf.json')] + conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/substra-backend/conf.json')] print('Build backend for : ', flush=True) print(' Organizations :', flush=True) From f0aeeda4ea3cebe73002b2f6670c3b4c01f48e6f Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 24 Oct 2019 12:00:08 +0200 Subject: [PATCH 377/457] Clean gitignore --- .gitignore | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 5c7c4df25..1372abc64 100644 --- a/.gitignore +++ b/.gitignore @@ -112,8 +112,5 @@ venv.bak/ # secret files SECRET -# substra files -bin -**/medias/* -backend/substrapp/**/conf +# substra-backend files docker/docker-compose-dynamic.yaml From 7c081a5755a8adc8f78f96e655e56225f8ce0b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Gasser?= Date: Thu, 24 Oct 2019 08:58:29 -0400 Subject: [PATCH 378/457] helm: fix apiVersion --- charts/substra-backend/Chart.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/charts/substra-backend/Chart.yaml b/charts/substra-backend/Chart.yaml index 62d670958..e2b51d4eb 100644 --- a/charts/substra-backend/Chart.yaml +++ b/charts/substra-backend/Chart.yaml @@ -1,3 +1,4 @@ +apiVersion: v1 name: substra-backend home: https://substra.org/ version: 1.0.0-alpha.11 From 777ec0cfc10a1aad34cccba449e4923c20786d32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Gasser?= Date: Thu, 24 Oct 2019 08:59:59 -0400 Subject: [PATCH 379/457] populate: add tags to identify which of the traintuple should succeed (#392) currently, there's no indication of which traintuples are supposed to succeed/fail, which can be confusing --- populate.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/populate.py b/populate.py index 5944c4272..177c4feab 100644 --- a/populate.py +++ b/populate.py @@ -324,8 +324,10 @@ def do_populate(): 'algo_key': algo_key, 'objective_key': objective_key, 'data_manager_key': data_manager_org1_key, - 'train_data_sample_keys': train_data_sample_keys[:2], - 'tag': 'substra' + 'train_data_sample_keys': train_data_sample_keys[:2] + # This traintuple should succeed. + # It doesn't have a tag, so it can be used as a test + # of the "non-bundled" display in substra-frontend. } traintuple_key = get_or_create(data, org_1, 'traintuple') @@ -335,7 +337,7 @@ def do_populate(): 'data_manager_key': data_manager_org1_key, 'objective_key': objective_key, 'train_data_sample_keys': train_data_sample_keys[:2], - 'tag': 'My super tag' + 'tag': '(should fail) My super tag' } get_or_create(data, org_1, 'traintuple') @@ -346,6 +348,7 @@ def do_populate(): 'data_manager_key': data_manager_org1_key, 'objective_key': objective_key, 'train_data_sample_keys': train_data_sample_keys[:2], + 'tag': '(should fail) My other tag' } get_or_create(data, org_1, 'traintuple') From 4b0bff3387b2f659a99a973cfe5d1278147e2d2d Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 24 Oct 2019 15:16:58 +0200 Subject: [PATCH 380/457] Update assets.py --- backend/substrapp/tests/assets.py | 278 +++++++++++++++--------------- 1 file changed, 139 insertions(+), 139 deletions(-) diff --git a/backend/substrapp/tests/assets.py b/backend/substrapp/tests/assets.py index 4ddf536d0..1c8ad63cb 100644 --- a/backend/substrapp/tests/assets.py +++ b/backend/substrapp/tests/assets.py @@ -22,7 +22,7 @@ }, "metrics": { "name": "macro-average recall", - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" }, "owner": "owkinMSP", @@ -43,7 +43,7 @@ }, "metrics": { "name": "macro-average recall", - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" }, "owner": "owkinMSP", @@ -68,16 +68,16 @@ { "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "description": { - "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", - "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" + "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" }, - "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "name": "Simplified ISIC 2018", + "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "name": "ISIC 2018", "opener": { - "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" + "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" }, - "owner": "owkinMSP", + "owner": "chu-nantesMSP", "permissions": { "process": { "public": True, @@ -89,16 +89,16 @@ { "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "description": { - "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", - "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" + "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" }, - "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "name": "ISIC 2018", + "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "name": "Simplified ISIC 2018", "opener": { - "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" + "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" }, - "owner": "chu-nantesMSP", + "owner": "owkinMSP", "permissions": { "process": { "public": True, @@ -110,25 +110,6 @@ ] algo = [ - { - "key": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "name": "Logistic regression", - "content": { - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "description": { - "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" - }, - "owner": "owkinMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - }, { "key": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", "name": "Neural Network", @@ -166,12 +147,31 @@ "authorizedIDs": [] } } + }, + { + "key": "6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d", + "name": "Logistic regression", + "content": { + "hash": "6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d", + "storageAddress": "http://testserver/algo/6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d/file/" + }, + "description": { + "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", + "storageAddress": "http://testserver/algo/6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d/description/" + }, + "owner": "owkinMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } } ] traintuple = [ { - "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", + "key": "363f70dcc3bf22fdce65e36c957e855b7cd3e2828e6909f34ccc97ee6218541a", "algo": { "name": "Neural Network", "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", @@ -181,7 +181,7 @@ "dataset": { "worker": "chu-nantesMSP", "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "dacc0288138cb50569250f996bbe716ec8968fb334d32f29f174c9e79a224127", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", @@ -189,11 +189,11 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0014-ff6df51]", + "log": "[00-01-0032-e18ebeb]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, @@ -209,17 +209,17 @@ "tag": "My super tag" }, { - "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "key": "05b44fa4b94d548e35922629f7b23dd84f777d09925bbecb0362081ca528f746", "algo": { "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + "hash": "6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d", + "storageAddress": "http://testserver/algo/6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d/file/" }, "creator": "chu-nantesMSP", "dataset": { "worker": "chu-nantesMSP", "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "dacc0288138cb50569250f996bbe716ec8968fb334d32f29f174c9e79a224127", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", @@ -227,17 +227,17 @@ }, "computePlanID": "", "inModels": None, - "log": "Train - CPU:98.65 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27", - "storageAddress": "http://testserver/model/8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27/file/" + "hash": "e6a16f5bea8a485f48a8aa8c462155d2d500022a9459c1ff4b3c32acd168ff99", + "storageAddress": "http://testserver/model/e6a16f5bea8a485f48a8aa8c462155d2d500022a9459c1ff4b3c32acd168ff99/file/" }, "permissions": { "process": { @@ -250,35 +250,35 @@ "tag": "substra" }, { - "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "key": "32070e156eb4f97d85ff8448ea2ab71f4f275ab845159029354e4446aff974e0", "algo": { "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + "hash": "6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d", + "storageAddress": "http://testserver/algo/6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d/file/" }, "creator": "chu-nantesMSP", "dataset": { "worker": "chu-nantesMSP", "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "dacc0288138cb50569250f996bbe716ec8968fb334d32f29f174c9e79a224127", "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "computePlanID": "32070e156eb4f97d85ff8448ea2ab71f4f275ab845159029354e4446aff974e0", "inModels": None, - "log": "Train - CPU:143.37 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "a1e39305a1863d96cebec40bd2a0c016eead11a3037329628afe9bcc9a32da90", - "storageAddress": "http://testserver/model/a1e39305a1863d96cebec40bd2a0c016eead11a3037329628afe9bcc9a32da90/file/" + "hash": "0b1ce6f2bd9247a262c3695aa07aad5ef187197f118c73c60a42e176f8f53b98", + "storageAddress": "http://testserver/model/0b1ce6f2bd9247a262c3695aa07aad5ef187197f118c73c60a42e176f8f53b98/file/" }, "permissions": { "process": { @@ -291,7 +291,7 @@ "tag": "" }, { - "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", + "key": "a2171a1c09738c677748346d22d2b5eea47f874a3b4f4b75224674235892de72", "algo": { "name": "Random Forest", "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", @@ -301,7 +301,7 @@ "dataset": { "worker": "chu-nantesMSP", "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "dacc0288138cb50569250f996bbe716ec8968fb334d32f29f174c9e79a224127", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", @@ -309,11 +309,11 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0014-2dd325f]", + "log": "[00-01-0032-8189cc5]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, @@ -332,11 +332,11 @@ testtuple = [ { - "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", + "key": "b2d127e65583080bf85d51f4bbc6b04e420414dd668f921c419eb6f078e428ae", "algo": { "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + "hash": "6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d", + "storageAddress": "http://testserver/algo/6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d/file/" }, "certified": True, "creator": "chu-nantesMSP", @@ -349,16 +349,16 @@ "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", "perf": 0 }, - "log": "Test - CPU:144.06 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "", "model": { - "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27", - "storageAddress": "http://testserver/model/8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27/file/" + "traintupleKey": "05b44fa4b94d548e35922629f7b23dd84f777d09925bbecb0362081ca528f746", + "hash": "e6a16f5bea8a485f48a8aa8c462155d2d500022a9459c1ff4b3c32acd168ff99", + "storageAddress": "http://testserver/model/e6a16f5bea8a485f48a8aa8c462155d2d500022a9459c1ff4b3c32acd168ff99/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, @@ -370,7 +370,7 @@ model = [ { "traintuple": { - "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", + "key": "363f70dcc3bf22fdce65e36c957e855b7cd3e2828e6909f34ccc97ee6218541a", "algo": { "name": "Neural Network", "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", @@ -380,7 +380,7 @@ "dataset": { "worker": "chu-nantesMSP", "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "dacc0288138cb50569250f996bbe716ec8968fb334d32f29f174c9e79a224127", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", @@ -388,11 +388,11 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0014-ff6df51]", + "log": "[00-01-0032-e18ebeb]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, @@ -422,35 +422,35 @@ }, { "traintuple": { - "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "key": "05b44fa4b94d548e35922629f7b23dd84f777d09925bbecb0362081ca528f746", "algo": { "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + "hash": "6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d", + "storageAddress": "http://testserver/algo/6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d/file/" }, "creator": "chu-nantesMSP", "dataset": { "worker": "chu-nantesMSP", "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" + "dacc0288138cb50569250f996bbe716ec8968fb334d32f29f174c9e79a224127", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "computePlanID": "", "inModels": None, - "log": "Train - CPU:143.37 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "a1e39305a1863d96cebec40bd2a0c016eead11a3037329628afe9bcc9a32da90", - "storageAddress": "http://testserver/model/a1e39305a1863d96cebec40bd2a0c016eead11a3037329628afe9bcc9a32da90/file/" + "hash": "e6a16f5bea8a485f48a8aa8c462155d2d500022a9459c1ff4b3c32acd168ff99", + "storageAddress": "http://testserver/model/e6a16f5bea8a485f48a8aa8c462155d2d500022a9459c1ff4b3c32acd168ff99/file/" }, "permissions": { "process": { @@ -460,52 +460,74 @@ }, "rank": 0, "status": "done", - "tag": "" + "tag": "substra" }, "testtuple": { - "key": "", - "algo": None, - "certified": False, - "creator": "", - "dataset": None, + "key": "b2d127e65583080bf85d51f4bbc6b04e420414dd668f921c419eb6f078e428ae", + "algo": { + "name": "Logistic regression", + "hash": "6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d", + "storageAddress": "http://testserver/algo/6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d/file/" + }, + "certified": True, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "owkinMSP", + "keys": [ + "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", + "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" + ], + "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "perf": 0 + }, "log": "", - "model": None, - "objective": None, - "status": "", - "tag": "" + "model": { + "traintupleKey": "05b44fa4b94d548e35922629f7b23dd84f777d09925bbecb0362081ca528f746", + "hash": "e6a16f5bea8a485f48a8aa8c462155d2d500022a9459c1ff4b3c32acd168ff99", + "storageAddress": "http://testserver/model/e6a16f5bea8a485f48a8aa8c462155d2d500022a9459c1ff4b3c32acd168ff99/file/" + }, + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "status": "done", + "tag": "substra" } }, { "traintuple": { - "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "key": "32070e156eb4f97d85ff8448ea2ab71f4f275ab845159029354e4446aff974e0", "algo": { "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + "hash": "6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d", + "storageAddress": "http://testserver/algo/6523012b72bcd0299f709bc6aaa084d2092dddb9a6256fbffa64645478995a1d/file/" }, "creator": "chu-nantesMSP", "dataset": { "worker": "chu-nantesMSP", "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + "dacc0288138cb50569250f996bbe716ec8968fb334d32f29f174c9e79a224127", + "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", "perf": 1 }, - "computePlanID": "", + "computePlanID": "32070e156eb4f97d85ff8448ea2ab71f4f275ab845159029354e4446aff974e0", "inModels": None, - "log": "Train - CPU:98.65 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", + "log": "", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, "outModel": { - "hash": "8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27", - "storageAddress": "http://testserver/model/8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27/file/" + "hash": "0b1ce6f2bd9247a262c3695aa07aad5ef187197f118c73c60a42e176f8f53b98", + "storageAddress": "http://testserver/model/0b1ce6f2bd9247a262c3695aa07aad5ef187197f118c73c60a42e176f8f53b98/file/" }, "permissions": { "process": { @@ -515,46 +537,24 @@ }, "rank": 0, "status": "done", - "tag": "substra" + "tag": "" }, "testtuple": { - "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "certified": True, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "owkinMSP", - "keys": [ - "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", - "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" - ], - "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "perf": 0 - }, - "log": "Test - CPU:144.06 % - Mem:0.13 GB - GPU:0.00 % - GPU Mem:0.00 GB;", - "model": { - "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27", - "storageAddress": "http://testserver/model/8769b53b9f4e14881944dcc13b6b56d4fdbe91dadb0b350844c9c04673750e27/file/" - }, - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "status": "done", - "tag": "substra" + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "status": "", + "tag": "" } }, { "traintuple": { - "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", + "key": "a2171a1c09738c677748346d22d2b5eea47f874a3b4f4b75224674235892de72", "algo": { "name": "Random Forest", "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", @@ -564,7 +564,7 @@ "dataset": { "worker": "chu-nantesMSP", "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "dacc0288138cb50569250f996bbe716ec8968fb334d32f29f174c9e79a224127", "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" ], "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", @@ -572,11 +572,11 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0014-2dd325f]", + "log": "[00-01-0032-8189cc5]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { - "hash": "3f5a0bcb8a47c2ab8094efc71e339b3b87000ae147b9eb05f95174dc3d07874f", + "hash": "506dacd8800c36e70ad3df7379c9164e03452d700bd2c3edb472e6bd0dc01f2e", "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" } }, From aee78fb5a160a1213a79513b765d08e94c8126f6 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 24 Oct 2019 16:31:33 +0200 Subject: [PATCH 381/457] Fix tests --- .../tests/views/test_views_authentication.py | 13 +++++++++++++ backend/substrapp/tests/views/tests_views_algo.py | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/backend/substrapp/tests/views/test_views_authentication.py b/backend/substrapp/tests/views/test_views_authentication.py index 179edc986..d8b748f8d 100644 --- a/backend/substrapp/tests/views/test_views_authentication.py +++ b/backend/substrapp/tests/views/test_views_authentication.py @@ -1,5 +1,7 @@ import mock from django.urls import reverse +import os +import shutil from rest_framework import status from rest_framework.test import APITestCase from node.models import IncomingNode @@ -7,10 +9,18 @@ from ..common import generate_basic_auth_header, get_sample_algo_metadata, get_sample_algo, get_description_algo from django.conf import settings +from django.test import override_settings +MEDIA_ROOT = "/tmp/unittests_views/" + +@override_settings(MEDIA_ROOT=MEDIA_ROOT) class AuthenticationTests(APITestCase): def setUp(self): + + if not os.path.exists(MEDIA_ROOT): + os.makedirs(MEDIA_ROOT) + self.extra = { 'HTTP_ACCEPT': 'application/json;version=0.0' } @@ -21,6 +31,9 @@ def setUp(self): self.algo = Algo.objects.create(file=self.algo_file, description=self.algo_description_file) self.algo_url = reverse('substrapp:algo-file', kwargs={'pk': self.algo.pk}) + def tearDown(self): + shutil.rmtree(MEDIA_ROOT, ignore_errors=True) + @classmethod def setUpTestData(cls): cls.incoming_node = IncomingNode.objects.create(node_id="external_node_id", secret="s3cr37") diff --git a/backend/substrapp/tests/views/tests_views_algo.py b/backend/substrapp/tests/views/tests_views_algo.py index c06cd415f..e9407caa7 100644 --- a/backend/substrapp/tests/views/tests_views_algo.py +++ b/backend/substrapp/tests/views/tests_views_algo.py @@ -96,7 +96,7 @@ def test_algo_list_filter_dual(self): mquery_ledger.return_value = algo search_params = '?search=algo%253Aname%253ALogistic%2520regression' - search_params += f'%2Calgo%253Aowner%253A{algo[0]["owner"]}' + search_params += f'%2Calgo%253Aowner%253A{algo[2]["owner"]}' response = self.client.get(url + search_params, **self.extra) r = response.json() From 1c3e7179ad80dfc1c44b65b0c17da6acf4d8d255 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 25 Oct 2019 10:16:24 +0200 Subject: [PATCH 382/457] Fix gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1372abc64..807b86293 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,4 @@ SECRET # substra-backend files docker/docker-compose-dynamic.yaml +**/medias/* From c5eec3e1484cfe618b2226bf50e08c1b4361e582 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 25 Oct 2019 17:00:31 +0200 Subject: [PATCH 383/457] Update screens --- assets/celery chunantes scheduler.png | Bin 126465 -> 149149 bytes assets/celery chunantes worker.png | Bin 125778 -> 149639 bytes assets/celery owkin scheduler.png | Bin 123871 -> 150344 bytes assets/celery owkin worker.png | Bin 124557 -> 149362 bytes assets/celery_beat.png | Bin 116996 -> 140791 bytes assets/database_owkin.png | Bin 81876 -> 82742 bytes assets/database_owkin_challenges.png | Bin 79770 -> 91660 bytes assets/django_enabled.png | Bin 83190 -> 85059 bytes assets/multirun.png | Bin 79198 -> 74705 bytes assets/server_chunantes.png | Bin 123031 -> 149179 bytes assets/server_owkin.png | Bin 121046 -> 148796 bytes assets/sources_root.png | Bin 154293 -> 138662 bytes 12 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/celery chunantes scheduler.png b/assets/celery chunantes scheduler.png index 444ce72eebee8a7fc28be46335964a5765c746be..5d7a796aad9165d1da7aa7346afdb5ce2a9cf1e0 100644 GIT binary patch literal 149149 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

        8U#Vwys(xP5cVX*|Jry(17;}Gw_8*=;ef{ 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

        l8VifjJm|viuy|#82E@xt3};g; zGsGJohc-=VngHNQQb&gd$YUNk5%SkEdnql)iwu(c&>J%K+YqB<3&CcvzJak{u;!Ll z+!?2=*a5`-We;=ndO!<`EjGv4Hv#wh{LmpWV6Otn(4!oc)z#I3wa^crJQ?^6!Q)gP*GXOXcB(&^1{Z)mmmC*@Y>1Ai2;Th8D=GP z6I*8O;cv%%V@`ekFLNpvxWzpikZk4dyIW@9?kyvc7VP_VslBK)bxB8egHb1e_+xB% zWDjuM@_L`~_-KB99w7O@$Hn=>=YIl8r|^B?fA1SU!G z@xuQ0mNX$5VE};;dW+m-v9XS`C9tuOP%+>_hN&cPP25wr+><{0J|6K0jJMLy{?;A% zKVF{$fzf)1JN^lXNd7Z3u>rf;1^83DF=kxlyJN$e?C*maU$IsJ3`2tR;m4v|`b3mW z&PhrW+V}OgR)p{^_6CgM-g~W&`yxSFWAJws?m%1p$7f(Y5sTC8CGy};1>6kAdw_T)I7LNhh*mCI~F>Y!L1@s2?T;~$NcNe(ztuNLF6n6 zl=6RFEos4wiMYLvz2iMvGo)~@=)1K3zj?$t5x1_GG(8@13>4ZhxL0^ntLxDnJhDH0 zQI`0J_}@Rwnn%V{cP~78GeXTkhLyV(&~|{V35}a);!&Ac)r9)ZU!!Ys&t?ClSfK}k QvhIipNxjd1tKsp#0RAoTxc~qF literal 126465 zcmZs?b9f}-8a>#tZ6}jV?1^nVnV1vXwr$(CC)UKaHL-1N&%JkdpWn0Fe>AJUs(N|O zd8@+}h68aoGqq+uLi4)ihN5c)N9##h1!Q zeUJ_Z9(D4+zaDZK-l6!LHIRy1E(dsTmBnz}Z}Wz8iFkG2b6>vRc@}v;KPBzGe0}-z z-K%-YYT-Kdr0-QDpHu^hra3bXET_Isjw~?gR_jK49zS#%b8h%^cH419eeEBH zqW;$6r1RzAP(~L4*ZrdF^|^S@&H17)##*6`#`x?`O7qoyHk|jx8u)yCf9cZdc|6X{ zxoP+?XZ$)Ed++EE@>NT>)$mv5WBLrmQ)gkgZZd*R@HELg>1OLW2=a}Bw~G8 z-v9bk_AmB**H^hLEk5!T1WQWrL5k~X{e)j^6Zt?RV{zNX`PopM-+qVHEc*V6*426y#@&8Is7h^^(i>=x{~rP+R5l-I^EYxnsL$NSPHwtEP!wora8O ztA=^H6AuQz`&;$ER5{z-b))9=s`>Ik=@rI6q+xCAg$=f0)7H~tn^+^K{66nP$>JKH zE_UE#&KWEHQu-7Afacj=j*dy5`sm(z_0~o6T38i}XRJ0`%&WC5Sc-D&rv+bGz(Mka%R>R80#&4%imQKBkO6ii$0?+BN+A*C}T^5&jZd9V3LLuCyv zFghR9Fb&q+LoKhgs#={>^X5bEE@DrYswanWP=T&X`|--E^>28;b#J=@EL)aV27DOy zx$9bIPwN!P_4=2T(O*F)5x~0lUFaF|bpJ#R{9;}`@)GVGJ4lb`|jr$ZVwr-?e ztr$`iSqyg%XCmvBzr$XkWdqI$hU2$!yWJUO)BZo9 zZJk%$Lf+z(F*oXNg@Zp<9pG(JPC-0MH-Suh+0Md-!@uc0U z)XBBoa*KZI`!8$Lsd$>r2CfUZZgt5b_?gBLwc#vdpx1;F({cBBW$PyRd% zI1;n!BzW{|G4s-ldoW=cxjZ7VjD_4t5Du+lL1;RVRZ2xU0O79KHrG;Ti-Gc-8dYWW zq-aSc_}WC>8wbC#$eT5}aFu)wik*SNK_pw| z7bCY@-Nh_7oEx*_hBzJu+*I6eWptU$bCnH0^h$NCkKso^>hL}3H|V_ zkX+-Q6+0NxL1p-rPXQ1O=l43nzExZ?%Yk>_i2yb4ZyLaR8VUx}p`>*TyP&T7mt7O) zLP+7gTD1JcY~?1Lv1o?nEu-|A&Ly3d7It_EW9R3z<9RwHC`;UPP?YN9=VW|^I^p-^ zW?j;UiQHw~ZR;-gxx;`~USvT`!2mVfFwp8LOMUp&X$4n9rWwbKejK7+e?<_5Ui{w1 zkup4INEtip-?6$E7RW23L`BOWEv%rXz#P>!1vLaE&M7Z zIXp-Yu{E7I)JAKcd`|w>qjtupFeZn9xAOYa!a;>c-{x5$-F$0>``ydTF{#itEE;oD zPq~q9Oc;zHp8@jo`(?t=fKh)Zt#9R*jqDEWPaSn8jgDE4*B z6di2DA5vO2ovXjW&RPZ5oop4*M{UhTBmGmnksud3?Geiuzi<4=g-9^>Q85~kui+#2 z5L+aFyqpQOb2rcRe)kxn_!{vxC{{#3{y8D7x)+gGpr~oLDz=nKPS~L2%EDssG-KZa zQ#CG`rye!LMxX#ljI<)phF({vVdK*J&b@(&Sdv71;9js6{Q)a-h}jqe%}-Y=v} zECiN^F~w5WieoM8sx)_B_EL<|-y0#2u4k>3ebi5GhqRWq!H}Rl6o>q?$s*Mng4=nK zQ9H}#(tT%;hd~G-smc!0?avW}>Dizy3N*hq* zB`@xfL8_-r7f|vSBb-P^(=v}@%{>=E27Tr*BMy!n(l zpbZ^blk+xCo!5j>^^ab)M6L5JqUuu7EKQ~%?Kvt5W(bUn2#H7m|0N_|FkBMsogi+8 z@vvl5`!fn-iSlEO76`vSLM`km<}aL#u799N#eocM)Zdi zdL1R&?=sX5F=}U;@*~+LQ49frqW9!Dk5HSSY;^$Iir+Q>bzSE<(oNNmy^3$^qDTb& z=wS7_LL^Ld^X|*^!K$%-_)nSGI_$$=|;b#eqd_o2%>gnaf24h>F9vPe`QiU}oso@ty3% zM3Sb)1YeNFL#9a72#COLC0uO7E#~E+CcjaNdq1nw56BHw#c?s*1O^$*tgj+m6L+x2 zO|Xse8wq^m`Np?pRLyldX&Ic8WuffsLJP#FlNeKSi%R&B6_?dZiq~;5gbl*stCmA8 zm0rjeBX~QTDKz$D2{C?>FN;+f2oehJ!O@KH`PN?k)KNg^wQ|CtnM?oG3l z!Cw}XR?OQ7_pl?`g|Jn_EgOh%&#NCC8$pr7i!r!@0{|kKt0b6VhOD+#7=4o8WyHB} z<=JQ=B5}%SXhOi~z7-WKla3^aS-i{Ik3Jp!Z5^eI){jLCwyg{Aa9Vlg?$|(=OUs)! z>@7qN#F{EMH2GQPMAXi~;Iu>x$-~_rU|X0yY_MnM%iOka(+AoPnzu&s3s6r(rv04e z5|KutpMKIAKy!wdRVDXc5<7#~ju;8Wp2!e}{7EpaA8(WAp&ka;S>`p*34?%82Frsp zs#ZpRiB|Xtu@nR{bf(HfR_;fJ8EHNDfNRi*@aN}i8f4%$Hq&Snljz@FKMkVIX!7g) zV@V`?*FVH6r`$wi*hO&>l0_*NbkPoGD|6<;N&OwxR@S77h z5hDu-!1V-&BT%6B&r{@byLg@fp|*?7gZh@HZgcRmc`ZKoTh1JFHChgz{!#cx-`jdkn=Ht3_pM7F@Mo4cdANY2S zVs>Fm7^=ZK#(N~4r~<0!M6#3_k_^vL{X)&h#M-ACpV(e1s3LuaZlKsp{uNoryeILe z+g>0+`B56?p(%e+_n495;<`>m1nS|_18Rl}sU<^N`>y1D6V(`{_jc8o&Xar{li{N0 z$-o&&6;yEo&gCdD)Tm%;L%%C3l&O$BSY?;fjm0MObMwSWst>s(V6kPvf0Heh8&D&a z1YLm6i$)IYnL8z?-&uw-KT2=>Gf@>T#y=^h0S7 z!q}!j-6cYnnA-{E;lPf<-re_2K`6BhsF(Ic!r_I204|gTmz{xcS|P3h&qBqCD5(9^ zoCGjFv@%ee;^MlU1js_AI|MVxltFA*H9$L0ly3f~=2=QNG)B{B0W zy~f}?TMGy3%HMJZTEGqKp(thw!gm^(ywfc00-a3LZ-+r!MSABS}99|xqhZs?!H)8S!&x3Kq zW(J@I5z@&c&?;l34@Y~{ z)^x=fgmeVtbewafsUww~{#S@G4Gu`JtjV7BaDa5dBszjdQO=L+y)%eCUAQd9W^GwA$Ey?nV z+R*n+nAAY}NJ7ea*x5pQgmnG*FdanU7szC!;UCokC~QzNER>R%=TMB2b1Hwf#GV#y zn*QPjI5x)Co&e?GkJ34Otu6cCIhZCWhSDuy&|Fa6AY6=_{b@+?@^OZVB1&5CsLs6^ zV5&RAOID*Wqr%QSRf!9;5#OMLf~$9bxUIdz|Jf}>WFiE0Gx@!hc z0+T?#CifG){c)0J_pd0EgdCiJ4K}OVfNp}3Z)-wC{r3DIZ5p4|H`ElW3E3I^qQPM- z>PC696td%$#7?{fH8>CMI+o-hgwA^DtK%v4d_ygDD@}m6Xl64d62UjPj&S=((ac=&DTtElexqLMv%>KtD-@0KsY}^*!o_Fc z>Y>kB&o9@0AxAUs@W~DhX3NnqGF|POQ9*X-WPf zUJgwvByQMNH!&4jgLyg3FM7V*SWeH&rAM>rL+S zn{$T+?X6dE4K3_IS@}(vtV|I-Y%;7B*BE9P+fVhljVd5fuUJ@^c`pLx2A+7vxby?Y3XDXAh6MxrEvgTm?%6(%!KTs7E9TWcxExL>p`8+zM*q zEiRjQQW{=S5BGy!zb@9SbUFY#HUmt?oec92Cnzd*`!(Kd3qcr>hfV#!bj)h#ceAh| zp_Ar;kcHxoNV(Q-!TG~lXyxHEk%f$&^(t(O0l4b)k=bT;5r{wz(X*ClF9=aG7fn;# z9e7{-Fl_YYCDlwGZ+n;}2&O!I)j=bKf!@;^rWZMn&{Z;BQ!fHCrn7}zCi>hREax|L zQ|(pEHvu*$arst@ACZHqZc@*d1O*`HrR(H{;~@!Ec1@Kl#MBb9ZeJ#c##g#{yk?B@a1za3xWeTs7Sw3!UPc*-Hy`s&nOg*F=MLSc=) zloFR}t|FOlgAp&t=&{%6&4J{d3!ZJPOqzfoPxEWyDrRN6)zD0eyWAj+s-EsS22(s6 z$BuDJTijL*d8LKg`i?1}lQ0ElH*Zf*(u(jSf?V2DaGNT}S#_e_sU|FW$m^}P(7R)s zmm1#{h6|?O7bJiNW0(|WJX}4({3&s>FjJrMKLw+^W(puR!qwDd@D18QVmcO;)Vr+q@HnRQOl&vk9rOJ1l=W3p zAV{e7mi#7@o-FvUguX#to0Cwu)_TKbLnIDEps`J4g0uGzncCAxnW4|K4%ySv)MP1k zZv|5SX!PQ%TYZ~V!c`96dm1Inkeqp@E~3A2v=Xl$r2+g+|}E-m(Zi8 zlxW@U&Fq$RI$>Rb14G`;;G^96(<&t4R#kF`>iu0%y6;Ogm~i^qGv+`{OCr0ws`Q8I zX8Ed7lsj`vsWo}qf&uc7q4&!2c#A6mFYXeC-W(Ur7>7>f?KU+3hP^jrUAQZ@$Qipc zI9IU7Ii-Y<0u2Y7I``@0TErS&gVutivswuc7jzzlfdsvLTo639!{r~#4H}6uyA%Cz zYXlXZ{wLCs|niPThzDEML{hCx} zBhRFDyqQnpp@Z0;c+C{c*kDqZYrx?Mn4^%S3N$qI`mX#A06+|o6cJQ$TRY!$)kZtQ z16&_nGW#PxLMw;t0MP9hdF`~CEC`%`o>lFsSypRWYFS!WRugDewk#I>)T+iyw%Giu ztAGL_2%6dp@B2N7#|-GV6@%h z5r8HMLKZ6PW3$(D^2$)YN11^Yh2zO64kKs1K)$aE|4x zJ2Na@hQl!^q+$R8F)_$PXrX_LSa3YvGBYzf-0qLEiXcD-=wplV``KcQ*8m&bdDE^ytUj_?uRRfpkaG+} z5dlP@vzBJHB==bGZnGE;H438l_RCsNb6NcuvCiK$8v^>Nc*68w>$H)a@Jz%(p9GrK zm;erZIka{T6YLN&$&8Y(K{{K9mk?y3*D??-A6zk<6}VYyf5=`j1n7J&378K7ZnLE{Z3a0O~J5hRS*k z8e@>Qv7xP{rIjvIBA-=2$(L(uY;4@*Sxr)|0t?X9)oq^A;J0XQZ)$2PCvlU(ze&yw z4V7$B6%`c${9>&lSXd} z9CZHcEXKy{Q|$BmQDhglhbzJjz>mhY_{gS&&a)B<0H|KV*x3E;^g~-A(Zg&t>ZwJK z0sXgY4hz4?aJO_R&jn@vKX>h|cISF*f9$!K2+mO0_r%m-7R`LGI@!2!s!iU4p&(2~ zKcv=-(rY~!u){*7w(-ej^dwhXyYbsbC{MuKVYbrJ5Ch}N_4+Gm-$mW$ zwzUS3C(GaNbX}1&ib@++=asoIi(Zc-|29p036cGXYxE4bUU9C!!I&Pj(gV ztN^qIwUxE?-R*6YCY`6w2&0UNMur;x z?A5JKOV7aI3&MmLG&7E)ryrQZoE}wuv646q@;bgIpUV}keY)L^l0yHUuGyog zvG$=wk=1tF(YoKHr{!i*&1dFyyM6OM37+3Y6q#KW?HcZ)YV)xQ!4j5)tmbMcudG$i z^t#?enJ@8Lzr3AW0$U=|aHt*_2rcS1(r*~-U{QVmn0JJYmfPNvQ zP`&~sI;eoXJ<|Z=xA?NEs;I718*_7W>|b?FP5TaQR!o0SPRtDr3stC#mCQv&MGXw{ zMZOs@1dNZ5|D?tkVB{gJl{$lI*3?l@=q0x?FzC}YTdI>}kxflWv0%aV7wFx!OOh%U zAlAq7dVT9-gn)p6A5hoQYBie;AcoGCqeva6qorN2V8sJBXbl}dh!FYK!s%C@O-Dnc zT&@Dhn?H$&j9k4$Wsz-^Okc~%c_?#RY zL&E`Jy?71?4HZ{ZjOQeQe5CNB8@p$M@Q#FxVg?pY<)m`y`+0)EO{8q^I6X3`0Euzx zbWZY#V=F*j^mgl;ZmB4gSTiyz@%if|lwm8pBx4E>yVYyKb;e&fKrcczS5GY%48Wxe zv-5=LetkFU1dc~oT;72H@GbgXe<_4bkqP3e)rC!!#+Ki5@m>K6mDp+xk6>A3YqZGo zjb)LhNmB^^^Yb%3JskrBAm>ah)AG{@?T7mM}i%(SX6*;i7vQn&&37)G=h1%28vt=WXQmS(C z@aTvpS&A@LTv5f|-d4wz^6z)(Ym28M5Rg7+TEQ~YbH54d6s3;21!(rOmght7U&o?HMIa@nTsl=awFx$ z@dMc400bI44*Y)yuMC^LFktUEjQUBPtXZ8hexRwTX<}qlCoWQ~G`^ff-ls2R!vf$@b3TR@q#mUCGmtrL5V{$RV^7?WjGwv^9f@}hd%FDzU zdbx#p$&vA?;y$XE-cyWi{PrB`LaK=Pqe`%E`%&S8*#xUUkwNnT3)IeN-E5WL{|L-C zWoBloP#c3y^AO5^i?3@v1UggB#DpAR)~x9-0E|on^;UFfaH-;k2JIc7tq?uW2mx8y z+1XiHO3KR8Qc^4H4;Iau#Y(d*)~2SVda&@C?WeWmthmui<@Q4kgS>_9)ZY3C#* z{UO&?S2wfpyw}nd9@5m(>S${N0Z1kQt4>Qx3o!L67fVV?Qc_br-P}01xv|jEDU+pa zZEaiVn)n=_y?lUW2bi=v8*6KtK#PQij~}EYCFzI41!Y8}(9whn``#a;0G{988W}9D z1@qL5pCLcSxq@+vm8f#3O$|GMhNMnbHJ3Fxtw>;0@K%6~qWuSYc2*h3cs|B!NC-P( zhfx4~q2Oxi7wHyVjgf`l*yKTa!2o%8j<>S9$cvgRCvyq&P5J{M03A&!+`WZ$7$x6~ z7Za6^uHn4_UOEXbN9C{HO)E)hWN?-}Jf7wtY$<8!)yUbbEc^tr@2KIbm4k0O(5#9) zgs~;&7id;sZ`2?Gr}J!VY_GehD;@Vh6XYw@>43qXJ)Q?xArJvpJl_C$O68YZU6r}w z)v8(=8ujz%>hR~)bjecRk)eV0w_Ns@mJD>TP((pQM8y3C6})L6MYY{38^mk0K|Pha zx_TU$hPwJl3k%RwGkQjNn;PEVfOT;DLp@isdfkxP5EwD5VwhGBeh7e{t8i?lD|5fc z1W?b%fz$igVIU^?{+|c9AT&5AH#hf3*d=s+s$TLC=wTBea zy?-W~ZTpX3?w-;*OS=d?{Btjhu4qk2t+i`h7H{Xo-wf8pwFq7HJ}aQ|De1tVzEo{6 z$ruMy*=;&1FyX-f#MT7o(B?`Ju;<`keaK*dIy!S}YwKVkk^x2reYYP$3Z(W za?;W?baayw6D(Hh<1J>4RdHu_zVYV8%X>0C+Nq9#DuUSy)9^v|m*p&Ov{>P+3Jei8rZLc+n#0 zt3wsua)RtnLs zAUnJtYrEfiHX9+izw&mSU(SbSyT96i=0?ZBSY2H;Z`Q;Q0Ld?rqfdnc515-%0(RP% zZ~?_6xzh2Gkr^|VSAVsN?ND}^AcC|RAYrK^0Dl9AVmlT<2KPJ}-L+eZs1eGa;hzwq z#XKWo12QfWWat$GxIe#`GBbb?4u!5zt^(v$m5Ui`ngPTj-xPtRz{RDdxcIwd0#~+N zxr!7SDqpUA0@+(95Nb@i;Oh^QGB!7stP$7Mqbjc(nhZ67Kzkz>RaI5h)y>#Jvc>cc zNv*I!hgjC0b(g7B0AVI!Y$=g)U;$;mg4v1#5D$>m$wK0y5-r5mX)QxM+yn#r2;lnR zK~_$#rM{l&C>-@Q1U{r1yCO9jNdAa#E+tVyBlBO(ig8q*XM)7BY&=F>KNuvF$PV#9u1Qzw(Iwyuj|)3c$F}tp~CtVq_H+ zm7?O}`dByp0dOG9)6|?}nMBmzJv=mVbBrY$^*E0NhJh_iCPfI{Kkx##GwLPG+QUF&2Pc1T&vcfE!?)GxOGh z44ih;o)#>Um7XY0rTGKw+H?2>1i=1C89_}&WsrM#d~!mC4!i1)2jpMCPy#lIVKZcC zaI5U4!NI}B#pJGYATw}qc5VjpgWMiU%t%&T1U#x43Pkx=DIl^42mo~{1C1yEf@&b* zf(h7hXd{!fV97{GK=uB+w6p~3?>Bw`{0y{K%b2xABA~agPmmT94Lm+A4H^Kv(BmH{ z5(!SOu19w-uMZ8@^uQ*L2SOs5K#(Owp7>KmC2dV3!~h7yFV4?_Tm;Av9olkoavmQa z&*y0@S8{M4fmrudA-K7jbzM#{UjgX00Ae7j`>kCQ85yZgYqHJ&%uXD7t!3|BhqlYh z%X0y2t5n!#O}f?*AY#x&DdZ{zI@#)gT}Xj26?K%$$DH)po&JvtZc%l z5p{CJMPTnz?#KJPl#~=ak(DBZsG`;1#bM^M?z#2~XV255`tuQ#2e)ovAO@I3d(8|_1uEG7C)u~xT>F*O6h zYS0fE)NSsy_uWkdSYl^ez*uKaoJvl6#kSeoC4p&R70Mex3@j7C((~pPiMwR!gf6B` zQ(dXqS}KQQX`wthy3RGJcZER`qyXk?R^b%SxQK(0!=nj$hd>g<_%FylKdZT@MHRK_ z)rgT5&_(B+1O@$l$V4{?gOEMaewmIK46v8{Nk8o(tKk2H^pqqHQa~HLxw{+C{@?Euq)=G7OO=eRApk5=fq@!+|5T+QT&-$ZY~WV;2T@g7qf@34 zQukNLE^I-Sq$DlaPf^Yb^`!1iZBGZBK!%z zK3Tr$^k*>6hUple)BMw2fUD<=nVO(M!m|K7zQ0e_sL@e6t?wAKeN1h0()}x zD(lzh%+bnmezwY1wATcEpy3CqZY+WNJzkFK)7RdmhI0XCw7nU6A0{aw0Df$DwLc4m zHmya!aZk(bb#r7&*Ze?ZlH>iN^fGx54r*F}O{Olb+p(8R@tgMK z%G7?D__gM#7oF)tt^bj|A#_r_D5uC>V+jEG$!$Ik%}m3IePQY;s6J22Z`v?mKa8?s zbVQy0YPx^O#;V=+wtEqtZPBQluC&O}^WIgzJ5p_5KjqGzkj(^ohuZF@s+vr!&Uk*_WtiWdoMq@q^5JE3;m}!T)Rise_Wim z@jyDoPUVcBZ2;56kA8Q3S??>kb*D&0HNnBiVsJa28ss39;B z{-aC=DI^xp<8-55y8(7CsLc-!bXc)TXnb)E!oKcep=vwtM(yN56j}`6QlcFxKmbli zPgZ=}r<=AWu1-6k%jLsw;~`iV+pd`i{MYSrdMooe;Cb3m@HT38M{?vkd+!@{Cz1Wx zQ~&^SNKDS$`gDqXT#64Vf7&A7u9b{nvmlCv%w$=+&75+OVQshdUwJ*sqR6RS*^@RW z`(0C+pljZpkfc5*<_GOFj(fDY!D4FrR&C-#hcg^KSZdGNAC7^fY>VqYJ z`TRGEr#> zLy%z5mUv8_sX05hzw=bf({Ya|fK)PPW3g6(tIlJPJ+!8D%q-&9{>!N!wEF|Huq-g_ zmSvd*Jf1EuS|0CTB7-)fVlJ-F$XVO!p~>fB|F41%sm_oeDF~ol z#ykZP;OAiPh~kv(x%;d&^{27f7mcRY_;ZZ?WFgn28)wnx>gL%_9xh>OV}ak!)p#X< zIEPPW*vP_p3@I`5exe<~A^70|QPDkPKiueKb?2M3qT?RZTBYI~?ANYzablgUK zZk^WIzh>Hqj@!N8g!ACh+q&(Azv%m6$39q%ko%P**a``#c))AyuzvUIJIuQ(adz0P zh*Y-CmTnK>rlP`J76KmZ)o!!ppHhaE_dLADt? zwQom9NIqT*CtZr&NjJ^69~7S+Yqu99z*1i}dc0JPX96lTDIg;Q4}ASM0uX|)i7^Sr z=F!e|pM=ruG_~A{3ckQEh2G?rb$g4hyR%1!5O|$fam-S$_wqPqHs>U1dO|$;@itCU zGS6!3Q?Xc8i>a5nT{`K)9^Tyi)k~P|#!d|e)EoZ~IDgZ6*7C?@t<>!7uH}5Stk`ws zGu>^?0YF}>rFiP-(s}Fo=7k!f(c~KYtM9h^vQY|V-S2w!&1L$bP=@Uo5HmbN^hFM2 zyP4amR)Y~3C48D)9?k>vYL$y>HQMg)&rG6;c6PmJc&sfzp8@;Df|U^bN(9Kq zvWS>iNJt2fmIARRkPP&kgNrKSBZhhekV!r=NG5;_>MsFD7$Tyg?j9bv9}+;UAX1>) z<-ux);p8FrV5-E2rf1hc@xfzR@mJ?vZ>Q|tlhRyRSXe-w zTCFa&UfF6i9y=fpIG0JL;FsO*@zpC=xpm`lb#(c-R=f%^IQC17Fs0b2jdx1m^9p_7bKMSL2%>sFV5N}i3_h)CDI(pz{S&7+peEuZT{ej5T`R;spgy9z!8w&+6H9hkAc&)$U z@wh);C|7nooG_QuP*YJsM?;%$GzF?RRYLg^^75tTxBwPh1kB)nCpeYE%l+#QG;lnH zdpJ5V!Q=IOT_l-k7Yl6ptU5s}V=63t$LB7>%X$Rup9k9vbDoF(Md`8!l=|Y~?Xy6D z1DwY=I66LEZSz|!lmV%OPKV242h2eF4^u!M@M<4)vt;{{y1n0)xNj0E%22$P zWvAC6pK7FNZ#RpUpy#JpVha~wTw2ydgZX7 z1KV@bpQk@Z5rcN`rFA-&?K3mSeEz|chEFt-5bEZ?xEX8<5eC?BaBywfh=BU~dWSY1 zIy%|H*@arF5(B?HAAf)gm9k<;$R8}+@a$|IphRkAMVmVAt{d#?X!>VY z$}7~STQ2pWtlUS2L+L%7JeoUv5na9W^})cw{wsOK&`c_|m3ZCC%j=u0%kOv&cbz0m z5W=|8Cd)NCR$l%O$FrmWpi0=~`D7#El}}=gBO{8V+y4v-P}k514hrh@q5!38P<(GY z4Q=(HgWENz2LLpqQw9dbzAyYvgZnP>gm}YhD!xFDB<9o#C$&eoJ_9cfM|Q{{jAGZU*SI z(zD~{jub?=8z+~WGrqm$=K?6tEu595&DGVO<#%r?dB_ZXBi9x>e9Y6cL+YCg*sGy}Zbkv9&2)v+FfWi~lbuOwN2e4-h+={ayvr2&;EH z83m%l)dZ8p*jg(ax_Bd><6i0cyCu^3=^@t4u>}OsbRwRLi0D*@y!L|h4?KbZWGBAy zw`!D9o8}Sut_!mqAMqTf?>oU*_KSd}*rst8X_dNsZdK>d!eOv?6Kyv(XLdCwH#_Qo zy>t+%EHL)G?iZ*n4^dBbZ})9a*DkJDpEQN*n7}gB;H}TjZw)OiZ4I`La}P(PQFoYn zg>aoWpO6+v@-}g7Z0lMbEty>38sa2#TFcR=yMmkIEA24gTX1kuJlf<;U!RZ$W(R5e ztD~+MPE72A$U}lInPfd5HzRIM$>m&#`FMnUlq@Njw2OE>54?wU^Kv<-5f!s2vUL;R z-f=%3bT*uKP!YDeUUrvOcTHtGzea}hg7RwX@M=BzIDQ24-~z^CWh`e8=GEx{W_x^R z7N*-rnc_g$yP=M9%1@#BVujiss`uc8)BV2QDvm&~(PJ5Ev&YAuDZNZGEEP4aI$$f3 z?eKf-6fsv16SeO8Jh6e&dR|~TKK=#%Z5``oG)1(q-_zA{nOw$qV;O3{{r|of07!N6 zr4S+%@l-kRK1ITZD!bV_F@%$!10={Y_`JDf=e_v!Xfc;rS(Rsljuun$z@P9y7+*QDIO1!XTC8lU;EYfdiYh2uF5$!mY#^;b*Ut; z2MYrD&&`ZTPlm3Ry?%@B+a64$Og7+;JLhbz&u&iPt+#!%=i1s; zl*>*Z#)bC%TeUXl{^Uq&^r@V;$Ag*HTz=UJ+d8@`J2Ppvzb_2R zKFTaz+8Z>gKKa(=v*+fM1*#IPE-b25$?`p4hM6mOTf4fOTaNvC|37ApGvz(l>j#KP zY!hDv`;*dh5Y@EK2XiY>nthGzrp@+4CS~)wjf z9TUHmjVURW1%2+AHoA9HEU%)M!D<})(eIo$$BIyQPROwp;S!S{nhI&p59Q^F1%0P1 zYN^%CteLN4+b5AoU(H)FqgziVwGd|>+nUQ@xi`T34kUbUuJu+%AzOYi;_BG}9}W&4 zF*gv7eATRDc~2XTwKdYlCMH|I?e~VF@y?}PxPJUdyr7(IFqTdr15WdFOKM?uc^n44 zMt6Vm|0&OL*TZK1C4@wT$0w-y46nySx4#=)8Jyf|RTjsd8e>U!c)i&#{?t7BgxyTr zKOI48#pEEvez>)1MBqnnzRi#dis{9~yO0B?J*>9n?rL|l8(0ra->>Y(Hg-M>y=}@| zdV{AWY5z!e+SA=J3g{difh&4Cj`mPbwp`nXOZG-?E<69Tg}o2sfyl=z&&L-w)~Nx6 z%x=n!bWlLQ&$AZkevd7GEx<2gJig-&O4f5SxXc@GWySbSqp~EF>zbp*V1DaZ-R(%O zrc_6@erzIK3zX{v81OM9;}i~l#Z2E zifFSE9PBd?ZFMHZZHilt~33WpV zQE!J8J7?A%mkgHDOad5zwtEC5YNJ^0e|%v7sHhFtQ1#e~Fapb;g}TtJ7D!NWsf-8U zSsLlUxR+d2RZ~6*fJ0s)01qqc;?&gCz`)*jZah#EFBX#9=vY_T=eeEDh<(yCz7LYq zlBOhbNd>~wBCr-QqHS5oL)ryt)|o^?GsHh51Y-q)xK^G|D~{Lyhta<=htMS<9zeOS|abb zAEIB^k?UUz(NXwH&c`B!>(^ui!xWsP=zf~TY`&>5mU#9D4cdgQ4yzGGV3lfKj>jGq zQ6-dOIkkvkaX(lmkPgq87ax4NeaqFm%srMlaXNcH6H~ljb|v%%wCq)ANPi$ZuUaZs zmW(&viPCAVsCAD&JU$emPVn9z{wDy&>i3Fbx#V7<1+s}cY!B{T$vcmH&W`c{0$d!N zD%|sy)ISKasK;e=3X`J`gHK#^nB~9I#C)*7{)Us}IxAJgN3Qpx^m!mgM$czlCXH9e5I{M3`Gj=k5R(O;5+v!zNhz$#OSY=HeMU9O|hV=X6-| z>EB_gn??++k6n_Y1F5@n{Ie%o7oy^wyJspotzo8heU?3!Qwej?G)+6Ti>=whI_rO9 zRYMv^&X=aPHlt4zkz>w1&XA~VUWb9tGS8Ft{2}S9wK183`thN)a+~uFZ~5%6=jyyd zaDbnxu42vljp^xgt5#ZtJ2w}18GZ55{Ei%`A3Z4@0X{cJJV514cN4-k_jT~J-L&=~ z236EGG`FDDvL>=)(#E`r4v_t+UJ*=;2skc^Esioo5@%!>K7BPbVh*)5w-dllS!pOW zj;{g^L4e$A;%>vnm36ru;Q4rda(4Dc6wXk^Rx;LCJ@4=0=$I%$7IJ|Fystp1JZby@ z2>5}lfI$ZnS&o!nd&lSeY-E3|l2J@i6Y{Yeq(%reEx}UDb*oHSSeM%FyotVEkKyIO zq$UDH^Jjv`#qnw=H9#Mh-s#c+0h`PSPNl1_Y!QCaeyF+k-CBcFR2*DxfAcMQR zySux)ySux)+cwYpJ@0O9?am)m4O7$8eedma?m0i{QM)H5gA~fjnxwnGd)cKFuJ_cFtahn%~M9y68cYIM_@ z&vssH)M84T42KbNC-=PRX&%rmbN$oGLJ@zWc^b=c4ytBzl!uM@9Zi1^?Z|?+Kxu@`nky{9wj*M2*jMO@tq-x(mZAgdH z*-vdqFkZ_}b&*l7r7Bac7JLOK3ysa^BuG_KteQd#J7=99@k>-o$H>7wFsXM}o}V@m4v+DmEx^K?!g5&HJ-c&jRJkmxYj!MHCPBFpoFF3h|3+=k zYlBZ%GVN{bx0}ExyHxIa+vEBjjCeh~sH0kwc**GuPG&T<-2Y!_v7tG`^g1l*)ORoM zNV9v3!<^#aSj+;+aOuGik=f(te{OwK!~d)YWg_+U$n-viocjGl(h$t_ENp(UIpqZZ z^CZeFd$(^ z@aBtsnnLOb1$5}vb;8tXyA!|q%HT9NII-opH$R2EJ1$z!_J!H__h&SYQkSdg?D)$@ z+ZxMqFe1SeqgP~5?pqtZ(nSQQ{+Y3m9q$29&-QTUSgcgZ*;eYTOoB*Y?$rmXrd49k z!QbB>?(=6Cox;U>YXebH(P%dd41i7Li$s*dX7n?%uZ^N!;;nSqcQ(M}ez5%s)gmXWzm4g7 zpl@sBed`J_zu_%GKO{zPoSZ{ThOdfOudBO`g!165!QfOr2dn28XKva~#Q99D{rIKF z(b_j0>59l5=$M8vH+@aa&Q4?|dh3;@y~ot<>oEmBojO{Fn)(lD^ac`L;m1t}tlu0j z#wp}ce?mm;miZr`34q)>mqJjv`Y4U9fC45o{(m4PWMM{xkZ!l{ktk?rp8x%yqY;qQ z(sM|-xUgCOPlNx8rE{I||M4Sl5ZM1T+>nJw+g<6p(zsjO0!5HJP#Oo$=E(l{qaV&a zx_%)cCkxeuzvxOPe`>nQ=GmsuDyZ{cs>PP&SoguyvVlM!`qx$GovQblcbXXm@b?FM z^?cv1|AidJC=7-$YpIv;wh=RyU^{FOz8dY9P?>ixFq$bqqlXT0)iI$7|ySgMAj} z#)zm>IYf_V(;RY`?@dZiE^l%S&jbHEu&~eSB+#JW*c8mn%mDF~mUb}desKC~X^%~X z_5{m$>0Xf_0|8^!B}vd}Ckn;dCHeq1P+3pH*Xo@cwX76fxD65O<8!F;(7s-x^Y(3M zkIW0RH}qH+M8K>&#bo>4W~@tv?s`;vael8Ca)RpPAK3NceAOUs+wwwB-x)M{_=?;t`|87~CA4N3iG}xca|PO5RFJC)yXPfKPC6%#;8mxx7?7b7iS+ zDKL2i^t6y?(2!J^f|M~|Hw!;+moFN~-QTo)7D~3e@?0k|Cw(VxXtaHHP-BXVt?3Z& z@lLB0+!BXw9BaFkX_N`wGBGnb-n{5UX_Z=|xCVW@M?>Le19X?)2^Ig`H3sP$He3R(*d1 zq}AE?Iv6wTaf3{3h#&+JRy8p#jj5E&j}N^vh9xdz)+1)Egd{Df>O9o-anQnlEDYSw z-(VDg79aU7n;mknzwfUKyw7_ffhG*a!o=L!*!UT$KM#zvX;teo+>K9t&5APi_Kv=2fx5mFny7Du$?2YeIL4L z@3JKRd^k-D=8wNhKI_y*3wq|ec@U6&e2!G{TAtFwP&k+V-+^Pt-}NruADB{(TmDZh z=tJL8jU$0&&sAvLsU)<{&(E{v6ZyRJKT*l?9Yzq1VM2~k0x|3jqx37vTH6vVdnsy~ zPw1QiVe`<{N2_ZQ)$F34{{zw*M|~5!4)D_X=T0v5EbZ*)-mEq)|C@t!3ZX0)f=Hy} zx4x~?EL4JOGuGPm->(#{312^IK7b2)v946|$fbmXIfnr_8&-CbCwXK_f*lf|H4-Nr z9eebllj-P#4*=Bz=RIcqnL#n0$+Q*Fb+lkW;b}9OQk&Hg*8r%|d=vt^O;npQf-LRQ z_b(M~G3yU-9>i~CgtsrIxI)qgv};Ip?o%6o ztC5Fl`1|#ZbC31y((tw^pD0ywvPSzwbBwXDk6uOD*6?ZayY*&giM2mgWr-_^eCm+Hf8yTBI%K^s?Y z&6`VjM?rw+;`-q9R0dLSymbetD&pUt?KHa#z#(m#}?A zu)<+WL(wGUWK^DJF>1E#7SBxc??kujc;RjWSMUpB`x?EJYY-MEIZDXttDL6x^vmiT zujUh0^FuF#Bv`{*1=K!x317Kjs$H(K0V4tzJc6Vpb#y5LIUn{vY zl?xA>=|X!SXKP&#rt%;B&ZNqz--$E0Nvo6I)al)hvNyzVch5ldtc zuP>zpOE93{VjuqU4arDII?|P@3k88Bb4T=g*y=J0Cx4(T9h#2nYmUCNI15E0lTe!J zhYRSn_)Q9=D@!-~3NY?d45`;xE52$TNlV%(PW$KffBO?(KyjQFggb<9_zE7U`3E;@ zg`6f0J!Xwjf!JS9qf=>MPki3>ufmM^6_F-_t;^ekh1wyu6d(|vums&ahsQfm_p|08 zma`>O4d}>|ET-gDR~HX{IQy1|PFdy?DhXSggx4L0*w7Ih%6Duk zF?Ntynv0GAWI6qfXLz|J=d6SC>-gKf(p^Z^qxd)XZ)?-X!=o+Q0BAlHvCo^u-E|lC ztf94wG2R*!Qv#XrY+EYEVEe`pq2VrcW;)R`TO$2H0a;6~wU7v@AOQ*4-an62?gw+W zl(9$jO@^RCpXxtdZ*PQxH5@e<49CGE4Hj6oV0#h~ADn)z-$6v$JcnBawXvs7@tG9f zpUn(jZ1$R&7*Y%X8Vs^N)3nPw1o1z0koyZi6fzJo85vaNXJAjoP{R}&6qLm0z_J*# z{*j$t!2Y7?WmOxiBT(-iCii>|G$1N7}hu+iWLHpBcxUsI} zM)Ff0-LlI{45jx`D$4R|;Zvuvy!-p$THoBFq^g4oRFF`j&CS=og*@w63w-Rv`+bSW z3+#@a>S1Q>o63Wmes8C8m{s%pts{jV2#=Zb{ZuE?&r>38$yBa{ACGP3;_st<{Vy*1<)| z7X;@CtJzSLfjB@<&IBeTvQr$)QakOrlWMVI{|Gr89i=q*lB%_SwL5hC8MDccpCzH0 zBBXTZ!RI!#`flT3Gw5n-(N`JKF7u2|1eSe&?Y*KCuKu+$!co_7A}1LsDK?NJhQ&lh zyFv(fX%Y*jH+{)@c+@B&rys$RKhhhl1<%*@jIKjRq(WV+omHbbxBVqr2KGhO+I~eaSm-$yGzJ+saw7(dUkb3nE_j zkq`a1`~FPr>V#VAiBig>fCqATX6e}Vnp0CwO8r;@|MwPcriDH0vJ9uRb`1*j&P!x= z*2kL*o_eBU`|whHez_&$_r;Up-3&+2!|7}Fb;;J^>EPTzHMTnM{`G;0d+e{l2n()-YrsaFk)8y%l96!;*}~o8+WLD zgt>grS`g!MAF_*sv6<+uN(6xH)q$9^$NO!H4-d$!Ij|`RE2^m>sGqzyuJ$KGLPC;x z!6mn_Xt$AstMUar1-^JFRm7&z>!*tC{oPRFuGYB-lG0NDcI|2ojC?QBfE`eN@zAl>y4ds8K1dTac#MnF8!Id?Pf$fOLuVW@g|#M z4Wd&-!NTH%-2H<{egGmLE3m&>tu~qUfFZce*{{k44--i_w`nJkCcM zMR=fkeeA?pU8aWmy2$NI#Mff|G8IpIo281B8Ed0+3Uy$`=pxA46x^lOhBjyKg%IC* zEsg@v`UO~LgGpiA!;}_ZW@jZ#b&jXaZc1P#SW}xZk4&kn&W~HkX(}tqFYZ5T;d>xo zsb3r)t+?0;rx#nKer%;wo=R#tSo?q?6=tW9sR$Ahe5rv+CALp5Jl#h?eKMERc6CZ` zTPS>NYNkF~Rug*);pSKO`-mxLrlsk?BJC?!DhtC|2L=xg`eqhh5&x!gf?0eTIvQ9! zUly;rhv^8&W@HU9toYZqpd|h3~0ML6dLhqRX%sJs39bkBZnXwyV=t2)vxrF-;BIO z;C{ZMvPqfVjAnw-B6+2Hd5?&dPgo6h@TZ(Bzn*^8(r={#Yjv_gr(s8fpHAin^}!0_ zE|BbwpesZobT#jTqubT&Dn~Pjyo!?JP|p16DWh)M)6oRVWUYqGWS!jsmN&Gwh0 z({V39=%!njM_Or0hE*q4ksQSVmJ@t6UbFL+h%taf;yYu}pqVily|i+5{q^Mxh2W6Q zn5ee%ti3D!)TNoxz{XppWfk%u73g9v6sCP~A2`ngvRz1RO`+kyjnLiN{*<1W8XE^? z(|+G45^4hiWd$eOTB@nxDA;NuE-yf5uwyvV*wTOH=+N)WD{BltHRGelVP**{kd6r< zGH_m-v^8LjLfDJCM;b|PTBg!t#y$%9mYp8_x76Ezv(Vx0*4<>nivFKih};ZcL>4UH zAh3^QP5b_(4mA4txlbJPYVwUin*JAG7ucMQrfUMqtQN=X1K_qgOcthM50Jp#cP;53 zrO$Xrg{4h2c#ul-vQot@2lr%Nm?>|%+H|?)4qp5hH$jV6BS63(ewA?D8@-naBe>V| zQT)rT#=oP9a)PwVeB?RRhVJmr>>(!ivy&s)t%oTsYe$uI{nyrhiLQwaiJBeL?p zz02M1Se9_TyLhCB=e2aFek<&hQl4$W0Ws@#8V(z${NXU8uPpsIh3K+yy{E;RVYZ(OXuaY{!;BHC+(3TPA*k?`e2=9RLq;ZvsmvAvraX~ zYQhV8?tgh+g91JgR|!x15Ub6!5&lOB$XT8(lK=Q*G#4xxDPG6*}bNcui?~Hp5X=#l_s)yALPzYJqCY-iwV76MPV1bCPpwLiTjP zhE2-2)x0ct1v&d+?%5wC4USHY6f7WU)6`$eNe)5HE$xafwEfe-b`;w7?32Eh5S1qBTGAFx#RuA zTJM}fU+jgNjdx6>CB zR&~t(mmhv>@{4z!$y|P?j>i9w3N7_j5nfvK z#6g7Ga&sNdSXdiU-pIy(%c1kkx+Lst)}f3WLh!jW6a`r0F529o%uEkh)fQ%o)p2|P zW>QFY_O^7(EE17`A{DxTfPk)LbORi)J*)ueYvknQOiW?U5)_eQ5)x2CK+ka6*N&5z z);KN~ZkwE?7oalTL0$?=Thva`|Kk{NxiegN=+XLg0S^koVeMI1zy$$~$=l;a7|>*{ ze5u3NWVzWfWY64O14Bb9DUJau{iYEz-^S;vFU?zhxkM@U`p>`NU_e6gcIP1tle8~2 zC+4K60pCzh493@2vMA17A~4;otYXg)JBiM+1fkkDE#VYeO%h3}Y1CD=I8P z3k}~ijK8J!ZoX#<*ogQ9N_lE;MyGG91gp|sZW*b351H$MVrHCnQ0KW@?GduQ{GuLUUm6oJw&<4p!LC(VMu%!Z_@stQN|0m+j# z3ZRDg@D;oMS~)Q+44EO;1W;-I%m)}2fi}+%*MOJ?;M(EgCDJ4so0$<{VZngDe*Fq) zra&jFt*I#~C;R*RYir-Nw9H31SD%WI{Y4+jlJAMqDYildU-I(u!Une`Lhx|}AokCw zmR42;+WChE2LnA^JwZ5~a%HDe35xuwRP7bj)yGTqmEPWBWIKgQcLns;rA;l&4Cb3< zF)$)LH5CfG6sz)m`{&j-D6WZT+?5M2_YO&vdlTsV<;wb7i?frj<|B4Os2P9munjD7e_Q2jQ!GibW-~_ zo52>2kef(2czu+c^2J)diRl*f2S$x(YE-+C6gK`wkDWR1Ahp}gqnNwuw#`5wc(b&8 zZ_f03DUC121{P+=%p^j!#j4BRSbE$jV>;j?;pOGErwxd1Qh33D@4(vH+T7f)dX1CK z&B+E^6VTmmsw+S`gnIveF5sJ$6^r`w&G~scRRA&Uo8-C5<-8GmYFxeW4hotH0gZ?# zH9j8DNE6`WFI1cK?q0ro6H|z*d;sl^Bty9Y?Y*UDCzWDlUmu@GQ?VQ;e!A+AINQNZ0vBhG&egN(7Bx1^I>7drlk?vK|cpv@tVY8fKQhChlh(> z(4{FNHCtUY)4v0<&coZjv#2big}oK2?4LFC(138iveIO=#krXX#SeEhoJ<0cKmxk` z?^H5!asmz)f9&n;p#t}KaM+EfUY;K{H8tmZ;E#-Wji;#UHCCwp?{?P2or5$N;tRu$ zcJ5eY@-XR^O8$O5#*kpp6}LxmOVmeS+z;_&-l1F zK(q7(6|R%1)?!teCK{lWsukZ%WJ?2zu_IY0yKn~020%G%$3sn>UsNPRhpDcn_Hwgm z5lSS8`Nm2>)tPx|3&Xfr4 z>FzG~70*|6bad2ev;&x%2!wodL+CC~=Mr`v&jl6>it|p6015YR4iI-rLRt1aKLfF> zn&H=I2x_MfqLVwf%&(6jPiwK^MA(l(n+s0kjLld${vKD$QTdZ#ky`A>T&toN*3pl< zO7I2r?bn3mH=a@^!!kr|q<>~c)GO@{v|9^LAGt!ea zz=y5xkiFevEHp%oze((4JLrlM*)a^_yHxAq0_rUHP& zjDc|!xtjh~6FJ>HZH5X0b}_N>@%!7`7|6)~06sxh7P$v8K)nT8#(?w<;_Un;4Hx_H z-d$P!e#<~muvMqiXWypb>dJ_?Pk#Tc#laX~UFE1+&0G+kf zMzDpl^2}Vh-n&>Td-b)(B)xBM4HBoJzV zl9=MlmvehQXRUoOp!>)D+YKy4GgDI;`sq^bR^V)a03snK2E+$`F0Nm%C?Lt~pP5c7 zKYp|`1p()^*6s;7M*t2XsiQzp>eRwujP8%5tVH9rI|8`@&Nnh~Oz%KI#2Aus52jOe zRn7hN=3J1Qo2y9k5hO1^3gjqjM<%wsOwr^Z{4w}e+W$0dnJ!K0%?SVd(Pm=WNN z0ClRd7>&~Q*b(6O@Gbi%6*`a$pg(*ln>KnjHC-x5OZ&Y&5dDA%z*V>B=lLZ1fan#N zFs8b;i|gy{b9=yE!@=PV?gWjsI6HX@qX2@)hzMP-Tpcc<)=HmF13<6X`tnfdlMSpC zj8ERp&HNz10pa2v(%F4^c^P~H*m#6Vk~g@%0ulALUZW&7Rs|62r;he29A*E^9#`gH z_}6?rqkhyiD)?%8H}RAOn0vT9eFTMl%Lb^(c&vYeUVxSLe?%sE4!yWQaBE9D{19h} zSDcmA)!(15kSmAk?*(+zHO;S3tt>6i&&~j~C`-JI>%V#pb1|`x=YQ6$J&3V=j3#qr zA&@6vod7A1I>7iX3n?@^`hBHB2Sz#}XI|$$AdnZ&OgB^Hc5AcAycdPGJDm?pp=V5hmR&dk*8L?Qap6~D;t{Nn<4+Hi1iKp<11LMILHo1MMA z*d7Gdc}Yo0B!%pTReh@K3pbw4BvNGls%mEzA)o#C%b%vP_8cOBjYjMs`x2polYx;D zxBfs>L_`FjT?KNlfa6u)cA2>FKFJuz`h%iHU?{ z{q-o>;1`-SmYV_R$M+v#n?2FriTz0UMP;Y>0Rx^x=m?`++iBM1ban-qZm-(iV_QKH z9iGZB!wq;zqM=L9FP}<)sHI@{s#9*)$N$*v3=PFsCdOAPthBm@BELX{}T#n_pckX3mRIsrXMHsDAC+=p3NQK_k+ zn_Pk2#x_WTYqM6&Q)4-@cvl#d-|QV6;F6ozA6cGiDZc^6Vs9^@V^8t}?`?eLF2Qp_AY64i3m0w z*nYJ@?tcmwVA88CHP{A{OA!zd0GbTP%dfxaV)_=MqoT;ae3?E<(=jyMTU#3&Yk&7d z4$G+zgaeBjFMwXaCf@;YUEnc;`!oMu2!&8C)#Mk*Q61r#HA!^8{>Bi$c46hJP_ zz(AUsnhGJk4bfRN;0!WjDyo9S5L=j=D-rQ$*auz|3dr{Jl?FhNWkR5(qqDKK{TTg1 zXlQ6SMMs;5;|nkuKCQX}t}$pI+W%Gp?jnH2kf6&GRS+2?V`*NVA2JOcUD5nVnq9;~ zs<#T@o%N5z4cG>V{Qweo$H(`mECtSh9ZPWgZ`eT!zRdN@-O-M($dUa3-wNo00o4Mq z`yAbkjfw({Dc~Z2uLC#PSo}{wVea%SCNd1@Q@#=-1I}u>ld5zvO-&HMc_y&CgGt6d zUq|0WSTZ6i>6^W-H}Hc%dZ3{}9kI!y|NiIrA3heL7YQTdsBSs1!2n#3OmAT!Xy&Ue zfCd|Z0eVdy%xrHe|6bD>G4?&(S2$p7)^zi}W(BS<)m!iE>|px<20UL&Q4I;XLiDhe zEoRzkBZ4-$z9PTw4?=K*l^?HWEF!+)Ci@i;1dDe9Co}3{^ltUv)ArWZ2ly{c;f~zbhQP^(tqN$e#NH(y2IsuKwpZK?NHWwgY~rfdB$QFaY9N z+6Um9t4P4w+OcIYIlc2cFb7d@`=bH}Y-9WcTm{HbHTGiXI^*pp*1*~MC!3B2cmBL> z6;g}*Zx0}9#b33+?5wU^3@@+63!Yh=sg4b%WdjZmyxJJ2(u--V25;pf7~_S zyHsN1K44KaK5nD$XhM+Pkr((}9E{C-1a&0H^ei}syW2t&bQYWqC^|1iU%bOj4S)RS zP;NwW{JX;Z5}x__)OoPLsoawB@FZkVHQ`VLS=3lA*@z=&L7b;REm)K^VrGGv8KLuE zQcswE;XzFm7_ad_rlZ$*movw3Y9(C+<`J-v`tNa5+grb%nsn~JopIag1KL=UDgv;7 z;;Yf(J6Jq0Pf6F)*yaYYp#;<;Suu+S{>H&(3-ilkb3?=lc3OkV$2~ZJTa$%`aP2 zG-@BW^`E$;5G<2tMSvIWcXf^ii<+XOE05>%NVmJDxYLQKyzYLmBJ5-L;38}I^nueS zH5PGAEYbg9vzW?Oj&!PM4x^^@{KSy0d2Bk4Y>dyZ_=ADiD8m~`(e&$u#W27cUOy&D z+$8jiM66wOJ5$5{(IdnQ`TXT11dd<*kZOQMKl-}(QEv6MPI79LJlfUi*-tL#;FF9` zQAR>b_GVkLyjMp*(s(1qwRvVC`QV@Ysy!}~dkEx+0PpG<(n7F6D9Wzd+y4gd7{ic>3^~SXXA;$|Sg!_z9<))1O_fI^EK%OqMj#6Sl0K zIz1iiVIalUU#B>%?WlW)bUyo5Wqy%3N|@@jwkBGef~`$NaummdAoaL2{T{ zaP>bWNxGcyt$3u|sBdw26`%dDgctID|DJifb`a!MAe$>xq?rImNCkM?dOOAB#^c0xQybwedPHT%C3&- zV6Qx*DM=VxTDH~O+ta&#wF%MDG~s(kiov#I$zw!jqJ;5pi0_5{Xmcr&d1GCdzT)&s zRNT&4CUY-Lfi5gcDY}RqBLo!(LcQu_|5MTs*WCmOcTxLfr-}mh-G2t~G_%Pb?M_Y(mTd!Td09)N zPsT*t=lMlR!rB@L$}uutR5cN#KFAxE4pY5LOQYl+=<2FC6Uf3=F=jG`RDnXU;oYk9 z`s5u^>eVxyD8e$s+oP9Vi*;FI)YPJN{Jh$O%53`mA^i z75zm0vCU~vGZUwZ*2u!o9w<~?z(>KctXc4va7-=a0<8MH)l(ei8p)pek|;JNBOY|j zpaLnQ76xMACsb5aAs_`j!Bv?pVn)4P@ly~3G!zsR9v&XP1*E;ZF@w)5j6%Y*-|*&h zc(g?))+l$xS7MFoT;EDQVGqXHZzGIntLQIMS zNEm!Q|NJ6r_08%^kQGYg&`KOP1_z`70aDepymK znqh276z`cH6Mffn!le(P6z3;-iW3`&+>}W!lC|ObGmxl@s$;5z!7WqLyCr2NGTXDt zTSpQ%oBQQZLF*xKFLA#4)p^T9lwPb$arwEq>V^OAXolab-xiN|A;Raog7@3h0h4#o z)!ps>mN8ujfvwMr2o{htswyidCnk)IJNR`ZmQ6LQm8$n_9F5Jz<#Y&zC2P-v38^!P zw=J1P-T0Hw9>A0yM0oDYs zBU@Zdgh?Qk^xnkP{jJ%UvIR@wCi{>m_hO)^C}NfJVY@Kif#j7tn|8CLXq9D+6;?al z{vp!h4FjxG=iLB-bDRO_8<8BwMLtO!lC3&Y(x2Az37+e_wG5?cwE2he^EU+3B195? z$f~&BCog0&A?Dvu0Q(C)--At9k}l%{Hb^z5Wj5f1%4d$Lj*1O1W}**U#2} zyoitG+1TiG`AxaMu<49AL+dxAx{B9WKGlCz&d@@79@|VG!0qYpd8!JXs4NW zz)5AedRp4k1Oj5}mSm)vs-&|%~G?T2Y<{-03*opln!#+AT5O@)!e?Uub45^0GHOs_3A`Ezs( z-TrH1QN`avdpd-oTC!koq~yzMSKpp3ey!uEJy}z|SSS0!oRLO@mHlS_XjYO>e&Onq z1MPdq_IHSFDz8U>j;s#vT7Qg=-se4oOh~mX4i0d6>9@DOe>4oR$ePHiCcr2BxTAsH z|FUn!Xcky`ea&p7(o>+fAt2)Ua<=obqw0rtms-P%jd4a4x(Y;_I_wv0vz*ht^?#F; z`yQ#dPiby}UuhiY>uxG6pL0kpGu?QX+)86bSaF=sRt(EN2(hJVCu!8%>~_aRA-z|{ zFx%u{K$|hgG5Q)w`X%Rp&$ig#+aoKNJiMVeckab@N3Sc#qud^HT>;Pxq+(csz?M$w?0Vv7XOf6g18JPkGSq z69$hTkxX384D|Dh@?aT!R*4GE?uaYHQAA)-sMQ<64Saj+!8ko!doUUZ zf-9o%a)`BBeJez+X{%VNobk?St;foNV{^kJbmyFWV&MQ)P6ZR#@}52Zv;^1R4mB>@ zB|99L=l4B^g(ExXiZTRr4g|-WkbB_Gxy6_n^SdW5Ettg>U09nz;#X# zBpF2f5=+MTqS|8lS`M{nT!vlojR#XsgyM=b7wGgUU2L@lz0~A1sPRB!hIrQSuaj(C zQy9>Xere2gva_}-OLn=RF40=>48i&i3&(h^U1wIH(kj5uvtW0l1wQ2Ww|{*!nXBmv z;FV5ZP*q>N|ENFfvJoKXfm{%@czF8P!aOfCTTl0pnUk#^m4rFt!@No?Vg>ue6q6z6 zzvz#)x{EOrc_&7QSpl2idf6n+x2LFy-gIBzrDvFvC+oRX?I&hJ^ynPNb}oL(y-ijfyr>)on5vy~<02PAnYKaRts zV72fG%;$SoBsJAM--Ri<*lL$=^|$yh53xtj1tefLzn7;};TTGYwKG=+D=2+YTAne# zd{tfRIw|M$6@J=N&1pa@y(}1FcTPlGJpL`<-B(4gIp_S@Ic)AQAJU{(XHBcAB=%8E zHjr>qL<_DGgYq&_Id|vt;L@^ezsvF9!SsyiMNi0)T;fmIax1^AYP%yXc(C05;(U5? ze0X*l26_K|1Y_peNsrDAbin|ANI{Ih-fw%9FD(GNJxC-PyD-P1gnGNHPzjB@M0NC^bGKpvYyCFPya@} zPB7KJeF~s)GS&ofDjplPkPPvxF zKgFYpFBm;yt8Nh!6N|S*98Ztgy%uhUR5IYbA{~9FSQvv(UL<+Ors5IX@;7(aH6})B z#rbBYn*xtlg;o)Ot#NAAxYXd`Y1+N>;(>`_f(6TLCk52VX zUD+sdYDKf|rAPRMnk1LXpLeohErqc&Ze*u$WurL>RDgT%+U{lBK9?QyH{P4sjAyKj zlxz&;nV`A8piUQ0&h4uu2S)l^%>&Q0wvhw-={q_W=Qj64Fj4pEbyP8Jkn8J1WBVhc zcC+Pc4^O7_CI!)G23Q^Jn1eCsu)S<>el8ypGE?Zv%ON97Dmq@}NXPTcbgwCQaGl)) z{wue186YI{BjXM%CtCB%j{aWr!h3uPYLathlhmtkBi8^aDd7IB@oE>qogffM+z=05 z3(#96A|k?wwkWS~mqdhr9qX)&q!Wfce*td=^d~rRXLEmH;yfBA05VANR z?axglZJjwAw~}zwc&xAYSm2y_FxAj`1@qX@1ozp6q9~M@d8969_1^Cod!@iW zVbjSlqsOMlVu#t?w#lc8PzN}JU0#zlM0DDpzn>l1zyDr_MvV{8!py(^jgGe)C_GY> zIL1nQcZZhl>h(&ucX!C3=aVR8@d5c71l=X{1GXQWP@N|I)MGmv0C;f!M9;`8D3q*R z^jO=AwP4lO)Lhz-TkBe8bolTUncN?k;8m067uSBH(3&czir@CFV&x;eC)w=7{WN0WsMg5rG>hn|)=WPu)Um~aRa;DYyde}D6FJEhMPRvl9 zNJR}HqN-EntoL$cF#8IqGEsT@J>>pW0YxYh%9`&UO*8yG0^fmL1pXXh`g+q_Qhi?K za~6_N5D6?nyWykDKt6vM8i%1bFin_|l7{Y#!)K**5?Sxkc63TL(qtDkpBAbmhZZJjVvpI3HryP9Mk@fd-KKmsaSi}pBnwSCShjAwLG+%CbDG7 zwf^A>oTEeIf$;W!4wLSI6gBb<7@A{!e?~17 zk{3{!5s^|?h~z%GXudd#xm4-A4)W`4=@~GUekpZ5bmFQpcaxvo_GD*KnF_Jjr zS4${?R322N5afa;SGq0F#8+aju6+|ji|K)C1sFJ2CLqH*yN68iy(APkJ4~nCeT&HY zeobQ+F%KB4Qj&>5d;bZ3`0!98)q}!3BjOmv+VR|3 zevv};MxpGuZx+8%$|R4c5+m`FEO=>3D!51V%W4yNjZ{VGxNlv(*++yYeJ6y< z7HKivI^1BzJ#6a}$R`Z2I8|m9OLKo-IGeWwxrhH%s+>d!Lj2)!;)EJMW%6D%rm4Yk zI>f1tF0g<1oXV>YY_WQtVzxJL48B(Dw({7!4KGM$k55%eODio^#PG~9NE4C1J19`f zd1`b#pMei$5r|;Jy}pMUUAnX;gT62;P=E=V?CsUtxl2{bOxiW@ z6;>x;;G0tSZzde!PE0ajJ+TeOfAytNImKDDwBne|=-q35(P9}B72jAcHOSIFuA5+; z61lHGWj69&J4i6L-z>lk|LD)Q;ukR5KRgo2%rV{lB_U7Jz2G{ELD;=|3ps-&Vvcm8 zE58`|zC_P=(19@c*J|eOGMRzDd+&o)Tj!W5*T6R$9)5ro*$>|l9gV(NUGs#Yi7?hh zid^z5R}z);TAho|aHwD{y|8e$EE3jovZJn5SC&%}3qh5WGZYE z^T15N|H{$}IXpVWpADZaJNd8BtjKaWw8}j6yH!+ z4w#`l5X6hO(}N&3;`6_5Ty8UEudkO_ok2}P)bO3TkEUQ@5ape8QaGE(+Wi3%XMylV;80_d@$`omMqJ<#J{7@`r#*K1ps#!BrB!{RU!>Dq^`#vqK`KkOHp*q>na zcbR(#K5o5*KTFp(ds#mHAoq87ej$bAdZW&6n2!pSHI28LSk|UXxuxb=U%m|V=s%LB z>TkL3oC~%F^4C9V;N~_LhX>swYxmCb?jAeer36yBNEzFh{>@Cb|2p8`8cH4$K9!r5 zRxPn&hrgtP)f=tE{p%(Xp=3&`>|%l?%UHK$xC2G$;-Bl-WY$~s#ok|3L>UsMGTEJ}a+;49DBStL`i zOz-&0fl96H0%{J|RIjRB2ELSEgaWTN>GncDp47)^@`xW3V>^8tTp>~=rEA;iO1|1r zKc;q7z7F2z*b$zj%lo5ySOX867>Z&uk5r_mfR~YhBy68qCP#9>9Mz@vilMi1-H&7< zWVrhWAp3ESPl^2{mkne~pEjhI2rjR$?cY7cqZfZ%Xorg*7LV?1XDUj|`(?$35mJGg z_)M#e9P=~KQxq01Hb0W)c}I4_e-0%{99E?SULe{<7@rKymO>0RfRON$|Mql|xkTPy zOJ1pnsaOlq=ss?V|a(nWE6e^nJaYdfz^LXdiC2ywj*~d;j?4eWQCPSBXukclh}E{|_R% zt*|un&~TYTm^|TS#Yv&OU<~>rVgYqm^VQsHFWduilo7SyJ`=PtBNf9Zh zg*l|Yw)j_yAvPcIm|1JP$1FXF&x3W(vvk!3cJ|@pA7RL-)w1A{d-K# z9MZ8fxn!Q09qx0abod12qtny6gAV<{0^pxkkSp=0CW*qDFdMty`s=_5D#?m4;gs9! zE=9C!${QI~%+qV&FEDRX7dT=|Frk7-vJ-5O6;5jEX=hRRio z!M`25X&#zQwc8w)Q|Spse-9x6i~xY=H;o$tSS|3di`VnOxY@*ph8{U-Zf?bOL7Ddu zc7SbCz5CV6-Y9kNk`1y1UJVGL`Gm8irZLmh$V%T70RBU09s8{0*cnl9iMR7OsC4E_ z6@bNBTI_TXp|UGp&@PTJyrZW&Ke@~JrT2%5l98FYG9wcYPs2F7{d?wrfz|Hax{M&;3L zX`pX#3+@`+-8~RogFA%a?ykXIgS)%C6A13^?!n#RcD{4Y+?ly+{@q%=V7&`yx~i+Y zYVZBXzO0keEr2$d<)y83V{`mGd+k4|JZ2e*F>J4>^qo{GQ=1nD-FvrxOCO3LMA z=T+mI5Ria}rsA$p-^_Ug?-$%1Xw^_EkS8_R<#A?J%e^|c(j@FTb}0@Yt;!pCntNQk ze%+&a07nc?MpZ=8{ehgu`laE2E)H`%@fn+p)6XU!(&|g(5lliCLMp47+2GE-%nl*iL1P=I-JDgA;e1B^SO)g*=eD+_@>Q(63)v6y zsx$2~z9qD(5lw0(O|f&=3C@ipnU^TS8f~pCF2vdbQ&$^_Ajp_y$>)U=pF@VbUhhW(p{pnj6JZP!W}ReDDNf)ri0c}2V(RxE=AoFuPrrrBfgS{I z(zv$<3}q}77%hax8wzH`J(7^gA`SLBZ&p=Z_Vi2*=d*db+&a6oA-n2wT~Xp?f-}i9 zqu07R()jp{JHzxYV?rn{4Hi(reGLI^dO)-F@B^r`Ap8Tdh=Q`cy*&WS0APLSMUzVF zmEfmi%PLpR5E=)Zy~-;Rtq2-oXBHfhk4-C4H@OyAXP$R=rLTn1G_ukRQ%5ZMSt*T{ z`lCbs`bCK!hm_=+x!0QAhq(XNf^TZR1hJ0eHxqW4OnVj)nglW1FapKkG^s&s=Ocsg zV8(}M?k;z<(Xil=Rre|{Rce!Yhvr~0_uoq)I`O$#31aUyQ7We;e#xmjA+R0N_o9U; zmd8TgmF|uO3{NlOw5#qFVP(oSL^xb>{70jmGt&H77-9m;e`xSJ#(ge_n#?m^v2NJ& z;aK(h`J~(ce)q>fQ$g*8Dt#F)$lWA-*yM?p_~$Ij58hf#3Eo=YpR7KJg1W$EnmSSn zJcN*Z(c8UWasL(wFHBmn11?E3@lO-xGFZT1V4=#iu3U zt_C2{cXY_3M1LEFgriUKUsdzx|)I+$I!!Ab#}r=if79 zOKoUqFnk9S9u!%DA^xe9tfsDdh0$_3qqL3+qhE`gI_v~L0n~&Qd@OVt>Eg+&viI${ zl0?vfy70@0*vL)d-@-7{|5+F=MM@(Lud5xA2%v5?+s%JUzr}I+N!(<@Az3dhqQ1zoU*wCnI4roLhy$qNK2hsydhv5a zF*z?3U{x(3yO{;Mz~lZ?6&|AayYiYq|vrDHDxe|&GMC4Qx@-VzODxb!ns>&<9NhAGT3j66!*H|0ldqyl` z-3$|UME~z9Z&6S%$Izd{(oHJP^X=Npdg(t_K~>oNZi*|D4VU+b)-e0GWB*!l)$N zv`1r;a3{&O^U0zwgfSX`Xch&A&Q65(VaS>QcBZIAI}P zQZRmWyV-QNj1ILhrj^riNy?uBJoKEjQS3yWE{FZM?){K14B1CL*&j{Um0)=E;FOqjhLwS12HlM_v<-8(GC%EIEf z(UL3g8C3h@HRfo914$8+*wC8Oj`;)VLEiKx+x0*9y0a$y*VO4#SdZRnkT?6@=8i9?JGWR5C@3Jq+}oLpn@w=CO7cQMdEb zmPU6o+gtHfqXDg7QMfh%VS26wdXX^s$1Sf>6M`_rB3|vgE)u>>g*i1JJ`#&8IA=Hw zIwhj37$iUAd+$0lJI55x+;pJK;EA#0)bQE|{1pD(_b3Uzf(%Z{+ z?BqRquc>1O@YJ43lOA=(zl*$l z#gnI8XIcC^k*PW;+If)~{cXp=oD6y`*XEUpWg8p%3T;m%zQO-5+69!#*8K*Yxz=tC zK*Du&E%{TFH2k5uzqd;5Bo`hGv8o-}+f7nIjZ9dj+C)s+O)y^HI5!}kdC8rU5hH59 zrzy%$AE=^pOLE=0Sk--!Vfq*L&NmCH^pk0JZf<)-ZhJY4ctt_S^NW%shT-_q6unF^ z{uo(l9<1Ws?Mwq<*SDC`h+NNCL2}uwkpxH~aBkJ>yhrx9p&K23u8ai%EM+fB0lo*y z$(eCsEdX1&GHf=u9S>`yT){$>D%W*a^T(5s#3+rnXdsFWmH4+$^KZ>1uZ=dwmB{P! z(T1;tjwj%Arpt^C@e1GToW}6mlXSdk>2le=Tg)kVZB7X*mVOp(6zYC=y+yY$UNLc= zyq>sqVxS21qYKWP?wKC<8qLiXCkhc<6APW4`S8V~o^|1;+VoA!XkZ#92&*?5Jl>!# zQAY%(;@t6bR3%9EFDemeY`(@!dr!~NSyy$L1bBg2X)NXzxj_qw1pIn*sotM}SD^4J z7B6M_*zJ0Y+t^Wh^kX2=HT(wAjbTaT+r7@#z)Mf`V@mMT5ZnGx2#hUW^pzL!MJ^OrTK6B{ElTnhrVt4Y@m2Zu*jzGnIE&0B7i6P8gR6rF)26kohag){5+AUZ1Vz0K7D z;at8^E>(Zx(g5ndo?SWM660^O@L%mgrFayf?INbk!k8`^xp38LtdiL%ZQwD2petCw z;oTGZ(RhSh(Ry{5rfgfnvu$|XHWqH{_}Ok+YLMaSvDW3Mrjv?48`rNXQ9MHc+n%#L8b;jKv`PW z31QS&cSjPVxC)SwWaG*zEmI$B+&R;#;uWZpszHro!&WFZFaAz0+DDd54FWlS{r5}b zV#ePBX~oCO44UGLoTSDNjpqwS)v|eG1h)bXdhF@pP<2!JvMX9cLcA$TZPy=pm43PF zSTPb+^M|?@TV5!IxrJBcA=b>^kHrSPNf6Pi+9MvHdznR$8~PW~MNwe}j=AYX3Mxw0 zP@#FqAJU&67Te8qS=p^m|CCKPFKW&Kr6!C*DqYvN~SYWoAfZl(&Hq=Dq=KL{1fkv~R^PhFO6BgB%G zTd;4Q5Kn8Z`@+UL?&O>}3=_$8wHt3U=QouI@aWb|lN*PZ{@NoVpzNI!5`K&nr7y&p zOe0Z+qxz5qI5u|Zfr%LmGyQoIWUBZDPhoXlV=S({q0%T5Dk&ihSVX-{1lnZ1oRw)NgU%oC1p!wE^)r`AFEtG(koBg|4T8&MDL2E) zOgKzpVqo39;5&mehSMhx|9Ti=5(jztF@Bg{TMDg}+>t|{sBueKi`2#bPqlY<^GjOS zD*aaPD>I~j`t<8FnOvBrSN=8N>ESBi7yZM`z|55dx5D-Z$#!JDg3BVTNv&?>W8$6{&*oA6#cS zryeO)f~Wmy8I=eDG5;e;Lk~TFk%oeSVPs%1V_FYTXaV=`uUNjwQUEpe@09WJ3(uL- zK=`k$2|PMg*!HC>z|w#a0zAExN&nBJNqx;ZOeEyLBb^vyHnN1`W-c=kpf{sH`iFbH zAF#Vk13>8=9!UchJx5IoO6M;G4Q1(iQ>NK4R6^4^r)pAE0munht^5zCP28x#>)!K$ z&&rwdPZK8|S*ecBGx`RX(2Yxwo&8ik} zW03|T?pgWRSlBwN*;@+q-K5i)R zRu!$Au~jGfbQ=U!!Af!8B%Ke(FV#2h6gio2V&5BZMTOrpf71klV#2A^DCEi$HmmDK zD=k$74zw-cQ41!DY_YqNm|U8(F7N+6tpydJz5aS1<@Es(K_sDnfTEWVSQbTujL&TK z?^lx+=s3yVf2}4i?~syL$n1zh)m!W5R}Ft}AsBs!^~?~|a(jz+ew;Z$zPS!xE5gxO zYC0DzfArr6CKM=uFL6+Q>wET;DWD4qa82HGaG5j)hLm`R(AN;V-X&}9BkWY;jvfIIf9=SI^KYL8Xet;O2|wo?HF*%zeV$bM zkQgxl2w>XXWDF`c8A$Kj-TE5||LHg?FVD||;9qS53JZ>^Y(%3dH+M>_SYl7^Vo$B# zz5!R&?Xqv-vxk6y03c><+hHr=+zPcn7hS5R?ngq++ZkdxdV1CpAWx>OXc@ zOO}BWR(7+KBo`i?s6w5AfC){``IH{@ITnH%usEN>VW))PWN0ki#!eTz#`DLMX}xl- zAdO7J@}T;5Q_n1w=z`Ulu-}hz0qNL3!P5Cu0tY;~7)|TgRqvA3CK5ieRR3Dk>vI^n1(emaHKr=wrhZ4vH_q2$ ztDv+@o9t`93+(uieLokDx%4C8 zuVr6GCSX+hPj6l7I5}shrkQJQlkrluLy?6;Tswv|MjVFDjxyKM@hyvj6GEa3`CY$U zfVo(J%hJy<>_m4`xjV5`Hzi~i7N(5cOxFKt0zmFX!QiV_GL8*SGM4;U>CzP)T%U@q$NlzL?9#Ut z*+Wn&B$?p@tV{2V3YPi)V zi(svLD%&ly^9F<(t5c(2ZRY6(JyKX%53OEC@@!vB?>@FuiZ?@^JBn&X=&D};#_8gh zafwU~QaJ%(@&W$EyX$Cc{Hd16z?2-JH0~xc`QNBIjF(qkLT({gWmXC9XB8Y@S-jfn z6pLi3H(cAvYIO$N@o1qnj;ZP}=45q>@O=~*O4dTvR@Ufcv>r2tC-_)Krvd(J`}32D z-=DibY({;}0&#|u{BYvx` zw~ta(?a@VclcB@SDjTn5sSbOM?)G;0T-w7^Sl9WcK!v>7Qqk{)p$g5^9__!|*iDb= z^o7*_mK~^Iqc?UYWE}X$j!V^At~sw$c2&O8^*gfPdgW=*=dmkv!LL`x>p*7vt>HMd z*pK&rhwcw468P#;)R+%nfW2|oO-vbUw>l#62idZL+!-x=O)Au*BrL=%7CZSgygE7n z8T~stN+t`%*{cZZV@}uu{P(;yeg~V$OWrbB0nu?gqT{uyx|NqTW;`ds0J$?>m%hDB zacF7-L*vQCUui~I5d1tgdFu8)@e_v%#~Zl7UC#UMo_Zq(BdI$v4unEyxs4*snx1{*WJ0;?BX{Cm-(EaUBpJ)sEtRj z$`{20%S)GJvaH9>cZk-`7f(OApe@Bcgg4QY9mrl11(A=zNG}&YIBJ})U%%rl8E9zX zrl4(~cjkJ|Fa5TNI%y)_Sqp-~ro_kVCf2jOO|c(1n+@0M(6Bq^^DsjFl6C-tLfTbY z?UzI;cRj8X<)ZvcN=Z>b`biX7hf%8brHUR&)*)ZMP4-vL5gM4Rtw?@4cgp4_o~7_} zqbzl;jvoc0V7K;rm&+RkKpAo-;<9WIUDbpxOm;5PfC%V-+tkTg{9gNVluw_5< zSa90n)|4UBpDA#P1+z!`+n_Pk)>c#x&r5ZxBG8Lp+^RZMYYC7C4B@Cdhw8$ev^SEI zQ2Y~enF!ruFD5rPWRaSgW*$5?opy7Z8y?OmXY>73bO~RTPbJjvYyy=$YXkjw7SdEuQWDykvvzWDnskz3 z1(Xns_`e0j*VG~ejo{p8?by6N$;s%e-2Yr(H_=r4s2{B(%$9na47pzM^N^*LAKFFf zE&Kd7si*`jWA6KA%((J)9Vdjah}2<@$3E+Pbc2G?ry%#D?j^4<#?0udE?tf9^^AeP zk`Y?7Kasx~sh0RMR4r6?puiIcm>U0RS{KxvC!GJvh7%#y>jr6~o8MX0y?aa0+NgvU z1vPAg5BIj)U>+G93Kn%pGq0;lfL_)Q>sY41$`_&Th!HH*fxx0$0EbMn@#?`OY|!)6 zEte{zJwED@*fc%o;6jU%;(dD+K5qc#am-|zj`(3_4ZYepwaWC7z2WPbphaUIToiJl z>Aa#=52N3qJ3GaD*@!>h$J^5vlHFNaFyigL5+&+N0spQBUKx?L?CJN6t^zj8#OOf2 z{>c*_6UCy4aI7qNvidf%$9ezYri3pcg$q*(j5<_AQ&wUVw`bq72fMLT8NB^93n`Vy z;N-@) za1Z=qI|=z3fRM)by!ReYJ)-6|kp&s#O~aXfSIxhGwZe*XB{h6CTKZ2J!aDIn6nm*2K#MH}4J(HtFgo|TqwzlT?Dd*VqZHQSN_PXzwER*eemlySEMD6}f z)+5!A|3mfhy>OV|OJ}xk7_=X=$EoP7CJ#3e>%)0mKL=-of8qrOEY>MC(wQGR{bzo!P)7ltHC(q0jm8bhNkNkGpE^fC?v z#}6uA2=+9%xVQ~%E{6LxIPs**_=5M%WrXmQ4v4OcLGy%<2GgPz5UGWYg%Q2YAr76m zPP~&4LHZ%N#r?T+)Cj`miQt$7_|-6W@Z0_-AG5fs0(Vjr{!}ZKkio=0_s_G{)s7{P zPd4s=(l43=4f47#*aIDikuzdX#SC!G4pgo$$6x8lV7fC_MNUPmA z=QV2k=pc=yC-*Evvb{4BjzyRhMr5$%?*G!(waRmTSSKuy>q<0p9-Qf+E<(IoeD2E; zYBJHjPa?9b4b!Tt$SPe}kTQJ?9W6}-q{V%B`10$}wy+@2RT^y+tkJyu3}w_aO_> zS($6U4Y)2ioM@ImZpK~*plI-~@cR_~n|i>o1Gxr($BN44@XpSv9{j}9+}z?3Ay}|F zlz0gY`$mSCxA^#&B7E8(!`w21#nO@D2DKSl6yap4jUy%YHv+@lqJ{69Z!%;QnqEEw zX&3D41Twddw=!*&o(nejPruBug$@5gZRA!bpt1aS4@gxm9!7uotLdqEAKfTr#mh}N zv8t&lDmLLiFWMbMF+cS@oSfnHAUR6wZ08r{=j*d?+lGCfhL_NuI2i2v+>)(dF}o<0 zis`lgp4Q)oEX+3Io3}#8h-htdyl6CQ)WV@TcW!2+eeiag$X4gIBDdxxtkG!fRG3@i zPPaPE$le`Mkv;4F2Hpwr7#V?%H?JnsK{oO(wikP}yEEo?E9EvwHE`b0483r>gmp5p zvR~S(T7&=GZMeRIzZabyajIEf9Ja zEg@Fmx^c1T*vQs>8FD7?SWeYsv~x$(0%pFrveB;XEIbP7Sx@!{`u#ydS8wy= z{;cZ8-J&wagu0C}`>dH)@o=pfASssp0SGG5y_u#L5{yj-4i66jArOwE0cOB&>=*JD zOD{RO#-ORpy-5}ZmlufI>?n!yyrxO28t|1sT8DB!srb)1b zro{juvi6;Y$&}@Pcs<#jUsM6SL#@ZjSWfq0C*|gMU?1XV7BE{DVGGJ~uLOEBt+Ee4oP z`YhE)Jsfur9Uw85$G%X`9RKdd;Leh#Uw)GL{pshEt&w?>we*hGIM>~$icN#974e*r zr{Q%TloWB2fMTRArHnNWqqg$4Ohx6Vt;ZJbLgqSc_X^Jk4Q)4C>-RnG$HKRl>fPK4 z(Ia^VYy36U5_cI<)^z8(`rOp3h&4h16X^iGFnNUUCDAQ63J(<*^E$CxkOO?j=W;Wv zrIIv7he4Cf3vTwihMEcATacmxem1Zr^_E_nizvvNi60^4b+WXvz9**%cVoTy74)O8 zxXB*czzUxHYZQRF;!Ct-Q!sVpScoq^Q97_luU|wtB|ou(P5&qIwkR!F*ghli6wl=1 z;i4vB*`G<+t7*qMPZQNu@O#G{${0!H9yG|-8ZC#9ISdYAjj$|F+8<<7TDAPV_> zt6xLBCiGX)`yY#v@wnK98l1+hmv!$HyaPfB41OL8hwbev87MizWjUoN;Pb8Viw!$W43 z^bK56xE1`W+E_fbxNuuKX?r!qoiFpATC7S+Bl^L050VzA=t;y?L706q3b9yp4J~}vUb=gpwBHmu_ zP}iDPN>lQu(K+pX0*rFY9hw<1zYyH%NzXJcm7-~_c&0;`s7#3^EiE?OKeLv)v#=;U zMIOTAt>v|nBHpxnrftElm2UYFTY}abXYmF`s#GW4GWqYssP8P5BmN)#7&Ir|mS5j| zX__4`Hm=URN%>yH8suPk@O7TE$s4 z({iI`J}@w|zQLW*iuY=oi%1eR{DDl)BaqTK(YBH5;)TdJ#`v6^Wb52n2es}BITX=L z`dmSa?YS)~q_K4kp0Q)>TH!iap|%f8+Qd;VOrWwFIf#$zct2IAcAr#@B(F`-Cn^!s zJmhiWbWJb6fn~g|Re|FCf}+R6kH*-9cn{C2eNR?(ahg#Oc7QkllQbW~KvOBWxUeT{ zd%>ztCiHzUG$~48ouc}AhH>w^YvTQorjmY^$4F|7y}%>g`HW8*t)O`jF+s1o;87wa z@W2A?vyw-RIj*_7q`uv&%bnr=(U;g8@6Ojb986L#f{iQz^v9ZU32lqR(xuh|Oe-(V zX96sZo1DM3I=d{6yrt~ z3ebkZx?&XU`3j$N9f7&R>A=!5R-m^>3R!k11|v0Us;t8#b5F+<7PE9ecVCAk)*ZP~ z_D?5hev^S=c%;S*IUh=u;0_dGy1Y~j<3m%*z_O$GW&ZSgUUJ8UN=lvEIZZErl&~~Y zg3MM*ki2W;arl>XSxTyzlrsw0#=wG4;Saj7!JCv;qssjmhlT5!GcjSNYaN#KWxkJz zOm??5bE?Q+zEWEqG}Jv8@rTh41W^1!+s;bE#C(wPS;`^zKl%Uu^mAgP28pY8kcPHaWWTGh$}5>#_TN=QN3* zN|sapvq+7~drOwvU?K<}2keJq8i2|zh5!m{kEELkNr?tmWRUgO7tCx_a#Q5)`S_sh z1u~*GCwO^LOkTNy272dhkBOBt2lJlPZ&~10tW=^bus<=9E`4d>Kry%un*~m2$3t*+ zW^*#2uYZ5k__oZFMonM&S;A0M{~86q&;H4Ie`?3d@!wU(sC+%xb~cbY}BwF7jQw@Q&<*FmqaQh~Qk` z5i1jmZdYxF&k9p$oqC0%nZCyzR5y+@^Ld@B4%eYiz3r;!+UMou6f6N@tu&Q;28x#bmgp)zi@X+Pk3S`rE!n~-E7hfRzO>)U6j-#)!BPrs3l}eV~((z zc6OMerl?Gjmm{a9X#g-u1q4#A_OE(nJ=tiCt9 zT~owUZ)$_bO5pQ4msfv%WFOtHfZO|MsS_tsXW%YM+I9a8!*7}vD7P5F<;!$cIJ+9n zZ1tndiE8$Ys4Y0lx@l0o?U%E{VhR8^w8Zf-*A=+4KVD3V)~_k|<>c~^V|^@qXAwP8KAuu^~pNEIjq>85AT z{kh`N82ZG***SqNgMnVLx9e*PzmVdF(>3?Pn6Jhik85W9gfRVav00c1Gf7dakwTW5 z(%KmY+3HKWCqvA@r65=sJtPJ;EUXZ+uYSh{PUK1997lkA=4|9 zj0o!I5FdPVpxJ3CPzW%Lw6qL6Krk(rTnv&}a%&5d<@501XQe^KBjORp zysH$Higx*NbH1UM-3F*xg?#ncxz3%Y1&-}&i)mWiwD;vym^PT7kbbqFW13`aBMDmt zSf2Jf9%ip~mC-N4taatT&56hs>>%S?nJZs!LCbCbS%-i~XmH}leh^{*&^^Y>_cP=Z z*Pa`a76a|p?wa=bViE~8!-~bEU{Y-=b{~MJIxWU2b!G>C_?QkI=D&po?g= zkd-Pft_8VZvMFM8V6Fh62+VF%&yGD8zUt0G4^p&W60e*?o z!zWBlGci% zT3?b(?)6^EO^ttTctzQ%%UUrlwPzI-5E{$Yr<24fI4*mf>y9?ef%DSUxri(D45O$x z-C$qct_Jyfr06ZJ7Eb@XF1!Cdy|xP7P%tTEBZCS3+&6r}u^QpAbw4wl=K5JCN>~k9 zTmk(9sAz4&_x?q0RSf|oH+4#?PqbW0e9(JDFLZ9fT>fTo*uRriu|}Z6{3A9SPAW{o zS}d`(GcL z18DUoB(hAtvluN-NSkPadw%GH_kbQcD|5Gjsu6#5grtEtY26?l48+EQQJn7TTjW%W zOm~G854vs6qfVjU?W&xdCy^TGYx9n{-U2wNIdB0<=V25Q1cQYE`eeMvp5po3o$fVN z8{Zx*(UW<1pN5T%5EKz1Ln)4fg9GJHOrq>R*cf%GSt+p@)=K+BC-!b%ng9w!Lr)qx z9F@LP;D3;yixfpO0NTtK(S08k!Vq_JbsNJ4UUi^YW_yilKXQC$v(egwMd?=zhHx#&m?(f-NnizBsuzxKY7l>?-`kg zwTk?|CfdE+cI|sZ0vR&-E;baR_b<0XJfh#w^2%leBfz_<{G|WLqMRB2K!eGYzBo#o zZDU*d@Te$~Ag}jm?BfNwO4C|I$kzb^AI!SS`!=skaCd5n5$1?=j`q{8o%v2XAgm4e zj`qa>~A2AkmQlCXjsQiC;G)wYa4t5?8A3;gdG-*(xrdY-#fL>to0lg=cZj zsu+6*#FY`LdJ<0J`ahIWj2=JPW9`F4Wcq%O7up=~Yny>6WLWK_mUS%Qpgpdh?BNlamHZwOJm zmRGLSw!`FHgTl?yRPUPDxwl;y14^sDt_4;?xY$S8Le6y-&OSf-M_fJrShth7B`g-` zEXhM0Nn5UBAixlLE*;0)0^>2Y3RXofG2eK*mYJpu)_0u6Ah-6@@BVMqbbOO%y}|~y zxv96yxeA%a5cr6cA`#B^V4htC`U9gx?kTAVwFDf;op0E6#u@Nv7$6W#zY<>q+Bu)v z?M1CM+E3a4U;!SUH(XPx(zA>Y%1e%(Gy`^b4FN5Bj%!=1Q$W>L>%R3942$JrwaqEw zX$nCG!wIF%QfbT2*Em3z?A%MQ!Q*FrS9s1GP42fk+Pif{a1u^~iEsWGu+947f@>)X z?cg&IfJSi#6WMcfs~QmLrNef8^!QxFE8r-^LZyy(~RP8nMpyXH}3P zEZ-A5$5ISS>6-9-Tj7>_XC$j*!wA;K z^#MF2G7_Vsr7#81cvezUDrWe*qJ9qG$9HgWfQ9(rPlV75sDjqkvLuc4F-5F^1p{>b zCLE450vw!@ygYD_sio!3s*5sXCKk+NI=)lhd%A zOSwOKJV+!Nb#!b@^k!%+MLjSe0H82<$_vtwl77kg3V2qecEt@DPTd9G6-(9ZE8fRe za}sE`xk`TYQ{y05&k7m{9VxpZ;L|Tn%HTl(`Oe&>9#_+EiCNmJrw%O~o#E4XfJJl(Iou5`+TD!^Z_K&;oa(bQCY&)RqaHIq}!xt zLjp>UNT&k>ePh+?i7&qa*lG&N1m1g02!} zm^ruc-*Z!x@qUTV*VEjt{4R{N%z$oI3Vy`Ep3^dUVDA>lw9_^pM_EWz0}3)>&Ws4o zt#?kr`6(Cy5yTY+mq*Y3#@-0iu8aEbwM(&><4)u9Nz}%sp*uxz{cC#3lSyMomlyOWkveLnzvPTh z<6l)pgcL5F-cy?K48iYZX9D0kJkL(Nlfc*cv<{dk=Az=fc()0lV{1}59X|2FefVb; zhPWaU|E?(Vn*Xi_`}I~sjn(+o$o!R-74k9fGy1@ZGl&9?mRGv`knJUlgJWyfm* z8;3FMv8tF)p(vkq!Yz)UsbL*Ie*@Ar>b+L|}w-Ru=UV4nDvkP0l;CA4!N-_8h^8Hu_{qH@( z-*0bnJXY!t)JXzwlPT;T9?#ZKv*eP0;>bRLvgsV<2UV(zc zx;$dnzEnFf@%yBm^3J?PDLMOq;AWb)IHSqOf$P1|Qw+Um-7`kSpJKrh9k|&p>-<9VhxnfPh`sR81 zu3q)@rDcDQfRKju#Fh9C@clTS?S3Zkm#96>ZVvQ0H6v@*HBhU>F1sVLC_M?7dmZB> zv-?H__qX30UtXUbXfwuc%xcNVOQW{BVd2NUcfq>7Yt|*aPeT0~ji~P8_nxlMgol}c z$d>RA9W5<61#nQ3=9L>TFA35F)ARL|Ru7TY7{8ys?-s8s$W|zXj?hvaB}ZxEJ~ejE zSlTyXNT!}Rch*}Ok|=_5a)3#%c1dG;yDJoA9wr5M^~bA%vWhGA>o5lMK2^A2`U-HsQW*9PMWY`i zNTW#_2`mi+Zt37VVx&BWoF;Nv?a6f7_V$Z>O_Fo-ef*bJ4AdeH#=>0-FHzB{k(kg( zlR|o~_z^VBoRi(jo~i;2J!x7gIc`ZRHy!%o2Tje(2DbYf?3(%FKT_B0L61^mj5pjd z%j2`-QhY9F89%|!><0VrbvYrBG2m#s+Dvzo>4|P${W1-AG50${Rs|AW8A%$&2B{Ef zyXq$OUpoDMX;pR6GYm=!bbY0@+hZ#7P5MY+_@HWE{&LoXlE>LGlj*ZPHE@!fizMHp z7LD%XzNHI`G|vqKamAU6ePxk6b%X&N{|Z#E^|Wk;X&?%IWV0d9Qodr^aalGSK6gnO z8SMeI-+8azzvN$9+BQ=Ih)dPqFn|MZbrwBmeR`Ki$AHAj4>2fz&k0W;#I$9-TQPIj zE7?aPN}f=|#bfa4H>9lOWZj7QZ3f#gJ~qDWIJjIyH+ix3LIUlt>*!wPP5L_CVS|k8 zQ1{$jFaSo8Vm686g+ISGHW8}H-!BnaxN7rKd7$?wS$lnMoncu}CTw7;CA;)oj*o^( ze0>JDQP-j&bSCEYe3wP23uf`plj%*}p1VLzp1Nb)imONlyM2Z5N{nX0d$iTcz1#=j z9QhP9mxf*9xDRH6>7piK6#TH?LnFmed`UTc&~^m79u-guj`nAY5Gjm1-8LHY8sF?} zMQU#Ue3?;>_v>A^YeoO8Of^5^PwO9hbkNHw$D%|jDK+@j$*Rz@qjo?=s9GiP_G+`V zZtx~1#t6|}3iZ39Bk6)~wU787kvc*85I6~$Ne5pu3&ib5_zgZcUkVK=VJY3d?r{@~ z!`Kp4*oJaf>5kTGEoy(uS zw!U;i>)z$W&ejlbSdZ>`ud;^h?)o@})>Tv(Wp%!4`S};_=IJ6*{OKqTLvR8gD8QOd z6L~P<*Jj`9UJ0T+ri=XOp5_L9a1FX+r#AfsgXYANQTm<7dMP0SFiq{I$t1d{pUNv^ zD(+yrIaOT`qK%IMmep!b0Y;h*65s%mSRJ`Fk5#v70Xh)FU_u(72DJdgfHGbD45KRf z`1nK>WoGP#V@Pj?O;YAknL5jYUH$9+|RGGcIqxw5a6KdokUaGi72xp zy-s{=x*gln88L3_WoOnD6br;LJS!{x^1SsnaynC~mjy2gBBQwSdO8)KMZfB3S(2B! zGkUw#gyjpAChB3KrJ;*X(Nq^iEYjyYK*e6~NSoBzAE5i@fJk43ms)jfHOIlpMy{}wbb-Z*PwJd;)(wLF`;HDPH1f$mmb zGp`MvA$}WU8Vjh4xA0lG8FEu_3D?B7$$6BS$sx&my}vod@M7HM|6N}m8^BeK%7p%C z5Ywtci3!LJ(b+szrpPPZRU|i|iWRy)5JkqMxI8~e7uH54Dvwa*zo=d`Kxv(a8nmyu z`ydKFx0ld<5DC~eUiJA|baZG;yu{2!Vz>ge@lFOG>g+9vcy_lf$t*v@ycOp#V?elX z7L{hm0Bf-*&*bj~dqvn)G`aQF(_6vL+H=v~;tf-IK7NuH7mug_%S7+mIP=BinbmlL zM$1#C^7<$^8f|@Dj~=Zxo0}^rFIpY%lBc8j<=THNwFcgpNOA}6R=$44&MEfCZcGI% zwatufMn)-^y>JotX+^RvO-VJ?`z>+VPYgmWJ?0MwYg2n3rIZ^F>1yh6j~vEXX`NhP zBN$iwFGY+o7Cv2hpgd63UW{PV9ysIi?_K7Vi!z4xPWF%>;8>{LSDhDHK?<8Mi6IniI0q(LleW-7TatgBKz!T${5n}O7ZTTP{Gn7q*-!! z99KsNTlO*G_v&9q=BaAhr;iR6>=ZrYGkJHGBFTlkqdZ%eyXrqVT2Fr@f`kBdj|k9H zjT90g(Jw0SpK4U<*-%^SSpN~1D;f{H7K;fc+)Mo=vqE&&CLej`@n`NM)?844PJ9OH zVi4il={)3bx1;J_`SM5vsNR{G>yxFrF%xuKuJocJO8;MnH2BAFx!!+hQw4YG_jNnk zreTmkpA!Zic}f7;T-?Sl*hTBcwxGbt5j(%Pby}BUO81zwOuZIz0fyOtMY{k|0$zu> zAZ!pwpHin|itB9>3|^EEv=5)i3q976+T4eafe$2>$s?alRDIm|VqEOmbP~;&CS>Jt zp>GDF&pHm~#1SX=J35hdS==Y!v|6!29b#3ygLV$rn zJnf{6UDp^lgpFtG90>XDHaODec_-k#Tf!^_fx|iR!NVC!aFNL{qFmxbK=8IoqACbZ zrKGL*xAA+uoC(dPAug|R1evKN`gwGbn)9V!gZgE1_*R%7pxc+<(E`?4{=rm z|LfA-n-L2!AK3OlW)SZKEFuudhHGtOMI9D0yX)RCe(hi#{R*ngQSf_i-~^b3C_3nK z9g$h}r(IcMo9du|*gC9t7y2TjPH}o`!7BCXG?LLSP0F;{zL^R4XYw%?;v7&6G=l~+ zjj5esn2(PeNv2X_?3F;YbuLAjxh0r1#@}s#NH(pO5hKP2o=owB!azuY8NEB_p>I5J zpszr61j08B)0?mHej3SPG~p|V%3rOL5bF>tw%x7U_b$T^Sr8Kh@=H07+foKBB8el@ zn7#YTS!>?FgQPk5kzi>Z7TJFUInsY|c%SyUGuA^RM+em%W$v$h(Z#y3RB2mjQGaB> z7Z&~ix1Lbb~`;ZFOM_336b$Xp+=kJc1O>Ise?7%iJ z94s;bJD~7zX%P|N0qN@#1(?lvKVbY{&It%t+J}E28xFlt1P>1neex6siyAZ52Z5B0 zP9Xd<)Xsm(IZJlf%a0%Vp?vVY!(zw*5{WN%pr+jRu+`{aL@S#KD#deEBiz0uT*e?! zsl;|Lc}VCEh9sP+gIgF%izOx!sJywln8rEQ34f#XS1Bp({G2{n4$7O6zuMp3%1hI) zSZG%(+|349kgCR?0`^XLN(MDA4|4=WQBcx~wE|qPtF~`$#kJMXGfeEdb+Bl=KjElf zR9|*#L#_@lOhrW`0_5O&A`!+EQtYIadKSic@!ngE6I1A>`4C{`zS?%O$smHV|FHBK z&rHYQk>?eCMN#;F=z0sNNS0<>xN&zF90qq7++pwm26uP2!QC0$-QC>=cXxMpcXwXT zIrn@2ee2#o7HiQBUD=gYnUxtkcI*I!M)*xFk1k*-4#cr8n?Osyf7!}XP?is&yctCB zBNIa(3f&U7_%0sA8&%OzlUdP_qA(tSQCUPDxZ{VK8%VypN-UJ1Ud|ER6u_a&xGX3p z?}(|zS|kQ6i`f@Q_=3Kl2MzdcxM%d-4I>Q7@1k&U??V@4(>C%v(!2fLlT*W46O3Qk z_k%lBJz1kqg7@15Wp#f}%qYH^|28Bohikc+%9f>jC#YX$#%t|44IXPw4$RGBDwbk_ zs(s1pkEOK8^WC%tt#}>U!jg)$94mV`J6Kh!*1$*39&i0$xJ_$}IyKg>0>f6uh9x;2 z7qQaa&Q9>SA9rI$mG(nN6O%-~O!a+27gL?pEu9odz=+W4lv?#SKq^zEwN~Tj%IH}Y z4<2F}gTXQ9yaDl>|Ais8$)EovL^a=G-+ljO3*=b5@;BLd84Y#Z^wigDEtnH^^Cs&w zEb#v0d$`ivoE$wXE34Ze>%@#EP$4z77WYiKeMYqKMy>XHH6lLIVXE3q_Vc=mmhB%B zutpFfc-cWG1qJYzPa-<)&d2UqZXiZRk|2o2efU3mPq^v z!cBnhE|eL1PNm#=#HdNw8h^N70pEUJsllXQROe8)<`QeuF*jIVM=5QzK4s^8`gN0n zE5gL#Raw}Swb8st%rNbOpaQ<`+@RZb$wz+|Kr1)mB@mmAFDXxE5aG$*Kz%p!2t9M?F_0lhxMC_CF?@Hedo500dsYZxzFr zF8N?TT0hBh%~Rx7)_qc$cz4lC@*W=Y*@pxw?V&UA(1IK@dJkyP8;C!0tzv>VShc`r zJd@Q$FP3!A_Eo%P<$LbM#b~5Ej`=R3@mooSnX-)+Ev|13JuXfNk2cHHC7dO~=e}SP z2d%Gk&M7WBxK9j>@^M{m5N01r8D`t98#$9w!BwpI;io z1al*t7$srUyq-V|+Uh!rEy|$_Ck*V(pD7{-OPGFOjuM@%ACl-36grZe{qbZrWbXih<_InLtx

        )uzx+?fn63*4iN#4agNlq5E=i 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 literal 125778 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π->UQy5*FT0UDomRL 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 KMNUMnLSTYCBgfGI diff --git a/assets/celery owkin scheduler.png b/assets/celery owkin scheduler.png index 0bf3a6583eaa90ea78dc2dd6d1d4768bfd044adc..99463720070e2046090186fd73dc25f8467cb047 100644 GIT binary patch literal 150344 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�~48niYpZi%9Z4Ef$Co&-RQ%3ReleATg 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

        sWHu67-CpxU- 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≥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

        M-G#-`F;HWE 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 QU;s%@N>Q@#m7)KC0Wycn{r~^~ literal 124557 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

        Ao)<1(f<2M; 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

        >mCyS@RVpsFVkRhtchA+ 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 J^j`bx{|8p|d>{Y- literal 116996 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 diff --git a/assets/database_owkin.png b/assets/database_owkin.png index 0a13310622ce7140cae6f870a3ce3cfdcaadcce5..b4c1718ac00fd0dd77bab8ff1d4eac518277f364 100644 GIT binary patch literal 82742 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%0DBss)@+0&q!w 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

        }1ux*gneX;Z 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ⅈ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 literal 79770 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 diff --git a/assets/django_enabled.png b/assets/django_enabled.png index f424843836624d633986c5419280a53f1d0333bc..3a955f3cdac270f66bcd488bb6fa163c90af2c44 100644 GIT binary patch literal 85059 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�=$x0Q52an$m0rA82UY6%0^S?}CNH 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 A=Kufz diff --git a/assets/multirun.png b/assets/multirun.png index 4b9d56b92a8d1d2276219e06df7cae99edee43db..4b514ec83872694289cdce4c7fcc4ad28c8faee6 100644 GIT binary patch literal 74705 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 b^7lWS;V&+}QSHn!<^USh)Y7EP$RqmS+NdyY literal 79198 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

        !+!hn#(3=ty6VsH-KtsBJb={3# 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 Dh6`VV diff --git a/assets/server_chunantes.png b/assets/server_chunantes.png index 6068e04baccb8c10dbd3caa62ed77d676eb7125f..53909a785b54d40a87e9435e48572d60fc6b05f0 100644 GIT binary patch literal 149179 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∾stN zc}7l7&cuO&GIU^Mgo=#~BdGIpr;%s{45(!AX%jw+Pe@3Bte2KDB{J(u>*#cTY54tH zw5z*Y5mEbtq~vQ;XgR@=P zzdn?00Ou-|NP7t!uu&OoWu3rWIi?cOxLqtm3BuaaKa|vyys7(CorHB;<|Mppt?Iv)Xfzg%VTQmdq3F)s9eCxkRN<{m@9|T?5n7RK`eId7ZYp8z{t6+h;J}A4N^(d0 zf-ZN3t)9UyZZ@YA7i8|GhTeH;a!Q&&W*5a5fy4p7x;RdR*q_`aX%I&N@@UTib_s!~*lw4>*VjCKMHz7<1o3%D+2# zpzC^`_LZyQlUvL;xAk6-_%exe zkFSBncQKDP#?O_l7=z4L!pmP{NfdBWn`4^Bz_)XyKXPaLT6pT)y^^-%GgPpp{yAE+ zNr&rT>dnIy_;{^4OCssf>YbH6&sYxV1H;T(K{Wq0%aT}UJ5UOUPO`ZYbvOf_fJ4|C z&!U{HVGvXDJS_uXb^@s5lFe{k2UAQ?u!*` zA_oxD#Lz>wJ~r1Tb8)hU;n-UZ+E_|3v#GaMrX>0hwba?S0)4A|0bCf5phzj|P>p;1 ziyx9QnY+kF`IEHNxX-EHFzfmDBW^6sGIA`yk|kRmG9a;xdi!Efiqh3&o84+<;0_~i z)sb2HH}mw`#)OK`4e{KB*rn+&i?j!$z9v6D&^2n7hE&A9kQ`2?@1M&;_P3VIh#B_p znQ_W+RiVFyEn}SW3nNb!hvhVq&bz6cvoO2fVWn4Al^!>J)9ejOi8CslWhOX4yXuCj zn{sifLfiBhCGN|8JF&yEi1dyFvDu{^=b1ngknDA;*uw7Ue)N_?Dd#MqdRMpfD?;7Y zU-Q33Koocm+rnNY8)!|R9=4mJANPlfPY*W)4see+Xaw`k>B9n<4& zN3e{3$=2C%o}#xRd4+VT(d13ZUPy8#tTf%fqQC11QvM){s}fta|KiFyJwgt)Q9Y8d zDh;o#5g8`w_Vid}Tl8SYZ!2COX0AjwNf)F_+bK|#3*Q;S6>Mk}^Wd!7P0-DGsiX7( z0GYSgvt1z3Aj=P*TJ5k!JI5M`%lRMHCza6eyj8eB*R0z9Ii+lp(BB&Z3B}rN=Y`13 zGHulIF973bTES%SIBUPVjGxHA=-{XTNsZGaO&U;~!~>`Tu=h+{_7XWdO80geDwc8R8F=%!=^+$BlM&m%aJ3Cg$cr ziU#^PwK}K>L0^u$4^BbqYKkPTo@pI8!sKFFP=djo=Js2Ii0vHm&jmY?#G&DoYil>e z5lzy~*PpiZ{gAGQDGnDtZB1<+qRIddmv@dD#GysAIZ`oeMhDJt0vV?_PlTwc>CiK) z!qCT7wmvPWd}9&BnwuL=YvH^y+^e!c7*DQ=&V}XjVLom{50xL7n_u5;?Dw=fqTCVw-P{v+ZQ6L;H;tPQuJ|Kqb%6NRj4G;7C;-F=Lj|%Q`_mPilC- zE2){!7Pkj-_?ADLv8-aso{(kf8Tb<2_VuXw>ERR7@!tI!q@pfaxLV>4@FOe{mo=HiD=YUUG|bG$^Usrk7LQRt}(zmo*Tg=pl)r38FrWei$j zZ#uqo{2qt2jdEH{KbZFmw?G#=%i7{WWiq)`;)Vx)S-YyPSDH-TB~|W}ONE;{#mvr` zb+Z&05zXrgwYPjsX1wrDis@^kz#-;wJ)L5{noOF658brCYI8>}Z(p;5=I`ubRVl5i()b`NH{_2(_MS1G$dgz&SlUk`wB2n{&zD zALqiA`5JN2X=mF&N&4tb>4u*#ss-mmT1iVEe;7u^YbD8a3YJkg{DBXVJ3cPX(%vw2 zo*1WH3mS%$m2jbv6f@Sq$CC($<*w0P%n#qe++*p{v~NWfcczNzFkKPr(}Rk)3C63S zg-w|jaOx-ovOW6Ea^eOO#jwWW+hq#xBfh$Z^2cwdUz>TR7aeWvEH=d((BJuO*DQ6BVtmTSrWTqL4d|u*{=UIWi6oMO{O!z0 zS~|cjl`6()DCw#nzQ$Q+V!a@`DK6d96MI9_Ns6~TW1+VSA2E=zF|GA{zVTrr!TSpq zUai*yUpAf6trr1bz!n7pE7=Njt1Vpu=zYN7QGdKobnyS1vxZ1~v*4RA)t-Ko7Jm~v z4y$1}h2`QO_vm$WOF1d|o562*;d8Gh7zcf}tg!sBP9YG}1Y;FG}SL zE9GV?JTf{ON@=IY&@#r5L|DB-T;&Fymgy4v#8QWN(9@Xd3(v@^0vq3H9}n?L7}0$t@1(dl#DI8>)oGuCs9V-tSysE z-WclCZy*b4bm7zoi9MF7cc9-2B$2hQb-1IGXCeb^0uM%+o}a!h(KWbsi8t~mExpxQ2vZutKH?Chpa`t2 ztn|f+!N`HR4cil;5^~Ya2|qy23XQu%AaoSuq`*)#k{pxXaG37APOYD+DrRhKEKHbw zk5onjdB#l1L0cwI8Bt)~qhPRxPs%bZpdHS|wXk$kE0c#stG z=vPEfR8jqle>%y$z@rEk%N-8QU`)&o#`a}PJf?1s}z?ZLHA)%wQYCyN2 zU>NgPx|F!c8f;BTNy)0=WM0R$07uk6Cc0b3@9^;lU=<;Q1C_^qhjVjtui@cWK}DyT zHUktV_xvntwS8?N)7>HqdLd?ghMUcESY(zYHcQ;mWWq6P9Y_W`!&ALMlGN8*vSUOq zt#RK6je3G$ecl%O<44@n4Kr)~TXgcHq=XS>SpX4?R4v%s8Z%tLv5oQE`FMCcm_HCC zso2)_6Wa1&KLYXVCi27F@q0PAE}B`$`-n1IqNX z26lkxD4$Ni;$xh!n->>4W&*BXb?+?qifm1{;@-G3CO_VCRrEGQ1hlSiuIb)`6s)&< zOy6Rjc~Y6rx7nFWP)(CL=M0zHQhOJw9K?fU|63B1{1KKxUw<+o{5CiU|1>tc2ydwD zm`*}`0l9#G&(5FH(2?vRB92|KugqRnj1@B$5x|C^eMZ|GU(f2_mAnfvj#4{7{L`s7 z&g=X9Jo)eD2=RPIBIvh#W<*!k$h?X*vBX=6tE#H{YfR_>hPSCC>^{TwDxl=mSzIX< zWdBBIl9QL(yQoX9`Y81t$8r`S^Pw!nWVd zR&Nhe(j0Jl!cZF=8tR^~r&9$c9^-59N8B~vIpZsGV#e6dFZK{9^fbGa-+9P$swVcO zIMh^N^F?2U(x@pHW?vJJ-J^hh3)j>j&hI8pXGzCSH z?)%ZKsZkM#eLT$}(q{zA1~c4_3wp$-gsNFVP*dHZtPl=X)eXLlSPPE6M$@mITi-DX z3UG9;o5!g32a|+f3ykm$+^b6Bdn#!%Sy^LS#jDPVydrPOBkAH_jRkxAdTnj(zy5vJ z^1L-0v&Pw8<&$wjhMMi1jacsB;B^}^anG7(-+0spg^(mf9z+lCzd4t6A7-I6dUspfF6kYumEvN#aN&Dv zV%YF+XYf z!m&pTTQdXOv1()zTK~c1a^^Q>nkgHHcb8OAeuhFyC4^62e1coYYEd`itlN^QuxgFU zgM3m2!Q?Ko3hq3Yd^vS8wzPiz;T`!Gu%)l&alnTH>A+do2?fToglI~3;mOJS3!=eA2HcX zNNfe4Ous%&8*P=ivsg7d-ps|b%#GCP3P(qn$_qq9^H93gu-%788kB&5l0+HSNGM)md9OC!PnuE2_{6QlxxZ+jKA)=0s}wXw(;!6TMhIWq zU|Lx<`EzigTZVO1ilFW@HCD6g>M$Bns0$Z9TNKW^8>maB;vAat2%%*-u*ADiKk{d) zV9O{gG0gpD+c_y}dOZ?FZ*=}Tgvx)g#~W{C+=>N07*sWB9a&)B|91vqI_QT^Q{Kz? zj{u@Ec{v~O@It=wHiLrG3ziQ$l;nfQa`E}Iv3_=rJx9HuCYSv7;~;>nv{uJIg*`%z z$djW{h74|r$M36kMXR}6R;h&H<>RvhhZzWd3k3Sc4@Trf)a=)IfwGqZXe3et-Cs^m z@?lnx?LOeXi#*{>0eHv6nw{@8*IZ?E1VLrS&%ub@NP;b&;SpWPn1;3ny0ZA@+~{6O z)KU+*Iv73#iV;!Vc^L5uhn;poo_pfFju=7{+oTyC71y3R#(LZ@x zI=D#+D|Tm_Z))$HL<+~#H*e!MfAqTvrW`kH^;L+BSwbH;=Y5#cSXQznR%&xs|p^ zH4u>sr*N*7y$SUhc+S$X#$-Azd)$pL{Bb;oU+{wjwZo_#j|M^CcN>}j0@$viA`T;W zH2Hzq1nR96Ph@n#vt3QNC%Ia>xx?W*W%0MGcUAoSWP)PTJpyhxX=sL5!>lZJ9DVBHTVl`aRa}W7>B=Y*o-} zX9gd@py8H|U+hoANmd7zK{;9=gF0?SMy(w?V=1W0*`@j`<NIXKBEkIh4M51>UtnELy@UaYsJJTohU0uc`ozjfgB_Ol7 zF(XSuzsslq5RTPy*FH8L=TG;|_uq9OcGSrjsfI^qlKD}k)om7^c`6vXq7=ivc8ePH1u}eK)JJa>*SVYxOCJ`$XXm3R1GTyfo zY$`VqhB_?0r}giE>Az`tgZ7Fs@q8&QX{v|HpdFW*Hv0Fd-mljw9ElWXIAa1GpCMk0 z0sM}@dvu70u$vH{w?0I`K}(*c3vInNZd4A3<=f2 zFl?!?NaYtt_t+c)PQq2>vOEHvh5yi;M!=W5nkld6l0vJS5$e*Cy1j2mWS1Hh7(e#u zayZf0$|O)NcFl8Xr78-S%T`$5qZ$ZjHppD!@HV5IbiSqB1@|MCy;%li~6r;A^!GqY`LrhX#pVh~$!!gbpJ5x{1)AHV(O8 zNk!tn)T&h+OZ-73lqRx{)aK_}y0EpI;5YsA+F|INUXef;ejtq6WYZSKzW~qlmGZe7 zOcC~gT7OFebQ+9UCDosWGdz2QOlok-Kfg@~><-v)J$c4oI$)pS9wt~{X!^KVaFo*j zOTe_?D_G*}+X(7&>DNi!oR31`2)^h?In$B7ItoieLEhEUbnA+)pu+=})`ue6Aq`IF z1l2`Y!MUMY0b)9@!}`z@Whh_my(gTKWadvfBmFsOd+0dr%G2ee{{;h_G|Dm3f?C;G z%i|10|3gQgh-?1@Cye z6nUn9cY2avP*Jx_2t0iczme1)Ta$$P@n>@U9FDDBX-#9w*{80MuW8t0t`oTWg^MVD9OSs)D z-;t8x=B78}X^Wp_L$N4k(l~%cN?$z2_9naL2~#EMcS{{_vOPMee}!#4Fdw_HV)P~` zrJeN`*$_xxUXxx*_Zj#csis zn*`_8!A0z`-UU&=BEZq?FTJj6vu0Ak@JQkLXW1o-mt4A~@X}!n*ewDCU$&545+!d1YmOs(lLpgWm$7{@sJQw$XWA5y}Gqb+q zRjtQr(|;*$yMR9P^1myt_UwLtw!k~!Qy+yAO)w)1#{E}(T@Yi0Y0aAH z&7`C{cM2Am_F^;zS75}=>YJxqdik-&X}a2%gq#PS+%3b+ z^dJ%cz>x~Xi`&o+mn|Q{6nahmN;?Wa=?WNWi;TV6<)<%JZ&0P@e2srA_xja-4`Z4M za_i%`7T_%VcH$X&@xzciflNu)N!j{W zK|chaLsnUy5-<(-D|4ilYif$~IRQ@*nVgi=+$ZF}L@l`cuQ9LRlRqJ})H~47Z(6L? z+YAwCv_XkkNn7L?H24x7hqAQ|FB_9ys+;xXT+=x!Z5Jb8HGa=C+Iy$4%9DFnSyKGQ zZH9;=S&poubL{Z!+}x@ivSA~aYAKwGA0v}UO`pcn&OAU z>!X~~Iro#Y$Z!}{WZZ@8bS)O4nG+Y+pVt0b1z5Cz-2ZPafRI1>cti0Z@v{q`pk{&E z@W)b!cJh}kv6v)7qs=0g+mVr;<^#lI-RIIl4~|vGUbFubQ!KJwtt-SsxgPX8Ipmh4 zIee`FCl_zbSh5nK%%&Nj&}VR~yR2@Ah=(#}Cz5>hkaKUWxV+U+h>_ESMk3(WA@S#g zoHYwWS^PuK&r~X^eCFghnn%qPtoVgsBI%w!Uo0i|F7HZD6mF|g4OT6x{ajzIWpPA3 zp>};!dQJPhR7=7aqPg6Zovl?liYlr+6Y0S>K0p?Ry1Hjz{0Ro!VeOrFW<&UZ!qHq& zoc^<^Q{Z9l*7aEe>PffzRh9FD3)Fz}w81=dgP*I2g-wapp@vZ!S5PNL$Kd(GeWYd< zE^j~XG-8B_GDAdFf4y-$fSux;>-B_S&7_83NU^e?%n_=32A6Cw^&f7^GQf zOi@|yIH(sFUr%J)|Ax}HD12<MS5JlzHmgcbO6w53`el8Aw+7 zJ4S|uy=P)NHt1Dj0H)4Uu=6(!)UM=nxge&ch18jXQ+HssASpF@AsAZ*3;$>MN-6>u zhOEPY2gqPFiC{SQhTcq_nz}l+K*mAu3l2_Bm?CnI5t|Vk{>0IB(XViWitz_CbMqZ2 zFC$}w`EX)vVxq?Ttba16%oXp^`~Sm_Vi@F;cmBhQYKim)?$)UNE;(ripWBHp7XkM|4`Y$_O{>RsI110(znBR5*G5{Dy^dVRPKLK94qbe z-~?vvxPyO z+n4OWj3yYAMq=&)1J8N_;@9B9Q#vhp5lN!N^}Zb2Uxx&cvt48vH(rsfKKig7$yKfO zGybz{!KknVf4EP#TrfY^M3moT*-;S0Z3|J-=ntBJn9jOBx}(W?-awojokhcjErcpa+~itMV^` z#s0T@%5TcH<&y5#Rz3`E3>%JX*Q@od1E21JKQ>*puRIJ1;hRhy_rjDDG*G-f*~uWz zQiCg_UzKxCxX972jJ_P6IFyyw+FI#zhT8^}WN{^%0-i8qgWcIaUfPb+Ayy8vuyH?~A}9}ip^ifNz5J@%+PUNReCzYgtt2uH>qgxG zE<-2$ce)0L(_iM84^?VZSl1o^bNksXK48aovIja;#ygNM%Xb?^U-07k;$4ytiTn(U zwIq-;eJrX3Q++JSg&g(ZVn|gfA7^A*J%f|AbSEnF`pqSJo{g0wjbr5QO{-@@V;QG6 zI6g{`VKiU&sy}6FAQr8{e<&iX0JjaX=4-8JjIC}2=?Q$pJakebk+dne)xAt9BT?R9<>Y#A*0 zE{&=B;lpRRpO7^%dJ2p@x}vW%Qu&KjKTZ0P1L41Fib=l6XB-vBu|}SvxyB~oG38>6vc zB~UR(l@M4TjyNJ@_t|mqs34ZEk{Ul>IzEt$5J>$bs#m1d`C0!n&gONz^PzuH=`{Nl6)99bdCdPBcD8mhO<9s3}DLA`@U ztLI3s*7$q7!4Q|rZP{qM=cq~agwECXCwjtetd3+y1H5U`&bzlFk!20hUq}o<<5#W$ zcff+y#dv8!8uo*;h($j}q7G=tXr1W+vH6(VNQHpKjV>L<-;0-sI$dhJ9<<}IyY{OS z#ai=a0PEWzU7Y^;>EMGB^eTVlz-i}W+Gyu=@z;pk(6Xt@#w`ihJe zPvKj!QocutWOx1&)c5E|;?}HK7VF_x!0UJ6<*6eh`gqgX77W+;;(OKYjg7&RrKW0+ zTM-kRcldH%O&co5!UD6dl^16uX8Pt!!3ANu8V6s zJ~wxs*_$)$_WNAySL`nw)SVr?k$Cp{PEUVO7A&di*)38L?+*f;+tWmyRxiCY7!pq?8y&pcZyma>vnGP&Qe@5H1b+Y zDoo8KvpnAS{g8al=b6AFx7ere?RUe%p^J@T6eA+us>}B-n57Mn7J*G2=!Is;#Q){n zXYm&YjvFB@M5pjCk*+wV8d`j{J}Al#?m{LcjXsL9JkuI&ob35p>uJ6%&-H@nh?!W{eZ`2KG4O7TAy6n;VLx?l{cpbjx3ku4~KNZ1H1G2U)a@-`r9XgIVNM zp5^6N^(iA%wngqlO1_DAerXa85Y|49Xc{r1iMEyKYBZRk$NXS68r{m}hdB88TTX}X}_g{VF|S?+sCPd&BwlBB;N;$D)HnTB4qdL!H;*` zOvn%GpGGg^(JNUcP!X1&0LQr)@DoDb|_ay@M6Q3c-O$3X!zJ-4WgX$8Y*C+kny6CADr$V zy;Yk*Z0&dMl%ZRo0~H(vo|L`O=d z{ql0)ro;}KpOso)N^@pPRotOo$}*5tlPVx@i5U1etrVT5xCw@DSqu=O-&4}8R=1p3 zMmK$~7DR97&wz0forMpGWg3{xrx-K5??cu2MtY02#>TSVY8FsKN<+2zJdkx+XS^#< zZWF9Kpu-nbf{k|{>3Yz44Ew$AXHN9j^Fzv0suIk#}4_WJo9~mO&+xpaR&Qaf&>d9w5*u6n*J==vbDBqfTO&%}C z?60=+%nl_KKq9dgk2R6sX4(y(Uw?bN(c_j&q!UX)?5i2~xo(_$1tysL$*>9Ec5xGv zZL#NhdlCk%_OpHJq7|C^Mas>XlxLNa*jl^sK_{T!Ik6oA$4&9_oKfrh=kIhjBJ4?6 zzvju6!UWx-Nwc0tE7GEO*aO9kBG8jX9{A;;VD_r(TqJZxrKlT;6vx_~pMApkA!PQ3 z-dWNC=-CEk(pBYriUb#h;^a18=!y3w4@_C5FUtv+umm%NC< zx-#|6>FTEUSjWFf9h!JPdUk$Zd{-NdMqR2$+s*+o>S~ms^9Q(A@gK{Sr-V-)1*qW@ z^QE=dMPOoT1TN`|m@TRhHLhg)wFdGx(>kJE8R?aza@j1V*0*(ZS2%F%WuR`TCcXfP z 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�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

        wn(wMx5P~ib=Xp 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

        (lD1P z+B9YaNOXRS-FyqWS2nv{o|FC$hS}dW>}Si~nP>@*EHZ|rV~L6O1V!DWg3p;%iDZ z^(_R4>wJo3rdwS?NKaIJOm_rBPv~I%?Xm?w_w#499AW>;JPfKimw_C%h52F^^D*0` zcEX(rUT>iiSNh#d6}2Pwsq83Wyt%Vh&Tn5;KM)VDax!LgW0=yU$0p1}0YgYQKvkHu zl){wLL(tOJY`NRV^^_t_lM~rjKMZPC(-L={VmWzHK^V&lEYB#SR1?z@5z*mA@XEeZ zRI1B|7`cHOb}6z$)#pn_`wj{edTsKUWw z*fnPPHa$x?I7>k;cTr^+?d;5)l-4_at}V|qsUnU5N9Ew)P>X75$yi%iSg`aenLk;! z`D`R;vi)awjO6f6qPl82ozLE>)~gBPbntVmWM=|WV~i8J%KpQ_a{R3C@0<{qTauw# z$($+&HB<|XhgGPy@d_R|(b{BB8}pkMdM1f0@6JBHFYSv2Rv5kaH7Ee41l2cD7BlOX zYOAqxc)a^}+{Kulmv-nJ@FW43w$ElB$Md)Rxv(UJ5|QeYe2mpIze`Vf>-g4-QJmA% zCy}F_GWWeVbGwsfk5!j{Q0=P0rgF!Q6eZOj7?I@zofb8(r)@~U=;|FGE-sS+{l~LD zne#&iP=kZziw7qL-D%k+v`5t2$fd`}toX|r3=uJL;FY^@@})9Up7SO_;xj;BD4wRQ zQuvzug*=RlhQ4$aX~OXSLVW+J^7RQK9slTsi}{W9N7ZYYswdm6p3($>sjO*xI!X)K zpeo_eZj-aU9f{=`APk>q9--%LLP>*bQRIDt>u}oc;|@)GWg*l)MSuk->w7~d9M#@6 zOy^G^Odyl9wGopiFlQ~qzYdIWMf0qVKA~W%Sa8MlrU}b8O7MY+=iBI6lX8Jd*?ink zNqHL&)#`rks{CnZfl=)YZa|9P%;|iT-+hGP^t?{a(+8+N41Y-sBn3gHUtN$`_lhX0 zvE}5rCqRz!2>q;LkwF4<-pX-rRcW0+U5jF(Xoqeop4nGgyrdE*o^%KWB&oAfsZA_T zJgvAfW}x@2yFWHHd*OYT^HKQz*`5Z?leuTQCjS5@Vbnd<(*U?S$X~kC=&F$?VXbv1 zLc}1pzaD$X;)g{F`pU1LR}NMwAP*xcCn`!sib&RAcs}fguVoaJhb_PzHPqx2qi1EB zn2<$JpDtqQjzv|=6Gjh7f)%po>W`2g$!KLU+Mj0}%FTfWN&1R{i9pL=)yV?{6h2;KaW4#{tEnsRfk@z% zj9`uDFb^T~sq|&!`?35xHOQz`%yK8ctve6oZ;B~^vnK$NOT5nlMl6OvU%Ey zYEbE};KrPDi6RoE~fBIg__qHwaC+7kl?OK3Zbky6X{fnDTiU@hvqfID_h_m7~DkV_$Qk9 z_5z`#S=o!q@G3hl6FRmOpvxd6^I`EN?UEu|#bsOmojoX0IM2g2oB%$RR#yY85{I2H zojzSZ=u)OtH4Y1rxJ0C>A$dcqw|T}DEa=dgYG+3=48l)nwvV#?u~2f9xk*5CXC}_~ z;vBWjOV(0W+Rx0-OGjj!UW6!6;glyrdNfOCzG0Abx_^EV_cD~&L_GgU`K%{j*RjcU z4@tJP=h0a!G|gPaVJ5}4Gpe8_f*BzMrBJc$nzX2rM0I<=gB$JyHf;n?*}k4p!Upq5 zxcvw?u4FLs-3nFImbX;ukatm~3MQ^aJvzC_-w73S0~!+3>#?v26KreZoAOMl#WDlA zhdbDETz(%RR#!I+*-lM#P~iVBAF=%3e8d7Di1{{*9Q%VW;_&H%(`7$V8X`;#yaL<3 zarfF{NF>RPakL#u)?5+9oicYXdPmF8Np#PvuPwqAe$~}>i>+orxzqeWLW-}^I2dRz z8?(%;!#siH>3Q|e{3^5G94`0BBZGj6n6{26jyyW5GQ~1A*@>!nz1E5u;kjRHQsS;j zIn2r3oauPTWIEGIVU>8|r7`2;@QhJ~rBQ6EHe@V1i6H*2>@Q4cs7%M49*iVUIX;h- zB;Mi$Rf5ptieoKcxLB%kB*F*G$`!{RLF{QCH2r5GT?P1OIF%v!Q=Rzx0hksNiIWv@ zCITRMZpCp|&oD1?PE}i^{hU6qtEU_WCO7@A?!}i;(_(P2`H&J-)R7#A%kY^^Xh`DB zX4|C+%ICH0$iBUnaWNkpBpXvVXsY65-a0G#I!2j#m^P+}+SAC!e&EU3i;oe}ghaZ& z+rPZIA}InrMHDI6&A1J&mSW&Qi+)G1p{FZ285*5?-?SrkGch`M$8^N@W2CI1Q~rs3 zjlcUwV$4mfaO57!-dVn_4sZLY#07_y>ft+C*34M5AUN9<^I%T(Y}9Q$H}lo-jbewc zONQqVQS}84gVYr{DR>8Nwm+`j_v+&*8*HM5eWh3?CN}k5BSt{Z1y4Z95f((8<42>z z4>+tbveS#vM)ixL#|w9ap18TuF*8{>W8=fS{(bugiao+UqsNQ7YWm5IY6QfUyHk;o z!Y`48yfYzRm^*Ys9M{H@($x~udc!;Fz#Hm2w~e-{LWfXmA^q)D7xjaE+N z^UzxWS=-toNq-MH#}VoDv|!PcB~?6gh$AX7EI{uu{23T9G1xCr)EsUGGoE$l8qKoT zxrVT6mpw#aYgC%R-!kGPSHyQ-7}q%lgZEfnDdGBV!s=Y;9x+Op+!E3XMILXvsPa$h zs@rsl#tRGo>Nrf)lXvoG6mBkbE8JP8nLApG}1+LL-%&Gth1z#&H z%EEw&c!3BJp8drzZ~0U9aPsj{t_i@`fZP<6VNp8}}4! zN<(uvbLADXCGg)y3~}<4^$c@l9iFXIE3N*nP}>^wmtLrLd-g{)zITkw+m{`E zSb$mzpAoWqYVcS=Q0~T?vb;3XgXYJdZ%0YrFeh5LMnXrYs_F@SoeWDC_#F!PL|Axq zAO2KxJUHxn)8{xWl|Ddd3cf&brH*GTrPpiW3Gw#my@}q*dLqrk50*pMFFYv8TAa)) z1`3q(jNcWiAsMgY$NWn0{T)*jQF>QYkw4>2FcvNQxusLN5rxNm1D)1!)29F`Cm-hf z*v{#DIE^qyDZwyN#?aU+IDx%B1TPs2WbCG{*|`yG-_!S)t>kg1nB13hpug!mOiwKy zPgmknxe*DO>-qt<6Ef*KT_(1r=!?`#?>4kStLb3=)BkZ0l51$Q15p^N#VLSd6&}py zw42MJ9$*iieLLH`>`Y$fQS@7kFex!AJMPnj+~p!W3xK`A4u@vz!Qxjjhjmg5>MDXq z_-`(NMDy&O=gW54dPahK2Z7-rib4jMi7N4bgXDnP0sMWmUq8j@2Q+zqK19n<+BS+^ z3To7)ptActR8MWeN^!^4)JylR>VdSP6xa?dg~?8^S?`^{g#fbr3Z11?Cp*YT^3jdR>mL}7siV#Y(L>frh3YvP?ZOn3ugc}NJ^QoY7Zpu z*agMdae{f|Srt!d`PcF$+J;EB2#Dm*um<}x-SLxeW~VG&qf8N0ja;U3Oz%_LtE-6P zJfGd|rk?ct3Z;FoXD`>{#B0zbP;jtkr_-Jv79Qh7K8Ww18{q~k213l45-M$9HD_z* zOz5LasM1iTP>AUGPM_@~STckfvQ-|<{aNyb_g^kFHrpe$X-K1&T^XvA)IUD&9Y7gv z?8v0|It<6cf`tn%gUt^g=IF%WyNJ2k2c9XUSX-5Oce^z+SCw+~2d>0JT(!UmA*{C= zH6QD^3qQv?py)|f!tZ(&cexM2vSN!}MkYF~Y8h@NSD22k1%=6nzbN!=H1&a1lsZ(! zv)GjG?fcQe_URu(OmHZJq(huZLq6ShslnJf|CL_Z%5I zyFOWf=0-!(nkA3~`R$DfAVTXE07mVxl`8w3ABTTb#3s95hhbewSfQ!3IrX<(6g&93QYjU#6T7#LaHT%y{D`X&&)WXtx zJCAo@WwUq7A1Pu;?txJ><28Z8$N?_Ha#>aHMD#+*b z&~E}~dPO0O;HJJlq>|D2Kclrkp}vazi544KKfjDZij7{={QV<1Yw>msZ1`-#!^num znS+HxUAs3V!1`wYxIyAX9-D|Efsqrc;xMWmVs1~xB0{&DtWjkZj9X&v>A&WEiQL+Fv2j*yiBCPdVEXDDf*v^nM zM$pS}@!dYR%2UgNp-d<*rP0+vwK=UG6B!{_@c zyK&fi`e4WL4`L=NimL(G%(*3veH&A{bX4{D#KHolDr48?qbf$~xno9u_6)1Zhr&~N zpm6e08|JL1iGE8GAZ+-?nyCHm14s|yo;vNLRVCcbI}pJ0Y;??B%oKx1A+kyvL}W|l zV!tXKUShk8LG*ZO>Ttpm1s;@XWH$Tia_tvWj!mEZ(SUpPu&Zfult*yCru|0$$^XEV zF=;Hw6G?_6AfY+w7W8pcfV}!Ed8P4ebow@&}jqJOiUjl$hsnMKqu?3lC%q@PtH}EES z5cO>n5&K(1>p;vs?(Nv;g3S3dTsYMH#+@OE&kjp4OXiCYv$fYy2V@bVmHjRAry)is zN7ZzFX`6kQPH}8iY@CV zI0n#4w22D+5$u|S*SkB{{zz|ByK2|t!(I+DeZcD{)&>_WceNa1C=`~>hMhGrU?7` zgeeU>t=Gl)MFJu~5FrUd>LcQa(SVc2(TQ){>{<^Q^&+i4Q1ZLq@x6^QeW&^)iKhh! z7+sd*z;j(L=IWID2hl=!6Puf521&~G)1t#m@t*OFuN#?(gHscbwoNuIv+a2mU#Q_4 zVAC!xeoLx7_N6$ayr$aHZ@^=6YUi_`$Kx)qW++A=4?ePlMy_q|tb*RXqh^IlOk0&XMtD6Y0g9EtCb7 zdw5b>p=#wcIx)!+b3^SKe0j1{P=J?^%*}j_|I&D3`k|O7BLo4*LJ_4jPtP*dzY=Ti`FVrY5ns>34LC|Ed6flT9hzi^b3n3fDP{uDw7+ z_?N`1BLVC)r02-PGG z4t#6JKmHQ+tWr}k97+ZKmF*4|BNR9LAG_$^n~IU>xBlwh{5_ew2J1!uaW5tOx2)jS z2-yEsinLKaNRHJ>Q0Q-=-(=JO@0EYv}FL*xa5i{PiGdmg@0bZ#twb-q||4 zy`dGTFJZmi#~(Ix;XwGmdIAd|uLL%`^J7?IhMqq3ePVtYTwB^Y9UJTV@fsYDiokD? zC&iWIH&P**6n$L+B0RN-kk!dm$(@JiRE3zgcGR+s}(OZ0`QBW@E$k3iGDT3I*Kexqu_&Eq2DX0TFTHF zq8W_{q`Az;GiQ3o(}si28F-(pyUyJ%bb;2E`Xlkibtu$g|4rIjtof(kHWKdtA?z)q z+UnYN(e|N0@wT|PNGZjkID}H%i@Uo9cWH5_xLYY!+}*862<~pdEl2_cPWrsxyZ1R~ z>~T(hCqYRTIa&x1T$lzKJn>kz2v-ql7M<7k8b5jgUr9;k) z!(wJ?D%G|(qrIj@IZ+{GmwKt40nGLghV4?L{l?Hgm;Mos3cj%y)fXWa5=K}poEjVG zI){I1IQESkh;L1MN5#WCU$B8(ZT2kL$!#+iQdXW>N(xfzC_DyT^=3Qs!@WEL$zm*3 zqfvJ))xYTKdfO3NFLQ#!RAR3qrwkYVL`$6(R911V&3-u$LfYQ+nN)Nfu#bwa^38F0 z+x=`N-1l7@`-#Of`cfje9a-jB6|d4L6Ag(`ic=NLzNQwry@szMlyvXEB^xa z`PTNf_T6SG_L<-h`}L|%E%v*UiDg~HmjwU0r{R|}6J>hBslDS}RW(Ovw#jLADcu)c zZ*miQl9^H$+BS?U!Q{i!P?IRU>fPh*`!l@ljUw}-K=XbAIW?Ij81|}92WYYtKdlWx zP(uu^v)py{)&*`2*_ZO-d?m+kVsAJ@X%FzDV44H{^x?KQ7MdNh-`Pqgc!OymQ|#Fl z1AETRiRK{02)COx5qaleR&|uE6*9Dz>dd5OzzlCcmrQ7Ig-1TC5dl<8Q z#JppD;=F*u-=^(L0$**dE7PNA$z9%@_YZKKDb1d>J#7@;uCe-%&{&uKu@wH`ctE-nc$50*fqDYtm_}X}{N4~LrC2Qixt3#Ze zQLln@cg|_x{|w5J-AZ-G8<$@)`ch=`r91iWVu+ZSn99p3FMtTXAe}>gr%xF_k&YT& z2y}b5QU1}DZuS;zd9g`T%I^b*?ZQ745Y_B}MC)H(cCU?N;|747E6R})RA$e7bT^@sYNzvp;cimq$6pM@fQ+#Ru0fScM$#~}Yz5H= z9xZEv2_53O;Xz5u$?$y?O@rzZk8sAq9c#OC>sU_}lqF4wKFi+CSk+QR6wxt9#zNz+J`1tLD!X@n5L~`nLr$~bM zQgQ&S$esWnt$iS;cUj1J0cqhxAwD&Gil2U9wf#*#Exu1InJt2 zQXCY9Ervq1&{$S_)=-8Pxd$RzOtCK2CN++FX1K#z(h^1rv!`D!Ued)=Q?fXhX=&f< zPM-vEx6kzF#Gai(W)7w)ba^5V(;OHQ5%2%=Xf1K&!PHvT-rOtiTb1xw9vK#B$}xPZ zDUg8*Xc0cBD3~A~)Xm&Udipvf*_+p_Q+%7Edihz4dFpn3S?;iLhdPsll6#L{B$taB zve)0&QJmHMFzh6i47Z1ys!=RMdu?A+Wbns;7Fv)?Vl>^~6pSv6L%|6V-@R znJ6`ilj+4jL=9;!Fa-71Fg0ceO2tX-+qLByde9};ej2G5 zRDLaB6L%lU`z2s+*c}C?a{no}YbtbE(|ggaet&_}1)xS{YVbtRHm>p2InMDsjp};D zICfC8Kn5S&t5DCKF^SY#gvAkw7dY=0Pu9Q0`RT8PPUUBhAvI-Ql=ezpA(_hYbn1Pe zgT3Iyeh;p1r)Q_c{fD`^{VR;DZ~=MwNGhhG&lyc6A;Ly{HNk96v)gdIp~)##bOGQ} zhfq3tRprJ|N#JvHN*1bs*h+wx;UwdlAIYR}d?D5o9r>k$i?;K3#dws9c{OHm0`?FQ z^qShuYjYZ61+fhJskLoTj8b7k!^iFiQA&4Y%wm*oiWwyqhqnUJro&)_2Hj*} zHb@&t!CYVM@O{cs|0_B(=R66XqOKHk_iDyK0rWVbfXfdGi*u z21|kTx$#aZ4BCi#8$SX*`I`_cSojXfZKn9=e|7go_1ij9m(A7k+C0j4roXV+)ah&@ z3PW|uI8wELR&iD(v6t*hhD#<(+g9sRrbU`EH~COwe(GDoyp&hziWg%sSuQ~#$7LkV z|L5U0)lnl?#=Diu)LYE~JQf$1@_r^{yKJw~NpJ}7s_UMS5{(aUWrL}UuM>%@E0;s0 z7`jH2{Chq)arEy}7+K8Ujj@gmelF_yT-6ICeYyY05!NTn-iH~da;=%FdxI*O{-2X@#F zl(cV!Djc&3Z9dQ2I6icyRm$dW?G>uyyPg(ozuEkFlOxwtGW*klE1M=KL~6I&ux|Bxrq3{=nU( zh%qEPo9JXsjb-2+`5f$7w_AtqsEM7W#hJV6fPm#kVLh8g$7a~7fM{30&p{8p&vUvR z%(m}mAbr<8lUIj!wrR+zdQW9~hb^w(8I1wTj#Anfi?i%wVqv6+)39@dGCSE@tEWx^ zaV>jjRkc1H`$ZwUoF;S=&Jud?%IyX1Hi3?AjVtPg24-I$1+uHjnKUpX<{4So=_rhb z%eLXC;OSqn*5B(SJmOL)b9+E#$AC$OHv#HBtJA_yWEUFS)y#^jei?rID37sB|~a%bb8I?Vxlmn&Ofwh_*y@R2znVB8LZcU9OU>^yH18J658Rv zf6C(V0at305n*^vR-m(I6mbBBlkWHB_kMWPN{=OuZNQXDG^48@o!^Ar&=q&@zpK6z zjPHWP6$5v~1D7k!gR4Y38!Je={DhTYNta>O=eQ+X*0|Y{>=S#&o%iOLi?*6S0rfu| z#=WeUF!!{R=GdNf9miy~SOsV7X4O|}nVMEWbmFCE$yBT2GoBtdKG_k@hb0rL9z;Vr zjmQ4vTHp0~$GYP58<^6aLRn|@?GEfYF(d!^?QQB)cM|NDj^LTnU8@g%bz5|NY!`)0 z9HgM693D@R@_J&LagBYt!AiBg$rn36xwlaT2@Rhev3@P^VE8fyDpyhEueGMtJQ5Ob z%UkxaZ7aze5weioyJn+|^DfJbBk7+%vVGM?q>xa>JPRvg0rh~?29eY4kfI7kuaXj*cqZlw zHvK0cr5q(1`*D8QAFbA`Vf)o6z3+@x6dmW#TS!qsNk4ro0>K8A4I^p?oDidFyTTKD zI+Kr@H|As9-=$z%>@~$S-GXYg2+B|o{{2z;(2MQDs$!^8S*n+xo8{gWwAN^&_83;* z&^Ezg^xih$A&NMo@#7T3M@?Rq?WQpcq1ADekR93ZzCgZF8}x5ue(kqAVLQ>*OXaL7>WufsSh?FqQv`wr)f zE|!oCE5=&Pj~Mb>9Nw)JamV3aY^BBxUi5&+vB@So9ZSP7A=<(JL8VE~kf^kNYMm&E z9=_v#lT&Ae!*2f)L`J&UfP|wz=5_rGMqd%-u;p14C4@5MUq95$f6Hi(0`Hv;PFWh| zIrUBJzq?U$-8}iSw=}HQg$z|`77aLIR@MzLp1m|@zBfi?3RwFy=Qrtf_S}YShzIfK zrjF=ofEAflWQN~yjXoz%pW)xELeHsvd#Pe~UOFB9l?|&(fT_$r#M(nnFqKHkD~?o| zTkXQXihNJ9FQLwtDe7O`w+j58+X5XLu!6@ehEX4Q#RAp#ui;PRr81j8?OJHLXLCP& z%=8n9E?9a*^}>^@!?oOck}!F2ClOmW5LL6|oUfab;cLm3P(?fMz1-PC#|_azO{UD1skLqb;9bWB#d8s`nW(ibCuE)p;*FUa3pAZ% zLXg50cpHctA_20Y#-4#I2vml(uX4?ULVZaIwa*qys5drI(loGxvM zTGB5lbofIy@%;xqda)%_IQ9)nopzYoD5n*fl6FKgtyFz=!p27kNC-Q!5)Ftp>|F2fal!cY%aHc8JFXo77px4vEhqy% zo+ojz4QA=l8olKej4D4~2{?iNeD%}$zp$|L@tBMbw>@t6w?7=%;S^%?02C)zR{!Oi z46lsYs@uZ+Dkj#-&fqTZ@0~7yo!4xrpBhLy%!Cu$H7-2U@L0#GUWDRofEp$(h_>e^ zU198BZtRUTuk(fe0>t7WQ06cAW6kuoUcrTt0LfxR zf%RN9y}e-EcGHAI@M`aiSN0t>W8OVEYyv!a=J$%OUas#PkU%dCnz$vJ3(4()gyq1R zTeoISc_8eoitq0gkXg}GV*j9f9B%i%VXXj7@)fe{dVg@#@}7(^rq;+|iA`dDgVN)-Q=|Pecqw zf#!&~{9W;oYP7>OD)SBajD^}e zBxXbm`)J=8x*jkPLIi&5|IN5oPBNEB>>n$ZOAUszwW)&oP|tc(iThIMQZK&=PK3s8 zf`(RPS`NrTf!_REC&c1qo#5IJtkJ_q?&szKPqM9iyu`Nf!+!+GqWwYu^PR?b30O^h z`^6ipM_fGRY2n~G86hn&`TAiDDd!Q1!a6*eyQ+cn;%nzfG|GrWSQ*{ZBbgGLD`bEz zr km)<}F7trtK!!Xy-<%OtR)eKWt1yG<-O%5E!xpm)y*__20I%--#ga!kVX(bCB|J4E%Kph4(ruiQ21L>8;S>aC@9Bqd9&QRS?Ey*JziS7cffPNsuwHQC=f%ReTN zA%RQdE?tUg1K&1bt^>82uJle(X1&_&U^gep(R z)_C=y{=VJ+qR&tefdI`48;%nyQu6&7ZZ0z;BXGT;nrW#LzFwII{w}aBc&Vpk$6WhM z)IhM`hqwRTF3mv;zu5t0$s}_YTIXDU>QW>9@{4FvV!r0vXOo(>lS@8d>l(=;0u0}k z7#)1eD$4?Re%mIlbY9IHSSvt_(fRalLPnQF%%s7B?>(}6Z3DBKAkZc(WV(BvXdq2` zrZt;H=O*9$k(q`Y@uCai9Fc+N{&s;V`T)XTef!L^YA>(h_U(t6m|rNoBfO~&GQI=L z7teLn*#ur$9`ZetpUW44j6*U;6nHcl<6)&Xt zGLu3E`M(WT^q$KD`a1(mnllOq=s!gBu-I(;;vlvpg{as9O#;|z>c40YWrf+aQp&TI z8Y}D_RFsRHD9oQqjHk|+BHMt*cAsXK9;rQaj|z81H9YZ6)mWOY5G3ye@Kj%vqzvM@ z7Ir2EavT8X&i>?U=iZ;s?=)#%JL=)%y1ajfGP{;JK~!ONoGHR-I_$Ku{Gxb=q*4$3 zetBQ|E0pFw_2I~sEtj~F{(i(40m`v_|G(J+yM&b$y?;DIDkNP9$IQcbO8 zRIA!ZbXE`9!!kJ46Oov1jw?V+Y3J^A3rj8d3s|3G53FGUhs3fX?#MHj9z9!Ix3?sNB?lUU|^NL)& zAw02GhtrKx=+}kt3i#OgsB(3|E$;2Yu}%{s#d1s7C{@J)>1JH^=0}Fd73Aq$ z{Na03EKyZjf+|IsVSApp0NMwOE{nCEf9T%swq!D-~I4dxQ@ zVr@O!LeYEc@h)4$;~`eFA#`QF4)tacvVd6j$JIYCu+M8)*&kp1FIbe(M{ zqa^)yxenJr=W?Es`wg{U{I^DZ&p+z#;0w5or^122vpr9y6iW1nR8Fgj8Y~vO4ev2U z9-?DI=SWD0zd_Q7I3hW62T4;Q_jVqo334{kl$?Pu{jgyn&zmCR&s)24oC`?aWvfeS zTXb77+v+%7VI{u94q;Buq+!1W#+OOzp!iADbjW?-UMm?Cn5_B?=gW$83|nhlpif0B zEQRBn6)D&5!ky|gTU45hj8{_{S(PKtd;HvtS*RsO=Hj~i>g)`OB7=Zxl^13E@uzQS zww6F4N~}XO8A`$xo7usk_ds&nv!xkl*&V%=Yfgu37DWYqaEmR~jI|o26w3#moEh7% zD9gR1s~lO1jztbyFR6IQCKk5Ts{oJukcbW)$L)$hIY+TTeYX$$j-|6{U(rWRzN(r; zC_sNX&;}eg~~C zf#0*VKwW8Co0i2qYef7FkxU}(tjR4KzS8l!=)h`J*hf)FEw>SnWh&A zq|DUx^F*>V^89c^2xy(tp>Q7wEDA_b*gHHZIyv@>$_&ea$2M9y(oMUnAZo_%K6YT=q98(@g^&7%9#l%pj)*yjBipkqLPzwctYINCv3QpHS`jQM+S88nT|TsHlG^B#Z4o`%9mzwE>*_;ntnw|X>4+o&b)88EEe{uj%f-= zf2Uj~5%oN1a%%gTtH5duf}89U{C<5#@fPN#oKkyeIQbwxn^$`AA_`a7skraM^eUC% zcOQC1B#}At=z=m{t5}Deaq&u~QM#a|7gTYZy$$j+&saX>5s^-)aE(`cC{g@H97pG= zDt)V5jNy9hIu zkWxT%SQ;!&|0Ei0gLXjru@TVtZPG6DLu2E@epP%SWDw@6L9__J|KRSvU?YrilF(FX z$2frUF`aZis{epyJ)2Nh*A5%Q%&e3^9$%e{>rXe)E#^4VN$SZpzwT~M?Lr7Ri=1el|5?;$ zF>WB;^UCA3{?`|4=71)}p4oZwlboom#@4_fC0e^<9M9#ftu5PTektQ)Q z4PPw0z1Qqv&+hcD7B+TF!Ze;cC-9MGo829p7w($I((hUcVf;4kE5!HVe_c#lU3446 zod!AvR-TeU$X@sqItv}r$!JS%`5 zCmCD5<;>I}jU}sGB4`XNdg=+R^m{l(rSmPGoS_7!qVQP^SJ@qyh?5zaD5zy*xS)oh z+}Vg{^(SnM-Gd^nRLpuPXX}kLPLr7;RrEV`JeyPQaS8#6R;gFBOn1A1i+n8mK-D3n zf3z(V(~+hmg*;;DX~(J^MU;D0!T)@|`F8AURGc5;r-D?txWB z_Hmc*L&mx=^6}8snVgyXmpkvzKF`hE{L8>UXfo>Pmb(=2*B-IYbJlWv5ID{ferZJ| zx^3g78iF{QduOq(p^@|H=Y`#u+wfNzvmL#LT@?&V1Mu1@Sw3o!7^CT66CsvD}vH>1@w(?Sz0a6^dbXK<*XpQusk^ zaDBvQe%Bwu4av2=RI%sOfK!3NBDb~19o&sP?w)GU z0sX`$cEN#UZ~NZiCGr6_krPQOnvVVJ<#6R!w{I1SmSx;t+KbXpBdS4y`AUj|F^E3-f1}d-@at<8Kq|b z8^0RfmYa}~p;H;RsI06kE-t=O=^6Y=eWuZV`6U(>(>&n*_N>?oy4S==^X}9?443jJ zQd5L%jjmJg=j|;pIXU^sVFf8^(ZHC&R(xoTwaTr$vf6QvIucn&ol%RmTlzCAfH%o1 zZRvmS6U@O8=_cs>@@N_JNkx(ZR2U^Vme&8>urYBikN70eZVbrAdJjh6g$}4BLk(l9bD9!6uA$F zTb)y&^W{!eXRc>>Jeu!XhEtn=UiS}ahh-%HsR1ADv24Ss7DhWu=Eew5-L(LuD?EtB2}r!jbHLSSr3P!W;1> z?B+>ECpPl8*7o804|mW5R_?3?tNsdobm~HrI|IjWtcKpqZQ9~R7I+gFiy!>&!m27U zF86Q2f)QI|vOwq^^ZNOSHr6NT>O@UTd?Q)q~Zd$6J;&R|@t1 zEj|e5Lj6rb&Nh>$?~*PUdoRB zb=aD1Zx_86bf3M?&rm}H{`A||S?J%G;=kgVFE5ex^BeRicMK_QDp)wv%ho@?zCwn< zybho?e1?>`{M{LN(1;sHZqjk-@?UHO?zEZyxK>mVI=DK%j|RG+&+#Su|1AkfX;bv~ zf@xi&3a5NtBC?`~0x9l{sZ11VHpP}0W7)Aa3Fkq-7 zGWeKr`w)B;(7BzCp7CnKB&wl<+&`b?fZrV;1&v})HTa!$c3@k)qUZ1^xBV$8dC|-M zM>Uiy=Xf&snWmuKv2e*^Ej1gfkhG0xP>IZ#U-$P6@S~_hPt_Fex%E1kXT4{rn-kGY z-P_gQXaxZ>Et7MhiDP!VpEGa4MxW;O3;UHVbVx520PLxB1rb`BAl`KcZS$l;r=s~4 zxq(>PzWgSu->MVdu_k_si%x{XRKed9qjI)-?#VaKelauu*|?E=?l8HJNvJm=)uSNh7m#BHDz^>b?)?swlH8p?#K%DfXwmzH_T2Zs!DZ zwAFFzt&i+YSB1yH&Gi7gnaJ?Za>Prbf3olXmAZN96YIAKg7;^u%OE z;WAkJwgm~zrvde698p-WxnS2b>MHn8#sgUIj{R8!9aL|>E+v<9Z1NhMOeT}g57qfY z!>%sbJePh&c>j~vv&a%uSmpocdw{v!^`57ShDd0!3C$dUmf5OlYV@~8FVXx4XIN|katEX7R=pcHHZ!|GCVPb$L{A2jywLu&2H1BlGu_Y$4(;!((#Y z?Zr4N$V?Cre3&P>q?5j)E|7F!I+nTC#YN+!_}`qZ1}d-4tJn()-fUrFU5P$N9Ubp%l;Q z^&?1@POmDZ&Gyk=phpm({rYJ4A^n-fQlHv!A#otphzUpU$ge z`~XJFmVAB^Lt23*<5mMFDAQd54B&Zc2^H$E8Qn)67^@~PU>OE4w@EBC#54(Ku}LK zyk(k&*&_i?>lgYxPDzdFEg~)KLbU@5csrj~6`$O6Y;H(K(|T4h@SGok*dH+7ef%Z+ zi@81r?KO~2pA^Bb9d@`%|aHiG(wnieHC0fUCiHTM=;Cr7iz9(zaWpjn9LI$Ys%>^S|F&D zsM@S42a~X0xhST3+3N9hftJPll%BS>X0h!2#zR};qRkYeC+(0 zQIsZ#=YK?>G`Si58NdLVI;bi336!LdJj-NrC7WQ}kiRCv&@|{kM|yp@GRU=-1ZFcg^*~KkL&)wVOJGnTjUVJtgnZQpT2Lh(5~LLTYPnq(kSq z;h=BGryb_+DU@;jCGm+0dvr44h3{ZuaFZ4Fz!F(D;5)u@ScJ@^=`M*hl&GN^$uXy# z?>2f1J#F&ocprX-D72+AKsROyA4t^M^U4bbw!xFL3}-QN7pHyUrxDEhFowlv{P!^b zVN?ML+b&+0npVL7gk@gNKthP^GJs@t$zUT56$NS|GUDxWLNs<-t&yX{M9isA7Ve z+zne{ti@kWE1B0H5l;^rwd+^)jy;$ zTjGeJwY^~-L74wFYP7{tfly86+0jqtgRsbE%Av&nJbb;PYev)RCL;~v@wN)fMyvm5 z^s{C54JJKYF=5bc##Cu8rq-p{B@Q8bsCjQg4k9dj%5(zuhRTdwsDV$9w$73$`fh>Py+OTy?uRWLrpWI zlK9umzcvK-?Q?Dod&;OEK_}TtDl}A8ZwC?|jz9zfIB$nbzd3%$GI zw1v?m|7g`KJf^6T^Q4{tgV&q+H0+$9BW?Q=-c2SmR~pe7xI1*O8erz3!i#Yj--qCx zU73qlk*rQ-PPe^5!BgAw436-~z_3)GM@wg%&iM7qnwuw*NyNLE1}4w^LYIhIh55Q4 z>cWFcaXZV8RqP^{1(=e+h&LA>$c}}}<&>D1=A5TOakp#kHhqPsV@8X;Ij=>Pk}52= ze*gOS?iT%jX&gE)_TZqY*=NyIQ^eK9r`@H#B90%;7%p!gF0Nv-q#c(VqR+2~<{P=U zo2nofxhiXpm<(M+N-q1K0>AU%L08#S{}{Brxy}!9bs3kN)?f$!toMHoGY9UBNzl$P zLw>mpkdfO8&qoT$E~I%^oRO=ok-fj{nVZ4zbozV<&QqRF2odc44c?}HWg!C zm{W;P!Z?U5dhs~VlnsH^eImZ>WVzc*S*^^>Q*1T$37u*MgEdSYDc}RjKNIOupry>} zO?*!nqOe?mBr3m4_X5ktc|0=t~|}&-)hRvdKK<&$aOrOIA!|{PB*Jd&NVtY0)Wftu?4X ztR1#n;N*K=#}y=5&-T!*x+xSjG3OJ^utc?uh{&xza^@*%q03zvUvt^hJd_~+QYR_t zZoeQCiMh{qF?u{eF`K!H?73y}(c1Hk4w%{pr)0PdW_Rkq?7vVmh@<2YvYm{(jBLiV$o(tYS~)Il4tUS9a6 zt1i`nD&>H@PZGn;&en4-gJpxxzX|oQkDnyBAA%Dtxk-0$RJLx-l7~U4LjX#NLhf;B|bE zMe_Zr{M8SHXwkZ24UlzHd8-Ip{DGkG(j)DsKyJgEgYl@$ttjD#s&el&@eAV#LAI}c z*VvuH<~`hnrJS`c6PiX7OIuo_5uUduj3YFuJ~0M2d#D|dj-!qngrny9w8cI{GW95*Z7$UxS6b7rW^6;2f2S8~Bkoj% ze6Bd>YkF(EnL@|mNmA_uc|--N}9rq5}>J+o?`z%-wFqIGMD5ORs(cArAz7U!DLR)_k58m|pj$2$L|><8ywBPsg{ z91*Zh{qbrH`>Hh-R#$rCnwCXJby%?=k5NtlcUHF8!5S;Ykspyop63JvZmA{I$N;Ew zsd3?!ol9H818Iv(e?*A3f) zQMN|+Gzo7LflXb1pjFtk3d;`~Tj*U|xr zqQ>$4h2IkcXa#Uc!E)L9U%xUh?0qzPyH_{P7ohR!6}dOKtN+j+&|C~MU7BcuL-gKg zlUY6-HvT*-w)KKMw@mspeb6M?Qw&bEGvv+WE$)zpSQkr=HS|^a`=E8UB{Rl@KKKPz zV%;j}^t})3x$yTC`)#HhqBlzIM}i*;_ciHXU?fjk@TkIYOtBcr#H1+NPx z!+VTAtE*$9Eedp2{#OeiwkcONPyARmf27^%%df4iJ#dM1UeR%KPF-R;1N96s|6&*g z{|~qc$&ad-BKc8AXU7j*9s5RgQEfwAB!8uk|6(V9-_-Qgon>Nb#3b3>r5SHg<8Qxp z_m8HURsR*w{ynZAY5KV3Mrl)I_}F9?8F7=+rhIu_Zy2ol!R#YdZw_C&E3h%ZZ6#p-76aMrcua&x6C0Ch_-`}fY z@YM3$Qo9(bD71y2mKm9MkMvrqm)NWU{|S3pY=C+`Rlg+pkc_i&P-c zXf;f0FjhY+2VHd+o5~+iT48=kj{+h4;y%x%Zf4D0Ke=`65i!h~^cus|uT)@gA$oWBNUCK!kl$csc zC!Es;AZI`=9YuD!u*|=u+9upr%xXUOOfzX^Ro+1*EJD{A(}Qc!SJ9)(pIKT>v}2?) zj+*wTKh8hDHH#&sO$8K|q-!(!&Jxj~lbc6&0UeYInV<3pOtD&wULXe6VO^UiCAzD4 zUEO!CB=G0U_?PpK>{&({J|bx2di}rF6kc9k(C<7>j)^!YZ_DKr`t&{X_5Bjzc_;OA zluVWP?~#Ugis_(fKfy`Xc7CO*HH%g%`0kD05mOHNL^7^@=2V`9$l9ZD{+Ou8H8KH~ zYg05M47RPy@}srl4mxS*1=sYZWSU{s7WdF;nCW_(2w*v`P(#(*8JH85)S{cXZgm>DcYyGjeN}) zlByah@0a`^OV&%Lw!g#V=g6cDfuslSFXcS0XAZFfIj724YA{FrPuBA+nIEnBuE}*- zXMTb6h!#>492`2Vo*_1?kWOq{Y;CV-CiA$WY`;xsVqVTvA%?`5uH0 zw|y*lQNjQda()q2K2&q4MM3MfwP95+}x8+pXOW6R{F<5uB{Khc_=8%9Bk+ zX%^6=b=*@x+?5LV_K3Y~D@qFmoEKXznDP9eOoBI5JEH&|qIzlE00)3l7m%mc4dTz! zb==>Jadsi)&X`FC=D4l-KGwQ`%o7OTQ(3Wo)PphGcYHEx)^}q*1ANq3XKin_!(-TH zb-tUQFKs}O4*L7I|H-R~5Fn4`^4a0zQ42^sDK_P+HGZRLOH^BRe$JWjaO>Qu-J01i zYse(@e@84H9vg{{6G5>!HP|}MK^^F^b+(cCE<>Gtjdl~%cS*%hXJmc6g9%w#@(%|r zV^kV=x*_eI6mwCeGAQsz={MGzkDHl|%JL-VL_V1Jot{D>^5hcz=@QHWU)fu${$B`4 z_tf~8|CBjo=_DsbV)JVJv5h+3A#nDC{8uZK6<&Mab($A+Yn<2VaR-0tWW`&+B<2IA$W<6HIoBP)4 z?2Se)3kllnl-Ukl=!{3t$Y5?Iir{93R`&D6`!`!wA^ISHp@*mARS!=Bb>g9mv*Y)f zU%c@!FkZdAS`+*r@gk4_HR;=11;)roN}oPV6R}P8SIVECKSw1L^?(Z2CX^QtqwkEb2z$;J>Z+YdjEsFq% zS-&y*XDqnEL9C(RXwh+F%kH;56dM3<_=nbjT5_A67rQSo0B$i8<=zr~ueAW6n%SSq zv@l0Fa>;w9ob-z!Y^%K%KgL>E)bpa|Gwr!k2p6UHi=bV+UpU5$;>bPf_W-O!VKkG9`FTR z7+q4Whf@Q}>yDSb>PmT=7sf06Mx{3MCVUTBA+qrk{$jrx+(MGXixE*}$ z%K!)Ji`SoN!eWX1yngfF007>%Li=o#2wlTf4~o;x(RZ5q&ozh$HKX=@7$8HT<^^(J6hCT&7lV!el!vs zKGA-=nBy5vyH?0Z>F7|}X6s5Si(q)N0Z2@#}o!XLPv$5b~p{ zegZZT+VDBN_MVQI4yUc(Pd{tyjqSvM0)E~PdcBY?63u>$+^U7qoPyF9Ub@nw_0Yiw zdoBAAK^zm-0Q?GC4|d?3j*83TspGRyRNkoMF^cPi6B!1XajKCZO#PgVZFpCF^|n&c z5V<_HP)2$LZg)3(_vW8?P8?kN4}R1>&ND{UC#wTgff!hfr*X#=U4^KpQk!XgvTrgv zqbSkY6z86r?$dbhPnAeHT;CZNbeVvVMj*&p7i{ywyP40cb&P;Q_Ny#S1pgYv4Q&{o z%JDAOrOL#SM<89Xp@`B)_kdWi|H_~5{V(>g+0&*x=yIvujc}vhj&;0NVq5O-dV2KP zi|;-STK4MdpudGbqt_XlUOgc%@@>i-P_@|JpGs}iR(FV`P(>1<$XBKRym>FY*Nm&X z59M?>stK@B*?h{3uygOUufht&<8H(GsY-8o=)E^6TjXNy5ap#8zZGxoa(>ga%};|=P*DGmN@_gYdI)0M|H|Kq=jbNuE%(W%uqI~9rD8}De=m<_bV)n0Zgkd|y~vcK|Is~P zYF5PStVNqH%iTz6=}$3O!Ng}Zr$4zRx)2p}A?{09)QRYNXr`Ct75anw2TF?ctcBKu zhBkXm2WqwrX&IXI&n6~)7wq4+`+@RVt)cCw4W92(Bb{6;sv~8nD;Q9_-M^tykD2(m z_b&Ftn^T{UHJ>edv?NaKInVsIfTV^n@gF=ZM~9uRg5g8MU?<&PlcJ~U2wH1*M<_kr z3iU15nX1dKAnBADC0iWq+d6L1cDLf)#mNKby${cBgBo>r#cMxrH0bKGn5Ro8UegdS zxH80GC+$DA!+Exi6@Q!<69c<JMOIvphni%eFpUHOT7vBK}uwadyz0F)GkP6N+RC?V$-yp=1 zJydfucF8pqu?}~1v^5d)ySTw9G+9Q6Im_uxLXzaHqoPj?ISz}QU)-U+Q7#mYYk&Fx zY6tEGA!4~qJtr-$bg}K0e+a05VV>%LH6E>k^NxoUCzqQUU;(Xz`C=FE_V6VTfE>HC~5 zx=NXiaK_4~VEWxV}%EZ(T(MjuDJ57sZO&MDAl za0liYev~Y&dRnZxUy8(R%YxcYf30MMJgEHU^*e-Uwdnn?;nl#EkdW22L1ct%SX*y3 zx#bKh*7BVDfbuPBaV**i-+Hy06gMpB`sooAeb#9_vl_%WU!?4QpL8ua?$&6(Rfxvz zwdo36%Y`F*sfY{&8dtQqL_=+uuJyc^c#+{Yc`=dw^t%F-kJQ{t#3{+k-F&apF10`iXpbBAczWV1_?D!vH9nP$*W7!Rk=e73 z>vd@t^hQ71%U8yH(EcgsUH;RhN)VY)ra(B*pF*nbD;Ghtp)SetFWk|v)4j~jM{Qz& zAz!6Eeibk9kB{!D^KE1msdDLyM%6a$r>bOGO9u=3`Pf3aRFyXOlP}lWZSE{?hciyC zerFfD-2u)PVW&|s>w0MW3VJWK~8@q??A z<#{;e|Hao|hQ+Z&ZKH4q2?P)B5FkKscT3RVArRbM2X_m>g9X=t;O_43?lv&^;O=^c z?4A8Q-}k=f^pC!Jx~Hp4R#mNaFWXqSzWXXFx?!#q!!NB@tWjGsX5ewVlRJBb2uUWa z{cRN;r?fW}btU+e^;SSDPrww}v*31h4X2->d11wwJBcrKNBp%lF26n?*BJ?(aE9ua zV|6`zb>mgG5sxBZ(IKub1G+`id z;Yb}=rW*3%z`s9jj?vXETgtjo*?v17D&`A~zCI(LE8<;la`a@0}iguOfaT}81% zLio~BraCxiR^PqD&E_r-^mTgDLah`Noh#F7BlRn7_ar4Q6a14WZ}tPx?79lEvOPvo zEW<-HvRpe|?}&*AV%F*X*zRJ5?$Tk2oI)}jw(Ik@@+w5_6JP`P-@@vytV7%ZU`>X) zs84PIu=d$^iM%vnxXXkeGt=G6m6{R-Bbo;kYr9vrKv)}aP}B0aT6^$XJ7#~|3Mwnv z^E=Df6smMuhvW1(qj>QI089Dj5zt?saPKw-KbWt?L5=$whX})z zWZGTHPMd~^2o&2>1eYleA8lsvYCId~y%qND*KwP4-~wP!C6?z+6ixBkcckYX=TNgN zz7Es~@Xg7-xex)W=^jaTAC8`=T|wRnL<$Mk$Jez`1e>u&G>W7YCBOS;w}hUbg7+G- z#HG|}8SWgi$BBu}u))AO_dA&5>0C@EH%&wdDUAMC3N2q>rBc}tJ^3RcTB zV^nQw;^?768L`eFACq_cvIoHM+lp7>Jpv;09Iy=7l(X}-9=^G-)BuDzIqxyx^RNLY z=(XlqGt(LZV0jHD9*QeV*b%Z^`RmGI$kMF*J3f8iAPsWdY1IZt08Xn# z;m#yAuCeVI=eJ9@s2Q@5LzkOtEjthU?DnR|U(`pn1;Wi+#r5^0O83dry-^wl@n1og zk7zPx^(kIlXsdfm%FMAwE9cg(>@KLV=7DQ_n4gsn0Q_v$d}j6C9}wfs`Pn_mi=Xf% zhgV)?B=NWVXdGsh6yn>HxPo6^4Zg`b^S#34UB?lAxPJq9V&r3z(QQ=Hn+n}Im-7mn ziG;eEx5P#a`6k}nG{?|!gF`8d=zC{v^hjZ(BT|>LrBT zNNjR{D8IAqm2E;X+n50o;Hc#*4gr1Uw4D1GO(k1$&JJDW5Y_7KD5ncmoEtm=V4%~% zf`4J5Mau(p)eQdmvjb3TP`g+@Z^=!BYRRc_*=b&F{4{G`&1x}2KQS?)LxKtQTmrXv z0>Ph3!djW2PD~}@V*Qm^GYyV=hyp#iX_f&O=0#%N0+0vqI_ueP%9=em0s}w_*a_t?Oe}|X*ph1Qk?GS%-CH15p zaJL;&|DJ^3#+Nd=QuT_-c<5O0oL{dKaG7h~%i?jNEOD;{6c*hmP)hh_^)I!n_(BCs z&0h&p-$w50p?#!cO7%qP`&|QUI9+V5y%YSGjDq?ccLSuk!KRK$(6;=0JksUR3Bddv z40QB*!4IqS|4k$EZefJ~MhYFB21klJLjzSUz9bumC^jMum6Wg+6#v;n3@@_k?w0FmbRV9^@9`Ja%BRMIC+>I=_~)i5GF_ z3z;naQX15^8Jn7V=um;*HaHk^ettg4P4O=cM-obx7uk&TuiBIu4dOT*f+Pb!2#Mp zk-2gk93*OFz0EYqqWcrF0&UgNjyD;4N1v*sZ-0p`TDi<_OSQ&D)?IUED{YylT7lyr zv)Slhj^s${s1sz_1UCj*Z0}ti&4V7;%OGX zk^P<2D#?R!bVGf8y3+;Ul=8p&&&|yVUo_X-A}w&5Np7MJT6a@*` z_{y?LwpI}M{ItiqG*jVm?%OF!;G8UY&31D0fSO^9(P*cOXsy54o9H2oP0r~ZeWQt2 z<|3L-0hNN6Fv{0 zp`%`R@0{-tS^kTDLJ+?GFEt_m3tQ5%oAuhnJ0&E5yewHaOn}7O>;a`LuWr@bFcRr3 zXXS_8CVdl+C(o7#(GuyBarOgk#6Z}#o>U!3*+?}4a5q5jC30t5T>+p`{VlvxpilpY z<%BOqFwoU@gFwG}p`F=guH7q}ngZIRDq(|hHk`@BO2z822?+_pR~LUc&8krQ_=en^ z+*O;81GmItDGF447*2Yy$X9QLAMEdcKwGnVq~SJ--2tPqwb^ zJlexBgE~yvJy>-jn*GQ4PsPO!sO_xSm=i~UN-QvVR71vRH`PI`;pL7GY4?p+c=?=c zsXpUMg&Mvetl56at>u8#YB%5YD>KXBG-d9MRXE}G&M+8EA`sRH;j&m$B)lvbE3j4L zAHDMⅅ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�BU8G*XPzpBR*etT~5oGz^rp;#uK{dBLrX;~vG zUKVW68gVVyT_fe%VbR}n#JV@*K#~_z;P3B6$hzEgG1>D)_PG)Fat4qeBsrZ<5$Dpm z8^=56X05k?QEANHg+2b1rlUr*`q=l0I8E^RnYUAgebHjY3zr@^p7jo8MpvA3beDAZ9#f{K>MkXqZNCN+_Ye zOvJF)CN;mPs#DApPT&zC|NFq+!EJm~=?y->u$0q?t@0-+bFjW|v{BFW^E4?zC|Nd1 z2J}8UmLV!zr=zbSSyaaQbKi6yxePyNiaAjxvq1?=ex?(j*URfLVr??-7uENuZyT{_ zNMZcDbsCk~j$08dbFi(QcxS+F$Jv!!vv{U&JAFzTBP*q}<^PP+;K41U_k6B#_F+A@ zJXAi>svlkFmzIp}PQv5OewO~Z*jPWyb2vDp^>C;TJN3FzrXQA_P zZ@=F$5};9{24jv9JX$K1ow_vI3H~%C{h0*Y`Rg1a8fI(Y=^QLXC2O!Thnai}(PA7J zuz&t*$aYXu=%cIIs;{$3Jh-EmPLKmQZLdxQfJh6t&pk38tcx^^jhQjh=!Z%K+rho% zvsBh zVu*!??%@c;k12vJ3*Uv<96U}mCOKhwF7K)3_F|!RNge)um)T0*pEK%~@#l1a%{r$# z?$DAYW^H|v$R?7pdJZIRpFMq?O9hPyx3^Jt7P~7Q_DvU8Fw~!;_MXVjxKaO3)>*Q{j;K02pvKT>nsT8F~O-6Y>5=?cb5DM+>Z~yA4`|F{M zA7B)3xByQX(Y*OwZ3J7?q(Habjpek|~T`JR^jNH=&0)lF}41xm0`PAA(}l0ds_ z+Fac|`Alwe7B-AkG2w*${zA)bpgJpI8Z?X+HAvxx(RAS&vg~0k1^}!L)LhYPy1aQP z1<>e!sUTTUF12+blDFMj%aEbecDyC(OJ4$Yt?Nzi^90Y`qerhILb{A8h+o1qx z9P?2i3A^}Y_K4744GD04@sr8u;IqJ}W)vEiLs1`3rvgwEKn!IYShVLGZocy_>EV2& z4#3V{xsT#_Q7iOV@!nHU>SyuJMP<86880^*5~6CxEC`ep)DcLpp4^+D$!402fU2UO zUTG^Yc##vJChR`!EHro{P(kps*&m7rFo>~#$dscbhXZ21((-a1fA}Q&gV*hY!CXF2 z)8mZAvhOEO%tI_B!E=)Fd)C%@J!p9_LNkkH=T?;c=yMTHwDJ8yX}!&H(0{u^B0Prt zzvDPI%A9{*Ac)D8j+&Rw`shE$!qk;T43!DNg~ztwr&m~)oM_GW2}M8BESqT@{6=u6 z60ZwgthM+6FDn2s4(>HA>fbmS2MW}_N?AtLAkO<&OTMe46%Vm^*o23=-qg@~I+sY3 z$6m_|koZ7(RO;mH?Cb_nSRvU(kM(9?oWk`n= znH1-)EZ~d$ly-rpL#0^9xmQXXfj}dT7 zpwk(n`s&-)(y~D9e%?RxH%QuO>iMD`2;l2wA>&9)29V4z?bW#wy>4W5T=~E>&M$-Z z*EF<{<`=NnSUcN1ey5FxDM)x1KR zgs5D*X2OPqt$|~ea8?Rrcdtmas$-z2*X_a;;`kqdP!8TznR;I}6Pd4BDk@>m1{uTI z3lGkLl<`7)e$0ZT&4t%m!m795ak+kf4obx>k00W~5Iw+hMLD-*9fDl zXa}RZWTfe(G6z@`P)m+;dePe*U9vT1rFeZicK|Nm^Pwq67?f%mIARAahc4pA{hn#(DHtjDKCo zy(Rw&y0_6Eh4(S^BQOd8=%1V8@=Yv_9Qq{!VV9v)-Y{h+zp&(QxE|s z^ubYCo6YTOCog{R{MH9E`unDb*$Qo(Elpc!dqkS{J#cDt5Z)kL#z+c>RpLL^9bElF zmp3V?p@Fx)zMi7vCkGF!kCIWuf^(P8uCE7%r37n{$;2viLtz?6!f!+xo*eoWFkw(Fh*@|<-HGpTy0AL5~LolLFEQ#Z>PVV@!{L(KVa8*sY-%ger& zEex5sVj{IXRR2BZ3>J_GdP~~dSARHR(crPAO&nWf8I%IJD!{?TQ zlNJiJv-Cab)7eHo9^#NsOy$!<+X7xn^prrkqFyMJ#Ldm^e21&e-lI_90x1pUUuA6X zpWr8jcB}D!eF4Ut+^OLuws4)Fsx$wibYRK`0ZGj?DobhMk1So#CzVdU@|V{GYw!Px z8U9m%(!)TOc3f%q!1RyArYocd0svdrM@u>#o(WcSm4Zw1s4+?$M#PDHC9J-J~*ZL?{w!Xo#8AuZos^@w}<=}p1;-X z026PdOgH(7N){|R<{VdL=`pp}6utw=^b8mR@LRAwa4ue0D7K4T2Zvx9D_JN_r@)sW z67jV6UU*|Yd0afcbmwdaeiedxe|CDt*Xmt1o}nYa@zo1Sq;wu&ECyK^mIYeW3ADy%CR>btBR zDgiMRZAPAPiaPAfC>}L4A1iZ;|2pOR&uQ+gM;h+^4YzZG3kNVJ)*tRIZI?TG$D-O& zW;8)l-5s~r)htB_bAd%@s+$rFSF|6$ifXj5!gN`51e{=wz@p z=X^Fl^x#r9W%V;Tq>e+ihf%jT$Ngu!qkDHvcvsPBSq+1L)z;7JxzY5Z<-t@DS?G2V zb{h}AYfyC_o%@^@aaF@hI)a5uck62*o#@Ro80c(CU>22L3~EView1{*G*=H|Xd1qo z;}JD*Yi(uPet;|BCG zxQ-5Z>LA@eOnyYT2sAv5a?mcQax@pUIBUk^d`PBV7`CAd@4N9nlI$6ok^)uYGJ?4M z18#iGXS>FY-YW5q!on)MJYjTaS>gcoS>{&R_aVzGrwntc4utW7{)APwYZsLqG>Q|L z@~cYIdsnF1wgaSiUEd^jK|*XBGojNZdNEVjN+ek#`xG3k{DPD#$qh(I$t;K1flnQ0 zm*-U9oUx?AViZwBK@;dj%-`xsIOsx{f87~&mTn10-B7ab&TO;WC?x#eC&qt~e?&U3 zkI}s24sxw!X-tS+hO&pCcj~3N3yQ_TU+cyAy^{=-c%c4i?)GR^`|*;B7c7sO;;fC0Cd2?MMci%%Vo%UvX|kKw7w&P8H*TpG@_v^5?_P)6Tf^(+jM zyJ|OjfBA(%nR)E)*3S$n_SA8HP~;qq$=pAO%t0f2y6DJ0gRo%v6vWFrQ;I0PCZowg zrUepX#u)p=s}H#&aBq3~UEz{k3iJCT78$V`GbJj^g!6%gNfL=040b%$EKKAakgb`R zqTT%qaXenAr|(w|;#B4%)BQGqfu3ivnkQhxt`*leW|s}Vu?wv6tt^5#p-s$Z*=Jri z$2Y1(R;Obr#UGbA^z^!m3n}b}j3ok$WN!^t0Qqw*(c?~!j_3gBLuSBOsd9-93rd2F zhqu%$R;fnX+J;~=&lYH*?S21;ZHYGLm=O!gGv~*wj)xey(;y-Db6Y&;N|bGDPWc;? z`oj(r>Mw%|h2hz(ST|}U*gFT}?-mB*a%Au$W$;b@C|;XOBbi`HY4fr|g|v7f-$K5= zt2)_<2NezZjJJ%poCI%fZtAFUa>A7o+bgwA%yyatx)SJLCwAM^$zi6=J&j<*sc#d+ z>RepQKBbVy5Dpy*bF|;! z_&&dUN6j}&RoHo7CBdfaWvD@0m(z9CW{8Z15jE=zSnAv`ueP83-;C^Fx3#?;_veq8 zkBWL~-nMSEuM+a&>SBlC3Q5rlb3$h+G4n$jc{f zUOCOti>pI(J`X~qyu6510W3dNsDt)S71ibnYPt;fkez5 z-I2x{Tr{SQh;oaM_*YJ`Gx9u-bu^iskhzPS7$0lTnFtTe^AYX*@^b%GLEsvhbsqavKva;V`KBM9NDwUK8Rx^8^!xX{89@C;F_v4zNS$|9R? zDTA4t3~ z96c{mD;9nB;jz|r3VptCtv=bcFueh6mAyttu1NVC+I*nH*B19#b9M6MtR$V2)1g=h zJWA!sy5;D%P1-REpbJZZS_)y_cYu$rzxyR-Azp3v1|Q1^{q6xA3=wJF)7o@c@7?>+ zc@zW)5DPAVN+3l%jkiDF(EILeNJhN|eoAf*>5|_c?OT^wwU`_w-H*C~Ife81q`NQ$ z=M4C_?u*Lkc?9*1W zawCo|4P*v^7Va7`*+82~OubhWqR8iG11k&hgE#V1mopB|^(*x0I~y^q^#`L#@?9six{yr1N49*O~}k98``A!O|RqcYP@wakNY<^ zqbtgNPM1t+{-paQO?#gNVubBVFl&}}6C*F3$ib|bm%9)ZikdcI+X?3;B}Ur5>~Hm< z56j>8pRwuhs9LIlDO9({-C5~l<6e)Z8?QN^8vhhX`Z!-;&nsWTCWkeA;%HWmuNmsPJ>DH=F0S zW2e(OhtS2OKb-rcs}7Dm_4n2|?vvM46Cghcq@wZ1Wb=il`2?ygsdr`H=1$;N`%x=sB>aQ$%$A9RtK0i~HS?bDfBVev z$%32hc7G;wg!4*Qu>4wG3vDG>fj-CLrfK9+3*bQyhzG!{-3PJ6)gy~zOwx>yEkEFz zjpLNC>}|XqOL+hvZT95EYxZaF*I{v&^^*GI8=|OqTvp5t#H!!9zZTxKF@evSJ~#!~(3S`cpCJ zyT=~a>6`wzOcN7-r7>wf&&}(Oy^=f|i6|ePQ{kn@XIqhFD0yW{uNOa9Jy|fKF)R0@ zuds07Lt4vi;5*SP(m%h|yv4y#tslS37-$Plb8R;gWDTx?AxI{~OnIEdXAn=!>Ini- zR|1QD1y5h*w7E3x_@?No)Ir7g-Hi-4+j@y4<`)BUJq_+?W-9E7-z>_RCZ?PGi5VWD z>Y~!qzD8t1wk5q$EXEcaId9s{FZK`k`EA~G9cRhpU%V-_sTz|GqnaGxI^iu>DiavH z5NRW)MQ7swW2N(RCJm6M`N5cDezN)HG_cEB4ZT8_sJ~jGBm6IAf0b7b9KtSPjth}Ib zJaF6oi?IBGGuuuJuYV{`9wkn@@2%^RTrUe7&+qIa9}ZZR(>Tz3B(o7epX$)0KOJ?G z{kr#Xo30h|$m+u;DF67QsMdGS?AJ0D0MW_@h3cA=tkLpqH)DX9SgKX|?QJl?GimZF zL-DmC`7?-3=m+b|&4=h+M?M!^KSoVg_&Dk7H@gib7TOKZQa2APo1sotkZm_4E z$Zdt%(9>b(ve=Bz9L36XZ_y73`-ofob>jt)W2gI& z{OAz&cI0CBapn9`@mS?+Y}5%jNIm};cwygPVp?mpr8z-~OHAMGLMFZ33Z#{_KhEW8 zHXJh#!H@1Nid0xY2|~AEb5S3}OY|QIyH1YG8s`+j&#V^LKD$@NbUHx8-qfQ{i@kw? z6IJ>`Q&Us(9bRrFAhZ_qXu$Aq~Ai&buGN1+@d?3&dG}Q`s$NLI(n3 zJir&ZAnXF}$;+WRcXsxXU6@+K{l$H_BoWpt0h+X~odeXQl7$zO&>vVsMLAK%M@f*M z=2sZ<4fZsSFPdt;oKYhgdd9ynk+4J&73+ky<-v;W({#y!BZ3F7oP;!FWbpN&)TxLc zJvh}>=SH+e21P1z^t8hRpmxr6Bc>ydF!7X3rV*xaAvoGRn}LlB~qXD z4J%`JM_|Z|yzyoZ-jw^rSkEE1&Qy2xs&AJvBaFA~oA|(7PF0J=UuY9hBqSu-J38pR zYw>^mJ1KluSm(2+C0w-(99VpftB%C}uIli*9)FhfLHJ_f*4K;oI30Y_8g^HbR+fV6 z2gm5KIogOvteo6k$7@M9O_UY9-D)pqE^I3xOixKTY z?=6>zvu|4@8)Xuy%oV4YpSfIkTMMus)d&5ugE~(l+Kt zrjQ5F%M(`+_YyZ=vIhCveB0m^sRrPSl4NUfSRCd!a?Q6*qD=^+p|}3#quIXmWxMV7 zB!_@sX_mqFs*ekE`f}^F-Pmqi2@BlJ_mRK*OSVW)XOp^Wb{<_WEjdD?r8lSdWd~NY zD07rXV-@0)Gi);dtGI3|+x?B{U3D&17QjYr_KWmOgSAxP*V$FwHZ1;J=YYwZ;>$ zetgWWmAFx%CP#?fZx~i!l+k_Xn^1O)IF9L~DRj~UXAC)#?ZH_N9c3M46gzQQ!dDDK z4oRo)EiEpCLN`BJxr%75>d4})+Eu^MU)&v5iQ@MO=s6rZ7vmw) z)ExY|^fU>$Wx34WxAwNn&B8J=GTl#xhK3(W1&Mx?jFL*6V83fplV>Y2W2V*R+*8No zZno`S>sHc z14l%i8NHN`Y>mSd^o#GD<2IAFf5pw)Ru$Eh<2;J9lDc_y;a;+1{YCOJjkFbj-B()2 zT2<-FSrn_XHr1}Jqcnl@%szFcg%)voVAc619ZO{`$nC{yDu1YJG1I#dSA_qQ%C+k0 z`FRgyET``mzBvKv`kBAboyiP~8u$fa2NXK7cs!ej68Q!(Xsb?wR^E=k7Bifwb}r~x zg#OHZ!`P8V>IV&R-Qp6iU0PxLwFDNNxir#6{B8Tvu=B8-My-)s;B04uT4Omk3Z|3( zT0SfHK?f(1WmWFS0Ojz;feN>6ZxGPPWe=&jrtWlm`ZGahka$E$)4jw7LY zSxX&6V19>>;eun=c)|t$Dx>H&zFg{Zu|QClZ>EIEf#Sys&DkW%KP!>ZQl>yot|Hbn3USa!*ty@M)mYfjsD7bK)?*I z7>bPKaw}KEwbTla=?FUM8qz{xR#kA-?s@@_rMvYvpovu)bkIh%FwN&UZ@CwBUmYL`(9O2D!Yq@z3? zNkJB5&c5}?m1l~F(xrnw?O4-47FFpsWnFQXi$d$)V%Rn-S9x%&5?3f{FRUM`0zw(~ zQ}tGK%2OU4rkX!3*V5$dk9?!V^}L_ zSFS_e4~uGV_6NOr+~Z>6JYf+ls}kgxe20rkh|T9%(-%>_w39`9oe2vai}=I;v$m}%hq2mAB0S%j ze$=-`Gn#+_Q2b1b;ena5>pdwK8m%3*sz-wSYA0WmshGA@LSOqVe%_YJ>|PiYzC^pj z733y}(A4$%BF_ojj#4-M}uC7xC7m|;%&|&eiWFLu1G&fx;iD1c9?K=zQ zhXSK_)}NPR`kl7K3H~3--ZHAqw~7CxrNynqy_DkaE=7yGySux$P~6>}BE{XIXmEG; z;1Dc08~S@>|GWFVSYG5na?Z^ynQP{n`OJ3)#pgkTy_E}Rt3PC2%Ap7;{CuM4i_XZ~ zzcKafCQ9oi$wW^^E6nb+&P{C>^3?wbOpkKll0s#tcfV^fC{^5*5z%lyt?M1RC1#0U z`=dXwaoYyI1v%5e2z>nBrM!w2)wp;xER7VFdO@D81$EEK{*w4DeJ#_zovqaPxWjQu zFN}1M46W1u%)zlK2~A4UbW@yqIS22yAVc5oN+ZEC*L^2jizZvpThWL!AtmwUjkMJL zuTo>pbBnSvZmItKVQErm@wNcV$tn%fN95$@I14B%ae{=Sf<2C;ME6{Gls7)iMRGdA zu=^F+dow1{j*$F(B=R;Onu3-#0+OyYGBR4!^l}If`g6{xJw4`dC#U4ry%m>`6EJkwfFS2s+GarU>i!T2HDF|T*fPa0fvJFlCsQkEkMhV}IBo;!Ny zi8;|*{6##Yhiu9FE3Lm4>8eJ6vXrUAe>&8kRIw5mSinC;Jvb!mUd+P|cuC0~D*3vB z0b~ge8Ifc0L}#(!)FT|+S;;8Et!47B zG>guUDvaQk?z5&xl`63!3u1tc)_0k}$cw8)YrQ7SNFFs->$+W`_-l$bM_ah8V7Z3l z2vcD4tU7yd906XTlShKj6MxEIYb4IeJIwFdw+Ar-NrM=R#bO6P{zBmE7YLre5HC4B zll!)A(VO~!WTX=8;AG15>B-7-_M)%y)M!LC+W0i0sQAW?R+$-#r7I$(K0<=1)T2Vi zkJ>*j@ASO8--(trk zFtRQY2AKykMOTMF?1EsRtt6mr9i}@@ZBGn$b8Sw%5biU$+*C3OrLXnKt$FX#eA!=q z$ZRnvMAQkwC49=Xhd&*3zQ*y@Ij7C-ukcf06JyXGw#w>c`d!UIKX&?#{S@F;I<}YT zr{dC2uiZzJMT4We4lRyNdqS@n@sFCdCHsYe&%%XirW0Gm)g!Z-5W~DHgSuLBMRIxA7jHE zjL{UWM3e$lhg@WtIbj6O@Il&gm3$sc-R0X?Iei=PhuU0T#MQ*12!ZUP*kj|hpkOS1OBe`vUDgGQzwpJnY1@0zx@4uz*V7$&^>laX$eA+DC)8E-N)U|eiN zt1p>7yMV>Hi&hM_bY#Y6(LKGrW29HVp{)dnmBYsyeJAmR3odr+TEJ_q^uE##mFlIM z=(M-`Ak1y%_B0xs$FP?MWqGT&+smaTB#by-z9k>uKv)`I4Rpg|xJx7pS33u8h8t@z zzcH&Dn*!}u5Sd*L{d#P1rs||$7xgs%Qm>66ulDO}0eaDVsgp&?~rU8oh3yUdijop%?3%@nMvwjRwC6$BfC z{#jZcAC`h!4DyTZ;ZBCrjqn_-FHz|6BO3K$*0+bNSwU4WM~{z0YRRCZ=M_beMKrw$ z2$a-z{@n9!$$yD14!#m~NRAV=MXMRTBU1!l4o$En|o#176!!6@o%Q&R6np5LA|A^o=8JMqZxY z-Y-WD&Rjp}$7L$~L<4j5W#$gkGtaCTp!|5}*)-*`pO3LVrkE?)%5nF!k=_^OXJMrX zLdbxvp|sHN%AR}H@i6+Tw#GP@(vq}z(O2w`+ei}XuuEx2YpRXMymh&b18S}oi8SBx4@^>e%#Xo0V@xnt_rjipNOoxZawCb- zsq;9X7WU{@dI+7`lHcp}u&eb_gcskiuCHhixc2~^6KXv5qB-R{L@-wG6NHwSdg)y1 z3i#yDx4M6`^ZjEfTSTMQ;YthACKz8B;hEJVD^draYzX^I2|eq@1$I0cw>`*qT8Xm5 zsw6B2_`KEcWP(MlAR6jmbxs@Z%CEJzSval}``iv@T~DU9uCYY~EFWK+ki#JUO}GYO zB>A=Byl}ka)W(NC3`zMVF1+)4dxWV0Tcn)p(78#5QujIM1Wl}wZkFo!H+z9nc90l# zr5NzTEW(TO`zhORIS1U4z4;)!p`K@%$eGISW-*@o8A?aBE(6gec2(s^E2Pu|WBuTE zpUpLDS>y+n1}DKyN$NfXo?vDoHH@;8+3#5i&cwWFfN}n zuNF&E;6Ee6VGe!MLMFyaO+JDh3^UVSVOiT4{S~uSC{vm6Gg&^ ziF}*y@DTnupMi$%&#ja6@iPTpejiEZWI|{-%D5fD6XI_w*ST$RBihS*AI8DIx-Np^Q$r<>Y0J^XUd_Y4&RboETJ2Xpb8Aq} zaGpOgDa;&PapNNp)_1DB1fNV~G<}$>9=)4tE-UJr&%$ z0^LSOJ)J}>`z37keGgAs$^+IOI%v>TAz zJ(NKn8%qoGD_7y!nlHxO)XL{db4CtWgg2A7ICgM$rd{<5zc<%V|J6T{)1%rz?00?; zuikp`t~~qnJ37XWK$EKJbHL*x%oBz14H?RaZ_-*1g<|_GwOGqKw-{BcZ}?F12TNbw zfFP+k$2zG`H`ILaN<2zlUk3-p`Me^ca!S`)Vd){rtb|l{(!JLoq z=q96y8$Q3?ZCimqx^$%Ynec7;^d!LSCaG-&=dSdv?QXxhXKOQ)WF&D8-{`o}+NMa+ zq%+s~hi$WK{k~$$UwXv0kv~FHMx*55sqKh)S@Iz<@b$QX6Uwird3zH&fGB99Y?u4r|yAO8%3d~ zR{~jfM!X-gn-CqJ^{sR8U34Q%{&1X4Om=yHAo*E*h2(kV$=9+%JEb^QWp_e=bvpHN zt(~q*)J*OIe9quGoqCs%?c>P+JN>xNYx)tLLUyFH{ZDw0=7u9l*pq~(yf(ZQj?mnX zNNawVK-x?q8_&aH{jgStx(?Q^DCL;8Z*&|; zWA+5_U6bebqJ6g4B!J$9cwJVbw|vz^dRMmid<93WAJw+TZb*Kui7|o8$xnZ*>`jJ; z3r@CZa(i$TWLpUopvv;=p)M1EwmRDYl)w%^O^{tYG=?MG6j!v}DM##nm~=FpGcF{Q z6t-*XnoK>rm~NiK+MQ_1T%kgx)_~wP?o}4tmnzbq^;VBKsq>i|M$o_{(VHHPA2BeN zU~de!?=V@fY#ru%s%)>R02O|o^UEK|%!#%DO{~6c^9~RKCy*(o#R$*tOkRFQb%9H@ zi=r4S6H>=zF5Xu~gHd#o1+Hd_4r?j^t2uDzn#z8&ge-bt=$!Dgg5COa_l;FYRqNnF z48>=-mIM?D8w;UvE1m+7Y5eq$W~Hy@WZl)Q28>9#(KU~~R7f3)z4uvt-|BeFNaI^& zRE;kJ^blXZaIvA68wSLyeRA(M9}z%NGb5r zwcaB(U7UsAL8M|aRZ0_CE(c5;;2k|Xi`WiKF}5`fG!k?o$_Cl!`UWWCu1U`8bzJoA z?y@b6-lDjq?y6y$0r8xzrZGl!(E~3oy(sP4yNdfO(UU9mfke^)C`NY$!LiR;v%p`0 z)8BCUVuP}JsxR$^w#WIt?j#8p&tmMzPIO%0^&EA|C^o>%ZWpiR9=fC2@xOL} zi|UMpJZtN~Jd0-%ulXqYHB>0;eb(Rj;s9~QYk6kw?1qT;MByHNdU8^mvP1PX^hZJY zsi`4dYugbBC}%NWvAP;24hQh9ju2f+6_!@$Q6udhF_=v!IQehUpfd333UdE|_P1mn!D(TD3&N2o0%CIIl-1@K#+iyMrG>7HwthLsQZ=MQ+qzTUcC>e(xz)C z_h$){w@3wq>f`heSk7g;5CiAQ?ri*?k;P*EWY?)udAv<=st)1sL;*T2&IhM3j9mKGo0|(^8YybfgdUS2!*I5DoX=F%LcNA#AcYA5JMzf^)!~NgdzK2b zYi9Hx@D6|(k}L1$gNMdv9u+a~rC#JV7GKJMii3&L)#CXh!X%$X#CbojxyG94Y_tK0 z_Y{Itu(-Rsi;am9R8~$f=Ef2Vc|j9Zuy=LsA0I!{4gP%kp|6}uSkKn8vIk8FL%w+G z@?~N6^5xX!)0VB`{AOe^KA1ZU)?fOszHwp#MBDP~*RNo1q`zDi4PF7+>A`O01VJ){E3KR4*#e?wN2 z7zo7lpU)w`VG5D|=N~|h+l*6Tz1I`m0|&Y$FBrxqm|r~#`H7YoINOdQ_|GvR>c{aC zSN`J~KAMP>l$KV<1gqyr#S%}2bnsv|K`IyR4`HN{S?;k!vokvd1jfUKgaqN8LP28) zUS@7>0qIlCW~96c(s|h4UF={3-erh?CsUPW_ELN7Zm44Z zjFL2?XP7}Lo;}VvVSny)g;YNpK5QT8XDYiZvfzYdr$F|i9rh3(<#f4j^xKu-rB^^I zXM`S}BrGQRRg3!Xy-N)7mzt))U1mcQO_mX}{A`A5yLr|;9dg1F7Tl9@NdcKrn-;Ng zK>s69U{yu%mtw#TK{|H%=LStXn5fc#qR6O-nJ-&oX1F$!F%C(c$+Vj>E;KMGHj&wM z%3k$Ep3vWuwrTi{@<*YvP80~)awrj~>wku=v7+4x95o-gG2u5@uGIA!E``!rM!lkHXdg}@zr zk6zl5zy=fYg@PnFXNx1FM`+BId0$qv`5x!}1H3a!IoGNrrP=kAZ+ zs92Vjl_A(!(kLU~*nWx4&<)g#y*_uX5;HLgk2iyJNuTM;@2%0aIW$lm*BEh_KSd&( zff3MpFE3wWH(M%J4kc-zWm%6W>h{Bro#1=O^OcPbI;xk|%$)4)%!%Yn7F%y{t-@uG6glmQ=lkP zDQMHwFUpi<|TxSAb_w3*8B{BSe%LzgZn01k)Q5c z+b6;&_CCZc0JmQbRTLd-&mz2!ABSZVuXlscwtUIgh2bHOKXC>!Y~UX& zJFPxHKldUOBFpXSw6)2|A4BsJmHVE2kdFxze7pL*vk`R7DKghR4uBn}zWK!uWyNr6 zdT?B8Jnt2en&9Iyc=R!~aI!#SB?_tsG`#A_v z)9g^0sXaI7*HhE##cp|Ln~y3hNu4F}_=o_96L}d&E;|+s{V7-Ci(tp|CUHvyLEj8a z=jFh&S<0=N5&zQ>uBCcoUGB=JmDnN{y3A7Ix&BvXR5|aSwUc9cl~rL zr%m}=AKFW?n?1zk#*{`odV?LB%eoU{{}z70&RRDUip75slA%@mM)dT5NmLV zh7=UGb%W(gC~r^}Xf#$vTIyBj1eZGWZV%;S;dNZlG66`RSGuxqdc@>Sz(i4}x0&V1 z74cSTiQII=c~Z54#}~t96q%oOcg0)J|2WF9L*p>BG=-8zp@<>;Ca|yLu&3H4hatEy zTPt*G0nJ49gvhR!T zeQ@T+IvMXW39h8-mvcD2nIxbrw`a6#lN)~6`JFb%aO}$yFfv{pHNvG8oEO? zIRBKUR_~qq%g`*E@Swm9=TCF*yE6WO2ibb&MITlNn}s;1uF%vg=zg;I6NP|sLaStV<9h&_)sF3L3r(% zpYr9F2ND)Kh6EB^lit_%(1n<5!!nsswiY#;VQ8p$i~qsJMaYtcg+}0~GKAn986I&; z%?a!sUHk9mMhA(kj93gUVZ9GIiewY5>2=zoI&$8M3$-Gf32tkQVmi=$6qdG-Dooet(oKa#4~f9T#WKe2bV@69EE=%L&#MEo_%ENiA95*h%cwwoc5&&DsDhMJV0JxoTQFMaeL{O&2+>(JAvVP zSI=D|j^SA5#xQ-&g-!@;;gT`11$d?6DqevW(dj zos@miO_4`3%znPFNnezbc5{hncKTRfiVUre69E8g)m+)~WzP{M0Ai@44)Q~6vTjpm z;@#YJ-FLn0D7vw;W#Hg+f=BN!XB50$asqzCast=D6)m}o>&==@X8C!%f%84U-OcXV zq7M^3QnNNseWXt{_e?$PrExg4H)x7AkKWWsQ0}JQ=~(xUf}-Z7&laBK8MEeB(7*h5 zh-B}dYd)4c<7of9n(nzthIM@e3bl4lj-%(7g}VL}hV4 zCu*?K8)sOqh|6v4o@7bk&de@wfz~^9UM)1Vkr1%;BS<*Dh?+hDYd{2b0b&Xx>twaz ziP=A_(%1E`l&!M#9*D{_lqXK13!{(3&J@n3oTmYGuI!4^Dv=6KN%>xvbp5Oz(L2`2 z6<=lC_a1(UybEMB9Ft4{ukSS{*`a5@2K*xJ4f&}n<)ru0@4@aKxsF- zH$S}#fEZ9O-{;r(5fy6{p5N|B>J02>sMtwgXEz(u669~ann)Kay zsb&+^D?{1#p(3R}@#r`@9L{%Qz%KJ-Ul-E=zGu`n0nU?}V`KgF6NLJjyXow0!&l;g z>Uei{=5Z8$txcJEuK9Z77=EpO0}h17|C~iiOdNYL2($X~1duUY>78mUGJd_cy*`q! zfiG$f!Sf=9-1@=Mofm+gz5TGa4L-Y?PfHj;74FfIMQB4|x2^BYs!$ueB}Z^6b`1=t zX}|Lr_lPre1KC`f>*8K8DZJ;Baa^o^Ch#e=GhWUz_dT|O-l=gidizvVZn#>QX`S|Q zWT+_1z_xA8{lBcRnm4C2MGCh!PN#YQ#d7sKdIH^Ebd6~o=0mfwLxdy7HEfz~hs4ME zo;>y;ZiXDb3v`B;bvBrCPBCw9UbDRU3qNQpgHot{3BIa?1BleI#NRNU7plg|k<)SO zOZ{)Pp4Cy6hWXc}qZeBA@3nriN<;ApQdLp@j+Y&!Q|w2UCM?l!M&nZCYtnzCDShh> zK{Ly{mg18b+P;Bj)-^u(SecpA;34CS!&c@UNtcxR=GMlo-+4 z)z15e!wReeB-P%^L-)%NN!y5HS|;0Pd7n}FgJ~gzXp29$G`Np-c!~0%jS|nQtS*@g zlTg?@4T}cW504#z-0o0YCK8+7$>FS(H7+ve)s&#DS@G~@5g}JmztOP)_2PvS`+6-R zeX-G}LLsm*{_&+!T^yES^)ObB17l2CVRFeha*C%U9i9d7(+JEP2Tdi@lXNGlxDXcY zl&s^I(&pxg#;uZgBJ5h0Jr&n`K9pZWuS{v5>NmfG&&k%0@K?0FLWF42pOU}HP6~%K zcW@>vIC(5X&bZi$4{&u>dv^r{?q7Moonzx+yzLuoyRe62H`T(1oYX1m;v(0=f;m)G zZGAgnQkh8hCe7=w6p@03v8m;m3!Izu>l1ikdPR4HH{VtML+J2c1DJ!nsD6d-BMf5| zQ9NrCXdVLFQx3N{vCaO}Mp95SOC|n=b5y_W9z=@YxNb2VG}mJX{iS_AZn{|A&nxRW zO7^*U*`yeXkMi4HIAwE?JTOmoN*kW1sKHru{3OXT0n5C4%aJjF9;JG-x7GNb*md_` z8-Of{tc$O68rJjv4LhtXz5Smo!vMQVYLe2WfWcfW{yy>nK|1(Dt)bRLXK?l;wp#6p zvbl9&nI(9$+7mXF+k>iz8EJnyiqY%>X-o_y&uyTbZIt}p@Jq$ARlao#i(j?#C47bP zL03Pn9I=|UGPN?o_aDPremm`z9C4q#UN^{1(HYTl8{UtB{)2m(v!#Q^uN!a@B6ns; zR_)eK;rE2mqmw(GU&7(@^UteHF@pb5@J$*VVy(kp3f*RC{AH>y(sb*+L8T8kwX>wDJlj;iF-P8~?}t}6Ny-Fs1f&zkWGzcYB2Rs0(|_WJC3d%vAz0w8{T_uAwq#JitR zSI5kbLf7;Ek>cT?S4;g*hNnfi1>Jism+zrJ({K|C;6*r^=@D~(@ty1cNc+h6ovrAc zzXU)(4rSul|I3ScxBc6TX{FO9|J#cZwd=k%AL=vaOdlZFYL+)_bV5iE$V9uiM3u** zvwyiU57^l8F3wHoWf!jRrc@1LP+b$+zlQ?0xXA7 z`#IjNW$w@PEb=&e_Q!k{y}ciK0>dx$u6Yj;QVI2OEKUx7+O0C%d2c2NxAVVI+&?;Q zuSZOk88WSv#2Fc$o=N^*F>=hlI$HlC0sSvUt}S}=^_sx@yn0LFZ9zbrijrtFjif`~L3}019GQ)4@Ij-~7C(4g@3XL7WP2@7$E?;w zsoXnV$^RR6i^HZrAiI;@=d|eDP7e)pR}DNO>ot$;h5HwQ>r#GI05~<=&i3NMatlSu zgfTlqJ8V3bE)wflpd>R=k)OdM;PZ#GTMrM$^Dyvy;xYkmlVJLJ*Dd(tytyi{e$J}o z&@ME6Nyf$6R8MhSQujW6Gh?+Je;V6iUW392hGscwTMS#UD~g{uB+IhgR8(&~rKJ%_ z@7tBFWU2{;9?Fae%z0&;P78=D;yS`_2@-B}dnxg5mS#n*`?P+eI^onBQysPM? zL9Y+H%dg0-$ROc?RNs_AFn5w)`qozfc1Mm_N_=SD4H&n_#PsIMY^J3xLM%)&Al?q= zB)A=*b_OQzO@pmnciZRpnnNHFAg{(2bx*TA3TRQPe@90lqg%R>4voT&t0(%u3(&hqUZQ9s&T6DN- z@tj_Jg_Bsw2StmFb|eaE4H4eI>E5`?Z?~U6CR+X zsm553!K}z|Jv=c}p=3eH@*hfYi>cz!MkGuzQp)b(J z9Uju$fi%`+o5$_A`n#=l_9`$H=O4Q7SYuDgn`jU>G zK4@^utIJC6X~0Q|&jTF4MwV47_L^QUAkEZ$Oi3OtwbM0MhWzPgKY`CjVUdTH8Y-?qmOokOATcK$KN!FI^tM#?sNg2|Az@SjA-1JNq zH~-D#`;*-lv(lw9GPs>k#S+6#F1;#i@Ck4GZ11O1qF@@zeaa~IbsuCpaF@02K8_@& zm$)|`vdR4>P49?L5Iaf50?+M~@zq;dAXbCg8vjm)PJe-HZc}U1wi=j3_i2-DiPL2d zAOgK}s;^i~Y{b5YK~O0G#=C3|o$2AB=bW$ON0L65XYGMZHKPc* z0#%tRlp@R4oq~GPkbksb{Qk4*5uAYT$txHg8O+9|hL~L|9AP!DDu(u3q6iAI2z)$(WLD zdPQzJW#7RaH`vT2$6{*qPH&t@oG_Bbr%05=ub5#idYokM%3-b@ElBhKyDLpO=YKY` zX|1!F%Yn9?);I6x%&so0om;4b|DTYU@oPKR_ct!H!6|JQaG~?l-v#(+IdcANef9I&h%>M6rXxdz7&$x zJP*U4UMf)ndv%XXA^V!l$)U`?n1gNyyo+5pKnW*MG^KywU^(5ib4T(8#N+55$Y zQn|qKQJ|P2JJtW21t95W`c9uOzTIJjJ?Y0_q%_3lc=A}h-hkb%`Q9K~kN>C}eysHA zV2Ki^$dMkvY+M-sgH$$3Yz_>`ur+YRWMqZD34T-uGVkUfI4>Ggoz9%T0!4>YCgC;A z)2N6^Sor^)b?)NWe4ODNb1q# zJ!1TJev0te=02BSPa63)n!Dajh;+g55Squ+@ZDnB>T+sRq7F35Qz2P?!wTyRz`EE@ z;%>uXNg^kr{u9n#*)i5LO@4m#JjiO5Ykvp;-u8o#pYfD2Rs4TBXimHLx^sK(G|t<; zCAFF{dp^U)VIzs@e+tGXus~l*<^Xt0tn2`XV5H&(4)Ry2N$F{X+B~s#&#q4UWEVdoeY0k&yRO}<OKy=4F<_mJ|RzG?O9#@_f`F8+i1Q> z@yO2?m(|ub7sw1Qjw~MS2XXW<)=H7`ol{EoEkD&iI-*=yBr|p}j8IDy%8HL4!8jKc zfmYNS+HU629#!NWZSEuW?l;(W+-jh#TbTH43FVrhi_fn>)GGj;-Oy<4f-gEE(b#55 zet)#|p8K;d=O;^NahU02Ap*v@?~{M~*Fv_6Rw0JvU1&$MM(yPMm_jkq1^wF*0dj=@?g~2e*yU^E4NGY38|y-sqxhBMtHp!d z%*BNR<-_%mBPX#}V+8d^RCjvj`G>N~dO19hRyLJSd~aoysaZvQmckUWCub=`(wssE zpI=@Y9e~QPTZ^u{pKiEc1mpjf%RaRND|K&&tOsOznA0tsNlZju<1k!II%FZL?JDxweZE z(aQFv6#PAVeaBhRP@K{{fDk{tp?vk68! zmE@w>VV~B_E7)yy7!~rS7Pj|yB9;bIqo7;judeat2ur$h?osvt!VZ5HKU5Uy3P)Rg zB}UdL(QYs4TGUV~i$cH+XU6SR?X{W6+580w-DThfNDLf43+Dd$J3YQiPw*> zGbCn&zk#aN9&R^{mi^5dD|V^QrqpI4_1J4py4R2Gj{9h!?yaY6*NolF1lXn3dj!s2 z`bQ}wF{XB((xpVl7v zW!iTwQKsYJKPTt*XD|;dOv&S6Begwn0fX<|PGmOyGl7HqZ-#PN{gJx|m2$#y(g z^Xv#9Me4VAgq>V<*{aKHZLM(Sm(h0rcLVsk|JMGWJ^?tI z8|5SBxLBLn<1C)|`XWfa`n~`q$0k~A-;K_AGbvtsXeMvC{p;4|^@!ew0H@_F*47^Q zamVYPkmG4Du9Q7-AX9t_r-R}1$$MRbxwpxP3dbBtylCsYdAyPPxaUS>YJ= zWMu|$8nEm&cQcqZ&YpD#p#+acG{6k}iBGrm6)vwElwId|AEls+{=nRk)CXuMQ{;`2 z(wTl{x_ zLKkQfH-n$Brz-%K%l-V*!;5?3w`EJ-dVSPV3O2@SO~v6*jrdeoO62xU7;&?XVL6~C z%WW)F!U(JF#@9%0--XgYF)i_Drl+5aMp`7V0Ma95xQcVthxSgMZjRMefm>z&yKUm> zhJNqjrt7z@0L;u%SMpgoIX%8}$-}Md&}aG;&l36Isp5{TOuyremNygR)u#{dd(|(v z4Ssg5aQ)u6$$2zV%-L8^x30)u@4gcC%GH#K=xjUSygTx0z;|hihKR z!5NDxhsz>`WQRH{&G61Pq$~^36Utzc_#Q9RT*O0BCkCxDNtB&ZYzf3Obwk7Pi9HE0 zGm7f=S{`9nYyM(WB^PP>q6*`XMi+_UC(^o3P-k|B@$xL~6(0VIB}eYd0LnYws(RQ+ zpYo6)CVQK08l?1cgP}rjNR7(Z)&p9vT*Aztc8Ty4;>nh>jNiXew$;jod3IIASUtm~ znhO^m`1&sqeZO>9vKy&A`CsfEMcCfs0d1+&IqyD9x$+XbzVGXXm#f_ReFft+f`QCl zk=3-AnB2mg|Fl0wkcJ~$-aEX%l8@7QVbyNbR*)}d)!ElWaJ_udv$BVM;CbDonK1NJRX6!0N&{9{g#WLchD zwhfdt9_Zrtoi^?RuZ*^s{w8ME1~3S%gY82-o;<<+aBs zu~-C-Lv(F|Oa((A8d%2dCzv=~e>@!f&SBt5+E5`7LKiJok_@*VZv&Z5MFm`qeU_s& z^<1_V?8f!4j*WGqr(SQf0T&+ylx~jDv@p~cOshMYIug%m}qPcgd z8?(7CM2A%9rx6NXAip*~2b_S4qlr>NxYK9$Qh|f0C*hT#-#3)JcBnl6RU1c}6?6#E zU+5(L%@Yyqe-&8F>f)mt-LA2!kRUZ}4^_!tc1k&<#x3?9U`t$Ex(t}bRjl{I$Z8DE zlzy%7{5y33spd%jS8Mt2`yz=k|Gf(3^mGl6*}s`)&_pr(;t#)i7ft5cT4HL2a{o z%9K=Hvm1!U7W7}~TV4^29-W0?bI`paY^p2h{s?X}&*#)}!9yLGchBAZA$E$YJ zUB1ko4*r3^c3_&0^*H$m9NSCKsk|Y_-u5-TmRmR2yI{y$iG-7K`|r3jt*m__{Y z$)0Oknyiz)^CH5<4qIMdx7`>TEnPT;_yH|#IFg85p8g0*)U5kc)y0Qvv%9uyT7?qA{>aGfnx5Qy8e-7FnMOs6pwV@W+c;>qf>g@CXdkJ zMgn*w)c#S)fT3Ojd~8S+rZl=%QLMet)tv(oF#aWTSnVPLf$B_}AlUY9>bDn81NOFr z^d$CK9YTQ-Sj^a3qvw=Hvo5*e(n*?M#;Xo6e_V0Zgcc12ZQ(bvH;UUCR|b0lt}$F> z`b^#~zTU!~vczV1JLC7E>cOgmN3}n_=I?_Ddwmemb(c=98(92_?lzmGo^e2zzQqpu zc=lwR$++sY%{3QySK*rgcoB!shs|Kzhm`A8Qrl+~)cePl_z_EB*Z0JEvRpcdZ6s_* z3%IS<>x>T+pH^8yDYfCj7Bu#ckITldcB0$)y=b0+Ep!a*m8I2Y=6|{ zv?)eIh3A{!>NM&a5|Ee;AbI)}tYrD&IY{-hr3@PDn z#qNRJG2Wb68v`IhidLmvF$kdW{uBGYvGKY(Y5A-3@>5t zG4S!g1ftsy#qE;H?!I()n&_;v_i8T&ArM3UdHayb=k|lVt6`R~pH!~8u3K@Cgr_JX zyK`2z4wwHUVAYEgqc+K=gkzwwSoA4LZUV$aObf*r^Pw|t5q36bm`u&#OO6e(re_Ha zZ{ueFo11Lq4--6SQi-@-Bx}9a(c8{i0*9%XNz8q%G7R0abjFPyUSf^TMO$fs?&>8a z4^t?Ly41JXr*m|+29fnDp__DJWOH+#W2+7raCBcrsR*ts+&xjzuEXX4bxo+g^YGf(oc_+9&u_Y% zxSVg|3`qH~D?8q}$5?H~qbd562?ShG1hN?u>37ADvl88sJ=i5N{pvfR;`Hp`iB7(E zEs!xr#|r}QwU4TWiNOIgb%w3vf;Ns0r1VAX)^u-CG7*agD21P!uiGYT;XAVU--%sq zt|DVow&0eJT&_Po{XP)-bF3leH0*kIO zR$4fMIm~P+n_T2x_Xck&%#0JbE}HGp`dlg$&8%MV$cQLp%vkF>`qOu}On! zyPbIjh?)g2e%Rr}v1I4wV>`A`en^uW31Yd@Jm*;ke_?Di+nm6JUK+;tC6HOXuP zcVF^CN83B-cdMPYJvr0HZ%x=$8eUE_-z4!|+()rreKT3y_Z^Ww8|>yYYfh*OA5WuT zG}(vk-Ftgq>&;d}%tG(FQ%hLX?7aDfC%OGwK{(e*q2DlK7nX?3^4RmwcZS%gJ;U;M zzS_(#Ury+~0l$4bL?2MSYauGNK~v*;@AsP<7}DOaAAeT)N4c3Y4iMM_7^ngP<_AND z)$1`&Bh!@DnUZG`@G*SLkSQL9{U{8HI2J4e!5e-u3O zjvY(wq>XTpKfl2!(#LDk`2zYgoA-vb#R;CE4Oh@Up!Mu?xwQw0$mr)+`9ab#|2>8O8|UL=%?S4UmH$GMEux-%7eAtd4CgG3VQ9pcE}(Zbk`NZ)u`q+ zSdC080X7=VFs;ThOeJOD2>E|BRFE-;nuA5Y!QNU!|<6< z2o4e1Rxmv&8n-@_84{dcdpa)>*cN7yfWV1mp|gse!e2~AzZ*2UB&5i+a(Nu! zrFw8*dEjbGKgRc{(Vd?=Gd_2#RSHAmSvzh*uA*(u1cmV8Sae*L)5YcGcm2p=fA+dN zrov$n6pV1bEwcxg)Uw-uMKw=ja##P-HM~Jklb~!%7Ul4y*EeH_=7mlWT=SmiuWL zgqoiF84ShIwsQxnjw^YuhfQJXalej`Vx!z+ClP!)V1V3mIxN?zPDUh$@91O+vVJk9!&Zdos3sdXlT>JN@NnDpTK?8^+VP7XDmxko!!`CeW4$6&dN=izV3y=s2W;>{JX?by~z~Bj%U@^b@Pb8lnXp`u@sEL1b zJv9B=wK-cEG0B<6eTS%ctR{%Tt{ZaW5&} z0!NYwFjkA_D*R<#SB)`^EbzhA|{J{sR6SbN|iC>S=*_ zX)CL5nLuIWSXMG^OCW_6*{AnDhty)4w}bPntCp0sN|BnH;b-yS4vPXDXh6w>Up8T# zwZTR`VEKo>CP(924DZic`k+yARS-q<=-Nj0GWu1C_KN-3YS*1IpF5`a@+29B0}*z& zwv_Kf^QB||&po>r!OC({+`0LTzV$ZQg6*eY5-MZ1oU37^Ts=@@?_Kukvw%~4FayP} zhv62qWViRKcJk3gu)stqriz_#z5Fvu>(A6#Zu;|R)!`^=rklY1Sa zk@?m}D1sWS>cGXq(A~l>no_-c_RvN~86^_o9Ur2IYFWH~Mz>Q04cez^H~$2Mr`Pgg zM!5Q-r0SuxG%m4+(EsYMjW1f`(6%Pc6tjy}WqZfdM^P#Pp>3Ie*eq~FMV6>d%VmBk z9DO6O1@g)Gdrk_t3+PFQ?}-$?@#+7XB(2qZaQ^k`s&eCozLpy)qctk}sM1KJa(>Z0 zyHP%E=IrZPOKS?t6GxoWS2rJlOVf(IExz9@@P`uFo~`P2pK|rRqfS2xj7RP{lgU=1 z;0;WVqNi|~e5j^s#+iusdZKNG$d{5P62P1(Lv$>gUQC8dR_3Ae8x!eKK{tvUBXIj;0!-G7g8Fo`{CUl0Z#~q5j#`|~>pYBG{j-%RXt2iNY z>eaP%UX*O^uTE5C?vCNzC}=n~g!US-a$sG#5rYnr1P7rB4{B)>p><>}KUJ)a0nSNwDs6+=JFIF`sF_%3oza`O#S~m zfj|m*w0WL5O{rC}qZG^&Z|_QYQu&^|E_lFsff_D=o1BBDt7&ZS?Dgd8RkB5hXm*|{ zmlJ)n;_g!$AF=$GzuWU!VJu_}p%BZw_O{TMHr}Lo4(I*Z8&>x%l_bCOcdl$)(CLk_ z*l9>WFCCwt@#mPiBuwJZkZ;!iMcG@2MfF8(!zwBwB_dtYN|$sv^B|k9YsUHO!o|&pv1Gv*KR&UW->Ul`Vc_75?efF_`KR z|1ZFPjRwfCYB)XHMO!~Kn)Oo)W@IU9TziB8x`n$yW7Un1M0`?Wd^NSp3fT!^G2p+o z0v^}uD|t$aKbgHBZ~4#I{x{Ts3x3Z+A;IvhbJBl%|BpxG%KVx9ZsA|>C;u0c0RP&E zCD&>d(6M%9FNe?O9$Dfe{nM|pF$bQv73IGxt-@hDTCOO1pS{haly}za+wvN-YX<}( zaf$LG6SbmNeH6~ej@i*>g7RMr*;J>wR}K`SfA=Y~omVg<3sjcR+kNu$(lIuyM;+L& z+Gey`uL85%&+w+l*qo7nMRiMBn>m6yqovDGDwI7!1kv2|+l#a)DtX;pQr|2?T(6a` zCzO(Wng^1v1$5&EO|=gW#03{+!6ms`x22;@}9 zExVD=kk}YabNC}mbi4`}f;mimY zYX$vO8{248C4k<}q8z-r4ubJHyA-wcm~uTt`e)o-=y}p!__^KD^!t}}sNIv2-$M)OGa{Rq zie277>h3x-9EIfx_EW1V;TdDR!<(XhM(hR@pxj+0oLydIA68O0J_({NCLr>)2%aJA zAJiRYB}Gwl_ls8|H+}O)BuNe}2LT1*eA>ghk7QrhH9Lh-CZ+{DJm7tT0x?M8C?)c< zcAlPY#F*F-ZRN{Q01U$&pZ9+OVvo~){PnjE*GMQd>Ur?HsQD5)1y6jAcK$V#{PD9M zbPMxwIuSXcd9`ZXKHj&3c3ZYWT47a?FaSvn(fCZ&y~#bVZ5Z-SiYaYOL&-L5V5&@x zucIH{7ss)f!nL&Oi@yYB~Jo(VpI{l>Pp6&Fd)7k@r zqh3cV?R>LcO82%(h`o~EJ)I8f4(P1fn@%7eG<=3Y7ZPFeZOLT@ps`SbC8YSN;rJ0# zcoZMq!W};V64+C!8aUMcr)b{bUIAiZ~oMFoRD7Wt!AWopECF3p>O+;YNZ1^V2QK z58;f=&Qkkwbz8x2jkP-9%UUO!vC=vw^b`A((NJqKe1F4O`-X-ZZaIznG|-MZ+u6H6 zh-kQQe6hIm9(#519U+fbcO{aQTegc7w$@tFu=1tO;9k1U?c#;T2_Ntp6sFlGD9`gS-Mxw(b1Fxl6 z8k`0{ugv46W*tbo-Xl4hcyCl4R*fou6&K8&dL}hE7OI}$@L|O|v&tmx1;;qTj_T5D z*#v%NqkUml6Ov9Ighma`=?B`SVl|N5MI7Gro6j9U2?3DH5ksq%DsxAtWFZWui%h=T zR>f$Yup3TxEp2W5QB_?nQ5)s!hUDpp%uJOhf}Nh6@^1wp#qL;OjyNX20q$%4;h+W;=7|4ORSjM<|I`8cPIf0EhMSN|vwCF3HWHvX$Sv3Kd4v ziOel{g~`qK;=4AadQQoThKeg{s=7*Tt7V&31BFfik=v%a9Vm?d5Y$r%Kbt_^%#^;YZrrKOJV654rKYR2)7j=<62 zYNX3YVz-x`z_JaY?`jnb|kDB&e)Y$iyLUJ?{)q|{!F>cIg&CP%BC0J6fxmA>Vj zsMm^&BIN5?lX8VQ)b3kV_4WyzuGs!Ev5YIiN|A%OiM0?dOLe?J;hl4EZ8?XGSX9_e zg3SDxUULR-1f^7)VLt?c^L)UTU$Xv^%xCvnj+yG@6>DbZaAuN2#}9DL+T65*a&TkE z8<04N)oV=CS!bljH)Gx+|H@(bkT3?W#S82VCE?{a{?hd5NH3t*Emx4_7R#ANfX$|e z1Gz?YXad54x1b~5Ip?`dmM&+xp9S-&8?Bh2d>R~-4{5S_PXt0En}-1RMt@T|yG~Wm z-b?`5RX2Mo+$O0QbOwcrlJ(Yhg}XAyx8Iq*G({e{+IqHlRi&6Warp4E%b%8$ADn!B zxE=no1&_m=ntOtCC{NOtQr2G5&3MS+-j*pM4trxBZ;d$o^ ze%4wqNR9(#Xq}`rH3{LlL(xBwJwCCJ)V$(DSqTXVQ??C8P(o%VJS2whez!l``M+D1 z@x(jZYinI0800iqRhl}Fu2-IskrAGfH9YBd!bp{(GCVq#2d;pZ(MkEYTH>FX5t;n) zXUF(I^CT2PL;9bD`J;N3g#KH~f6n<8AmM}vFDIMa@ZIoYcsE2V4fhCh4@}l?eSW))%{Lnzr!JEfB4i0K;L@0Rn z2tj9qe(wktzMt9C%_D7&;`{nlIlt_h^Q`}LXLIzsXwm?&nbxTHe*+dzc=UiCaDh}b ziv+mcb6(ID-Mqr?81AT%kk0;*I6vC5qds7$6Lreu$oHqTWhz<(#3BHnUbiALYhmue z>qcD*i|~>XqKlE50!TAQnWslQ{PoF(m;Yn3#oKbEj2g`_)JFFa0<{Q|sLajvF1F0L z@eVhpJ0_kxk;5hd>q)$2_jH*q_T={0g4I2!WKIxI?Y)KA_lzp(3!X^Ue90VbT76Z8;+FXCC4ckw166 zyk^-^iV3MtOwl=h8hEm*+Pcc5jAnkXiZ3&UfQxkp&ZcYw8Dc8IA|3+ci*__6X1iiL zXq4q}d#Dk$c6bb^h|pVxyG5yOsO22E&aSGOeaxO@da*^?fOS>|5@@x!S=xm9v z>2XTuz4!Kb8&mKIzWY_9#<^u*=4-lo(pX$l+pP>SC`CsBLB^P- zJYShF2CG%Pm=WCXk?~}z#u8j4c7?HJ4HrbuIBz%uAsI1E<-h(>aeVBSqP&dB@Kwy6ssgg;kY=SJY6tT@5PK(cX|cAqA8Nwyv^g5 z8YMCii|656O6}^-*f+((0Ck_wY}Dn=*DkI#Hx}Jq?R-(^IO-XkBUthUReLxgKo0Ob zJrC1RKi04As4@ERKfneP#}858AnH2hA^$P%RwM6#-07$*`3oOwkj zRB^}M?xfN2YfZm=0e%{X=jgz2SSk&iPh7~+3Ou-L{i>uj2VX+G6Y!n!<+Zh-S$LIB z+M-=F@yC^gj?}P;DKx=pp3pgc!OwP5@uIy$y{ntr{QFb>t1C8+Dq7~|sUIVZQr=`m z!*8x#h&tP|6pGbr!_zzO8gqv5K4mO5=U461J0zrT2I3%`EmihL64r5#N?WiR1Lgi|)h3cO z-u2UphD$Y*luWv-Zc9$#vKMVtUUJVIGI>?JH3qCKX11IJc%yxMJOP3hQMUKDZnBiO zoxKPM%xxChhaTNlOmHkcuB#!_N8iPoes`+&`MbTj*1;`u8)k=jQ?cl@;Qm~$=CPr% z2aggJqBU=d^uyqA369WS<&SQ-1(g>9-efx*cD3)8i4~S@4+tTy(41*Bo~@wq#tv> zIqk%$R5|7#0dO2U)C`8(Nr#h~Zk{uh1ttpbFg04%=any>9-{-KPQ8%5r| zzG0V35-xi@*oVcvxeJ)4JK8@QoC@Z`jD0Vb(LK{}I|Irx$@dc zon{O828HN7kd0L=t3JZ!Y-V_&NoUn33~Qd$ttO*UpQ(DHfQ50dZGUcr$L&N{X(X+v1lJL%BfJHEcbK-$U6WF_D6~4o9DpXfUP*;1lTdFt^}- zol@^`XYk|;xgNzwfoBgdES1@++hl1_TOnLgu6DIT16%I3Z`ImVS$#90;YbU}K-Rg; zKj5IsBOYuh%#)p)duU1(<7TMmNs8Iwu|dJVG)-ZrE)Zr*+4NVtkzEvq;L(wt`Pt(CJNP)2dXPPB{zJkqIp(f67CT zn*}U51vgqv0^dwZJn97eEwRMJPaX{8m(1wKC>Fj|kstHFv8c83HN<|};jA^sYa;YG z(F*pbOLaNysLo&yq=bIk=I%!Q7h*@xnS8|9X})|=seUMB)o%R~mO@g)chDN~J0JMN zd^0dw>X^T#j)Xtg{wj?4_USvzz5TG(>W_cH_bL}(loxtVH3#Gjm7|S^7+=ea*UE}- zMPxHqB>bwfq)FETgzXj-&|hmB%&MnyA8}z1^>4HxXXf0&Yko{v3@XIsGjB-vD_T?!``K65C~|&0=h&M)V|8r^F>m2?trNnmke}XBYJk&lm*E`$Ii=&9)l$KY z%NcgK=z9=(St(m=va@S2%?=fbMsu>Q8O;JWf_fA}_oR3w_%eahG*4bTW5}_##-WEX zBn?^MaJBf*`p^O7zLkyg&a_`#n8f-=R-qr93o|QBaQ_TK;>v~f+ z@kHG)`MD(-vql--m6yURd9C$ec~X(cYI|{(t???mT4qXW9q`b3{_kCyxc4vYFDorK z1W&%TnMmh6dG_pC!Q2UI?biHiblzzCw6zUf=o4P65VWQ#^gZfA4*xVzd)d zR7A^wW<-%z z54qS%pT4mC53)$Zsjz$pP@dNR)cIJv6LsMBLUHB-`S=N*b@%aPw=CPaLkGO*))|b8F$WO;l6dS->T`*2kL~FOsvQiwc1}cDbm1aRU`8w#|!) z*J0TY^%>6xwv9=N%^$6yi7!{&2vy!(GS?-%oA-xw{W}SnS{G9!QlYKy1}xeRHo(ca z`uh4Ip)#Xf?tQW;x*{~6X|1f+<^UIR*JkNnCCcbltLB!^KR?6{(Gn^Z$3Z>$@$kW zsZ~1JJszP}pAQ{=KiTXhw%YF<=C2A1lCLpmK$(Mcb+$BH2i5aBHf?W|L^8W8<@r)l z7J~!ra2n#9qrvKXCIib4@v2bDBtTnc&Sm!SZ3XlRflig)O!wuCdIxW z(IH=^1MGhfx-eTmt*_i=qjFJ`*PxlznQ~*5J3f6tU9EV+$lLPFlxP3h!lvhEfh`u6 z5hJ3q>+m}bt9P1BBdc}WNcC1;an#>i>@HDFeh=larCcBjv=9rbRk0xyK%?|_ZN;r| zYh2%h+8F<`^zY43X4DJ~;LMuiEtka@5}4)YU%Y{9M|x@+)ghI?7(Y#l#*&d9Uoh#S zKn_&Y-^p*lYcmw}17gSo)`Yqb5?D`3{ZxOYBcUBroqi?EKa_0#sLEj~=P=g=pB)w# z_B@(dMiHgo09c|Z&o1jumx<}$f%;S-c%WXjO5nlyqXLx#Yl69^CWDDGO}laRfCa8U%bv+aE`~RZFCP} z71)S*GJ3TfzNlU?H}Q$F0wb}IXt(S-$&)n@?al7Wv|)fdKRKUo+sCUqYHVNSb}!uM z!cO&<9ptc!XMQw9AM!uE$oQbi%T&Y}RZF}b>ut2+Qpn2=q-_xJRI4`4>e#+e`IQz} zP~A+A`Rd?~$XtMfE}VEW#!Fay>k1K;yI^Kq9YtZis-}$E+=6QYl6*M{5bnOPYE~>u z$0=k_bm`DX@3&aivd+a-|7^cXwMB;OXQW$VX(z zU?NXmc-SZawDh<5wO-JEjH}vJ0jA7mm`=IV`03za z%7{8vM(Y*c8DWdSUDP?^NDg%8y#zfe@wb!3cW`Ec7g_oa=8EQm-XD)YLp#Z#^w%R?Xuo1FgbLVa%695fTTiw_cE*-TKY8c zHMXA|ldI`-a}Jw{dGQfx9j1Y%4+$k7Oyzp*KICA_lV_4mlyb@d+nN(LmJZ07^SDYD z4vYIzUs{oeYSjbo!u+yH-@vOQzCjP+-u{?jef)w|Cqu3)TI}s6ko3^~?M)p3)au~z z>_L)UVnY=2G@A8p!6jwJi~%fqrSE?C-eT!0fau^31{Cd}8M}@@AG+mD0eQi5bwV%^ zze(Kcu@}kl{N|mPd#f(Q+r54V&jb7i9#|#)sjF0mNFD^jINi#;t=|^6-ux4p+f|6J z{jTxNGr!f3z@v4wi|=*Vz;g!+M9pUCsJW_uQ1cn^m{k#K-#|0(EOway7BDd&o2DZeFCP~>dO}IQeeo}ag*RW0< z@3OQC&*Wow{|MGGcE}r~Of}r;ln`d-NP>RBb)Gz48L*&SmFZTfJUk5 z4X5KsDg_=!_+DSMV3!-YTl_K~mW5-@kB-6L$kF}iyBphUnO9{8OaTQLime8!F`U3g zc$!B=^8bnaCH$Yr-@k-)5!A#?ABe~=bSwg?lwl=!=O5w|@=6Zg+_U^k9v4B~fI=-4 zxxRNC`I2M62hc4L_=k%CLiZR8S#&}LEY>4a{drpvuSGZomizv@>w7#yG!wX?i_rq5 zNj7C>9>=TE%ckcP`};272Pz^xUdS8;K>RN67QP(=zY{u*@WROH`d74YCU2%SF`ueq z;aqba9K5*Ds)M|?=%ZsUaod>7F@!R{cUf0hq@?RVbkF1$ZZRA!Jml1T79pp~L%EGyOi~W&(JBS~(S%k!QORt)z znZLs7|~4mI_Z# zsEf6JzZMvT65ctXDQF)EfmsDA?`v%7Y(&b1{MkDeVPc3FC#S{*@_T}y8+OjQy7PozA!amf8lbA}~Y z?jcF6#rwh7HTjb$M;9JTs1`3^+d%#6J4G5)>{{9Sn+bBZN-P<#Vq`Is1Ui*iec|r$ zvax*Y854$?#3A^e&MO1-U@*{@yw^7cK;V7eWwyZnOb6P@m~a{L$%I7e;gml3@EA_^ z!teZDmzn)DlzE@NtnF-Ga<=C%?ZSRtlO}~*!E)i&Y@!ljUzm@HwzOb%3pju9VJ7o+ z*z7wC6CM1zoe|8RrSH&@u8{AJmC-Acl17!glxo3u0kB3eOU3u#h*nH^7@$Bb_bL1t zkYPN%a71$2*e&7ZzuA}0iyEG9j6Y1Ie||Q?`5~*NJ`_&@Sm_Ftu>OGd zyq2V^8eQl8fYOVrCRcjT=W11GM`m;WC^`H)$c=0dfR0cBrp{wd*4bKP4`|(ygy!(Q z)DD}c7miLXS9fRKlFlgG0;_7`SaE&{p9QHa(xSIlj8~(i~vVSFXBm=69g+ zLKr%X(sC&tx)z9roh~vfXs1#KP3xqJQSp*n%K@H%;1@WGf0si|U zy?Pyne3C=aJWzM{^T<#f`V2f#D0(KWt_Q(q zMa}2QBVHOh&-C3z1&!Q27Xn9&4n`U9=bmn~+$)(54HW?&@gorogp^)y!-FvL>6*O( zUk0b+aySKDlKRT^S<@v^zMl`LGe|K{ii-V!1&9qyk5~ZL0HfDbcbokEh1Xe|Cx+1z z7?Lzp7;QZdjoF7D{KpY`$J^lEen5%8@L)yr@5wqv7NtCPvKdcHdIuFk5Pv0soKsPF zT4d@xyfSWhq~1f}8&4s+*CTdis>5kahUPhQB!yRmuuZS2G<0Lhvc@_C`L8(M^d;pj z8{KY>^ryKy30zMfENNq>Q?VpFRKD$IPilLYU?znpM z+WV~|EHP1-@C%DGuAlL-PP+_H8+YNk)58G!9&eN9$OFs7E(}0DQJ%GHY)K61hFg_5 zp^ox?_k@FDmj=e}a@Yr4gL%1Ho>RPjAB6?pvqSo>9|7T^joSWr=kd0UKwac)pp}V_ z(6fs0;1%!sbbgw=y|oq;pBfSe&dXD|y^#{ph1o=3f3G>0E6;U$<0yjRZM##Z6t-ZM zR5kpYTwGBXeN2tmyPZ*iTj$D#AN~qke${o;y@&AX?DoxJGPK&>>{JLwX1}trl zV6e^ud`aDpmgeQ#wsb2~I&RH0GN9#My$KQ+eXc`IEBy(mI_>tgZUz%&-$Gib>hofM z%O3bBUpUivIy0K`;2R#iBHI5>X`yVxnZNg|T?hX9fVSXPTN*CvX8Ed%J9v5DG_(+e zLXgBA;DRR`4Z;>B|8YoESpnJL2uU_4ZiMghy$_^*! z9BuWwR%bfSx?pSzSg<6se`J9t=*t}$o)q4ut1Rjh(l+pU7bpk2Jj>*Icrw+3Av9t6 z#~Q?O6R8bhxo(+uFG;46oig{8uTV_q9Q*Xq?l)2(0TcUsj z+xMdHFG$-=4#TiS$O@92pC8p>1E!hEU}j&l6xu#Qs&=BsMabs4APRSxG8l_Ms&?cM zmY24B1jJjZwq-rR*+hQQ*Sc&n0Jbc(22{GYcq98%_sk3e#?>doxICTDGx{THH}(&iBEp;)4~LTPY%V><4T`&~rh#Q|UP)Htx*Q0ui;aQ#m?8PZ`8dfVGeT60gh z{v$#tuzdhb_<<{QWf>l{V1)ZR^}axDjf_;@$d7W@Ik|sB&32vg`}@J@g_^C|h&l$d zxt%kUh1(FZg^lps1~p5OIO`@(U>UhaevSjEMQkXsR7Xc}=z9M3 z?7B_^KMPgAhP?FicqfnI*U^4DM>lE1Op~g5CN_aPfG!g{e^Xpt{{$_j`vkSP%JTcC zI!ALwdX$@Z(r~z#_*PT3vja)|n}h`9JA??F#GVje^g3z;Ezd`S9m#Ny=ert*w-4kKiQfYrIO<{!V-g=&D>w^Y^9GDC+q-ruo4rj*AhgB)hfnRq!7q?$Kix2P2 zO#2!|H;JqYcU6nBqdGaQ2Er7K0!#Az2J0$+6Wq)zCL1x?8eDz@9;)~;BoX$6W{n`2 zu9cKl-hViSv*g)Tq7}3Zps;)eOxS>RrFP)~C!CE<_Q#~oP2hnl&-OzDCTfcxOL=g*Tn^WQaJOKb3zzS-(T^? zReEuAXe`*GZBt$jA^4Fd))|)MYCiw&HqEE^Jq|~@gNrSH4d+V1ADlU$;n!#8o*~7- z$hY64&+$0w-BhZ=8Q)GE)YuL#bf*luAJGH46`S0ajj=nDmy}sMYgjm_v6GaP-c-@# z`?LSd`k>1cZ`s{)V_Gl>uv_%<6lGor9~i?>QBk1*NU_KM!J5IV*XLLNLCw9z;Za)~ zKSJJ;H==6Z-FdJZ1u<15V7`V(OqPcCi$28cpuU;1u-W8NMHfKgP}6d3$I!Xa;=9$yM(zWD#-EqBx3gXyX*2`HHAErL>Ap45|V(A=WOrb_Wl)8zcELD5L@5P zmFpgP+5#X2>}k@y;L>`NQn4TPpa(f3eP3{KDK4hVJfty+1N~*Th8#FS-DRAMQ~%_Yc83{5m7CJ>hE2uFT;$j7C>YkhtV~ zYzOa}wedS4s{H$*qO#(jZ`vy|!P@D)7Y2UzTHq#o%bO@SWOloPX(aET-QB@!CKbBO z?fEyNn)4Q)70eNdH0z|?{VuX3as7znTE+I?c6|lOzC!^|>qy3`Sgr@OHRPw^IY z;RxwHCq=;Wlg#VD$P2z=)dmvr4*W$g%a^RiL(4HH{03<)@$`d`9|};yfN#!a3!kk` z#krNt42+JEso3Zu%EL4Y(rkDd4y2@28iTfups9TI7GlP!)an)ndyK033el4(E8p@Z zR)CY13^Eio3h$>toa|V0)i2%>5=z_ZPL?;sfO7N+N_*+(o8LK02M$|qwjF=WGZE-sky}oL2AMuF-t7`S!q7pRI1hJ#}xc)MTPp zuRAbkbU(sj`>-nSwuYb2+-K3LDsT?A7sJzFVn8Jddy~!^68>;Up^$^R%x0Z(2hXPe z00>>MCI^RPK~o?{prW>%IIQ>S$i$wpqL8J55Ym-yampXgBWh>oGn;M#^h6C8H4m$< z%YxRp*G!0#mH{rfeTSJI!B6)UVEYz_2E4Z%*2L!=7wZJiMVzxB+ZL{-w|M6S;+gR2 zgkF6aX*xIFT;xv~VNB8^I8$l8X_6nrZD2BIXgj)tLZ^)_jNW)GvU)NfVi9|-dXM<% z6U;dKtTsk2X9sVdZVg_)UDuPafGi!?6=@r+B43@)#p7)GczKwFhlEUo*YFuo0V`Gj zb#CL_eiaB!Ki-&k(eV#uEChe(*~o5|MRaZgta0TE&LnOWk4Wk7p{lTO-ohTb({Hek zPSR+S%P>9^vq4Xbefqia`zkFKPGaUYk} z?g_!>(2C4bXavc0VEr3f%3#*%YJCj6P#lL^9X@lJVy_ITQ2gVj(>pk?QJ_8cx$q0IhNe4 zBcrUz$ZD8RPI%c@9clUa0L%s;HYGkX`!Mx-TT(MKGi~}R`whvLD7aq_Avza(#z%I9 zZBL|#222uEQyesYsW^p(goIR!Ew;M+8eo%2A2~UiT(Q+nr9unNIWexAqxG5HcitRM z6E`=f0ab8l1I=R7(gx3V##?4fZ@@`ZFPf67bXV-B4u{si#9(G-y;@ah9QT?2^3wTr zS1+Az4>X#^CT@_!ny%t(&o!RN565oH$g6Pbypy*(JL#ckHDG7n&YRbQCW(WonE&~6 z@wZDq3GT!q^mT)OoRlGW%%bt9J0E*#etMr3mC{1>!Xxo?!QZHODMdmX2^I(%Z#eu4 zir58ppx^gXCvuy&WSv&jDjF4g-H`HMw8eVl=O*e9bkONeYRFBsM48`cI5n?wL8s<$ zlb(pX+;(#;(HnFf2*2a>L<)s|Ib1Q|Vx^Dq9XOv_o1Wk%d{OLrN8(A~K<|^9>_55D z;JzBxq2xSnmHCmOLHZgp{{pWm1an=>bKv-$Ub&uRH3B_bk{ z`-$7>nF$6)Of6LLRr)yx4F;EyG%;bxkt+Ph$Cmrzqb)YPJ`cPd$GW-V+1!~ty_wgH zgS0^uty6xdD0{huP-QX0fBp);-k-MmiCmvaW${ye-k_-x8x z*Xg3UllV-!pQV!C|MRW(S1HuT;s4dl-leYmJ|5-{n{Ovw344N4D1#hH}Q zh=Ig&IPDE_Wf>lE>7y>TW)E2g&{MXk$cjTOr`cCw=Hk&9TlVgUxSmjMF-nW%8}Q|f zrAwQ$WlM@XzofUb=Bhj3rniIGwd*e^-Ce+a-lSmpJ~-$7hy=7h3J4-=ebqbqGT9$X)M9(ouzFC(G^YT4y_`^wN2?&mS{)%dju1U&uA?tpgV zZh(qsL3+9siRHDU7YZUG_;L5s)PJpzlJDf-Gh5XInRW4TGAD!AL*85Rv)>A@ZBO_R zDvXqwOryjfsP;GBqD7=~`u_IXDIRv5@{ED^rCNUd@(uo6iuYQX?${G#Xq%dJP|g69 z?vXSbwN%Wnx~mlI=aa8zJT{QeM?#JeUZbC;T>Mg(u&m3x zhF!ma;ULA(=Yj50;ED^+`hFY(qcHOEb$)DSSVMaydz^0t>$LloW*OK-NHvtLvWg9S z+?}9uhsnaXmF^rF+-!s<DzoZ7ob?rQC zBydS_PUFjc#4wxu?;U?pRq%t%9|?_{->1g03$dBahZgNgrnPkahEU_w=x7J;335@L z`Zh};fgiSj`?*!`Dv3(vUBtU@cjh`%uTaQ-e*hNL>x)%LEDqGU8CxY>sZXIrw5)u) zem-fEQIY^_y?f=#3LwfC|54|TE^){3exi?4+eS|?@~+eniH!62x~?Dwm7w;-0vTgiVeUY(^h<+3~1_4)U`v~(AbWD%XxIWqQB`LdJNeB;ijGMR=gp`b$ z{2wti#{K;H+s{w0UQl7Ruv%(?*HQ`gIGug^i=)G#%m`Bw7qgBR&(D@)NA8~lobQPb z_+J$-Cd--EgdkV3w(zfDOJMP_-+h zy(YmghZ52P(78X-()Ki%(+A%uYBqxb-!4j* zM6|!Ca4VX*=}r5;LPE82m6Ie7IJn~}U%oSfp*N(yOB);?)!N3rCQqB%H!>7zq9K`( z39G&Dyr_I0l>7Wy&w0_@D>4e)6SS>Wiapog8nJ^h`UD*v?C4NCg=_fDtPp&*{c1aG zB)5$_DWAF1Ud9h$dxsH2mD8^Fx6(kg;0cO6985&NALJdJi8z3SPJbmZwqv+qL6bLr zsqE7-?zdnqK+KN+@?xJ>Eh(vQd+9#tUawa{YRfOM`FxRP${5W^`nCd51~Y#=bcZhQ z=*Zi-7%snP_tKq5U&WTxSR$6YIvn$&JZl7W8L6Ov@F8flU-xIdrwoIlpo5#}TPJ$$ zSLrEJF|RV=vg#_djDP9NQF+leiJB4AX^Ke9ybSHOewioHvEfGtQC9`FQN?kS=-%st zp6Uw*dEYd1WA_e$khCPpNZX!c65iASh&f6gB12tVanX|cjJ<4DHQHc8-cK~#-rlu` z=XOcM#CC-quD-i@#I&_DR8-!5k&`nSN@kW(iVjK7#%9p`qOPtkl|=d|v#pbRjfc1a zvV>@eK(kd_P8u8Mrk0cZ1#6SVX181*Q2F8+yG$IsP9RV&^I+0>e0*GjfUWqWvxJDq zdahxK+|37FxUnRYQI(sY@6i%DQ)R-@{378$TjPt;bx_#f|0WI1V>Lfap%dCpc#gF7 zQj`)yVieA2ovhrJL`8C~;UoTQ9X1;Vpd0SeBWN^6V2>tVYKe&K0u%B7u|Xc~oPXx< zkE+f2*C;V#CiScR+v@p1S6%0bL@mwwPp|O4bLBt$V}QYhdW_i5e^&nEb@2oLk@kNi z{=0vN^XEiZwd2#jN6?${&bZjH<5EhkjXaLLN4D5+rQ2m&wrwQ`Z~o)EBDMA~$U{dR zGvp*c^rPxRX|KeTzt3q|S)~NP9Y+QA6{uid}qN6D-vud4BRP(ZUh|q05|{vk}2dHnWfG&fwT-A-EEy)on+~d&d=v zLuNaK9Z$pkgz9ZQp}{^Ytt-ZOwA?Xf0eWZt~q_#3^v)a&jcl&wzmu3I^_j_BpLo`iQ#gN*FU7AULN#Iy(^gw2%65sR2Rn^JRoUb zZp(8Bizo;QNq%+m^9vxhkEi7s9J>XlGVv+eYP2>?zOIAAl&DvMN&VwqoU^Zyt> z8IvfR&W|lAhD~PPBg9$^(VUtS?#k!X4Z1J3`qd1$s-w0SaE~bO@^p{AlScEtVRPZT z#`8$s6Nbx@UlGmCyyIyv#>U6-SdFC>CdtY23j&dGViOam#*BOoh#qiRQ&TJkpCE+O z2jsS5*5CD0HGW3$hKZWOy&emlRD~FZ!&3a4u|x2ZjhN}Gdq`) zU*5M&EV!pRT$w}70}MQc48DOXZ-VW^!L)Q&8mX-(6l7zd6kzE1PWO%@T--6qU{w&LL9Yx(Fb{wN_r>(oZ}W~$DwzKP6| z5p1puF26ckiDc)17uWXZL3YMhv`O46w8sg7Uh)$V5?B z3^J9%w#X_04W71Zwg>mznUp>RGG(oCuuCe$KJ(Cds)w~#|)I0v;XilT>l%&o6y2xjc##uFVYR}Z{n^cj zuk>~{9e!VYT^qtYac`DF;ckyp`TkmOGP8{^Jv|YiFiP0MZ;6sy4%)9Y8OaDUn~aNL^>IMM-z%AaFfj6Y@5CZ9}gm zBg!puZPm>!dP|T9?8doF=) z?<|GS`Jg6iHnPP2H$40PIJ*AA*0=+U^K9Zr#Q=8(PT}gOPlA+%CAO%v@pam;@)}p# zFi1&7OVrRX7Xo#{-rwj&Z{5&c>Nq=jG2p$jGiYP17cH(u1!CuDZ1FxJGWSyzK77dnM%lC4eV>c++|$ukFWHV z8NB1iQPH9IOlh;MCUL$8D#y2V(3ut+0&2u^GJ@5Q6iql1lUrnoCepSrWn-T0`ndmezc3qVi^l>-KwR;HjOI_Id1v zc`Q`xtg))RF;$F|s}n|WWPpR&=&;?RiWpk$0mM^!>2z*ff&bsc=v`&Qc|?dcd|NSs zupcXq>MbD&l*_zFtb>xVA(|}#N_orE=a^FAh|JkdX*;kQB4{=xujl#Ny5_}G0+*7l z@w6})EGJ^ktB-F=eg4S(QH{g3{P1YLFb0+Cn{C6u%7nuc*-bZIx62(0*i)jBwF9WO@icY#$5h_h zS@i*B@AiiTV%f3}1(wM>_FyU}ATK&yZ^S**{zWejDJ7 zISC`j(yY~yU7>1g;^}hPh@3f>IIqjoI%izak9ICPZ5_}LB7rKGvl7jkb1Uyzb+PC( zO3Oo@KsJE_=9=aygFB4O1noZLHmGpO3n9>azl=#U$l!cBI+&!ygpb&ArZO)|9`0aZ zj@DQ}{#a!qxv_8qf~(N+U_Rxe0+7k&K=TPuIz?z}1kj=x9*OiY)5A0F&pdcCeZR5P zu)4bxd%GX3X{SqagU+~)PL8d>mDI>aqLJx&q6H-7K{ImT1mc9YVnxG##1o1i{MtM5 z1-}(^Tt8-v<=ju4@++5s{)IN=KwiQ7NGYRC*Us5Tpo50@8aYC{4Nu(wovmI-!LQ z0Rl*Zfb<%A55>^S9pHVx@Bi;z>&{xqnl)LOGjnFoKKprgOZeLHt;(=0Pt^Wss5DAO zUY9!#zg?*jtEGnuTP2a@@xYmqhkN;MPm?|Ncw(Wclj?2Dmt$PE?+p!Z zY_u!46Ey~+AvyUD*?G}NwU?8d@NX)GK&e0S4c^5(7w)FCp_^ZQg&ovz-Vo!~>zM)9T-iM2#h;I=3m{uP#-%R0&l{T1p>2GXJROkZQat_7L6Y}1=IM%>WihRx_u?jFVQ6XO z&c+E$$7GyQ6v%-KJg01_HW*PJ(+Ol@!H{C>Oo$w`wcX`*Oo&9(iH1&>_O`@$K* zlI>MC!K~STA!Dki#&gC{bUz{K!Uy3KxuEW%Omzo-@4{sD!)udMMJ!+ysvXGqt3C1~ zFpRD;LR>E5-BC+u6+YCQD2MUJ9uGs+GWJc01dLo-E^@B>ykRaw-2hign&; zUu2LP0}JBd`yCrKJpLx9-r}DkhTRCDaXo)8YzQ5#N)M8D?6w1mik#k+OTi2KtZmBA z^Nh->*|0ZYU}2$0^=~mBB@Cu+oiVf=;a9Ga7n`(_0M*^}s_&dHKesI8(6PA(L;}t) zsqM8n$C6t8Y;kYfIBKeJYYbfzYXqT>q~%)p8@tU!kxG%wYY6D;o5mQ;yRe!h=-}5E zBcyD?mJ|!USrVHlU25T4R8XXT=jR9w!mIu_Cyz-BeO66V8(1&AJa{M= z|GR2Etj?L7E;O=*=?^R<9hrgxhDZ=MLaK1^Vzp zyHmlu2460uPcV8uv2}%#PG$0Gqf@a1+SnzI!LwPTb2o2G#OfoKN#;}}W5mISVP+5M zOK^Fu)oXi>&u~ODq)zvt%>)f5Le*#!zm8F~ z+pmw40>=q>k%vaQ&5=f{kdY**QY*Y1&}^eQpAJ%7OlW7bkfqGA(LUkmZuaV~d?fwb zwOT0wv4P8&l&)&8%aIWExdP{5dhp*HMPUjH656wH#rgAD;5Lg$1QZ{fdC z6qoPcm$er)2h`WcOI?vtC z-=dO|jL65!uk|ioY_;oX!O3>r+4M$2Ql{@8f5PU=hz@Q;2(qIyWcyjn4tq39>2Lnw zi}mb|NUyWq{&Pccg^G$-qeLdE^@Crz>~gEs{*(_NO@C;_+DH#`79|U#o|?roNtA$> z-)|uO{_Vg<96bZ`ZcG%9il8y=5F3TB6mi22ab~yHr#oP5Yr;4=z@45gu`q}2mieXa zjoYbdc*nX&>E_@y;Uk+Cq7(N+IFIOy%Mh9%;nT*_6!Ls9-$L81B?*twP#*A$kHOJj zkfXX=*g-3ES#a{%{i*4t9thP)N}9HXQI24?=6) z5SZtMRgNm&VuNFJax4B9-`RsyK zaK{9P%2xh4q}UxDNfSFIjzUkUB%lu*tVfK7QfzPD{Q7)Sz-G2&o3=`skJdC04j{8A z?G`QW5PyHdFVWFSUgBsfF>b4ifQ8(K`Fe<#A%xEs7WHeiysn)GJAlUSK8e|5xwJ%V(z`YMXIk2 zv>M1Ne1E{$GGt9|kD$==M7hv&V!T4!9`!wAOrwFpf*)YuXEW!-91$jv?O=?#OaE(u zxE0Nwk>*#90q9pNzS%cYs6ZF~cDEdahe%pjB0R|PO*#;1^&p2>o!QPb2#&9dH_{5g zgd^1cflbf%e?V!I2IK+sq`>`~-dG?esE(Iv@1Z$xqd=doK&-t>v@tbckGVH2s{>?@ z7(08m#qy;7y=)6mRS+B?4oyk~pS|LEl+!oNDUdAm6QIRkC=(&il4^yD-8(BXO{DQd8LVE*)2NHx0ji)O^^?3YC9S^UuJ-u^fB$ATa)$BwLle2e<;#3tB8XuEt7wE|XMX+Y>x!&H| z-e%$BivV(KDGlTPbp+&ot=XY@pTqp1*Xzq|lLY(RuPpKrQ+Awofm37zd3za`bj}cfYfhs z(HuzEeN!Ey71+=K%kaBJFXrjRX$ZREu|mJjblkG?zb>Yhf{|vk&{j=%N?_RBbXTH_YtanPNgpmx zk?RM%Trx6G&(9AG@wD7`c-*wSyzgT8-1L84T$+By)bZK6E3KEgZKytM1BCONs`tPd zEiC?>EW#g*{7KomYnvgT5!3F2s2W$CVMf24H$)0}_9}h(F2Dsu&Fj3mQScLHUI91` z3baX)jql5~PYmsi{vH3NL&`Ae%fq_wM(~wu-9Ob*WxtR|^PUr67@JO4fB8m)*y-ZmPX=QECu3KaN@-~+Coiw{cM^3z zP*V8N&}*RKP;LF^M2kd#^|t%Fs6kIIPx;Etp+v91A84Hb$b0(cpMBjF;e{N_A^pwx znotrC@xEc9-{*t&Zb_84I*_FpoWgJij29DM#zj$A8HJ{Ce|_ch#%9kO=Knvsd0n0m zY8}Nkui+ zza=J>m)E_oi%-s@1=UpivD-CCz?D zm)MTh$D}|#l275`Y~0+xRvL8|pw7-IY3qDuxYwHWPYfb6neOeFlb{w@A z&!6p>H%o4PlVktkK_=VTV+uj8H|iKWlHFxuQd*m+wBzLBVwRAoz5Y-P5fBulrKvfM zcW|j;fWc1Le=N?<<8YDVHoG38z(DSvKGjJUxZJpm6>r>l z{NUKCelCgyemRYZ<>Lc?%*EKM8WCq>%Qbxl)`8d@)2W1U4`Q!{&h`8RMf9Y%4dRJY6PFO{TWSwxrw2eV=w zwS80n*m2wn%`GVSgL7r=z^&v2dfixZ1ZYW!~S9L_B!Ab4RS^M#A`2^s6_PZp(A}I$%JAdXJV9 z=T_H!TDu2MBozRG&D0Qr{6 z?wg~~T`|1!JjVE$e}Y-&X>riP8B}b+gKVcv9qdkc!|G>YWi@Mx^AbW4hMS;>b-kvA zA}})fY8?Mj?(KiIyD(#NOV%-P=*VEv@QX`Ol~xRRv-SyZi4xt+7NHQ_Gdt zV+!v`0A@oOkE?ar*s+th%DGA`(?!Rc?VTZ7_aXf%;n1K3CKFehx8+aP$L?fT?wYlK zdhIh&9yj+Y`rQSj73KAP3grrI7)5fwQ7RFZ?m&+q5l&p{NA`Ey$R@Y2EG)!gJ9aO2 z1*#581ojH96SeZdcHXahZC)ENqyNTpKcT7bq;p$cU(OZQ2mo4XqV40o1Sj2NKJFc} zs8_uS+$TawK`4|l!8|tWXfh2qH+))fKjXKOTM+ZuPFf_w^AnkX>(xi6`!=Zu=4^){ zM~bu_G%(nS2A`sJvTkDmvj`k&1J%(WtqYVZ#pkT8wyS2jwv>NA3_h$!v*ykfjp z7J9!|>eGom(XU;4BTSJgJ#3?7>Wy}nun`U$p5h`bke(#xNCf^b%vLZP(tovo`05{= zeUExTl=QHI0hW_DMVf>p|{nZo}H?H?hyu#c9Zh!?Q*I&*b=xjgZeF6 zEZME|nAmDCc(1&nlx0EiKvtK4Bgl1q%G^mLa*30NWzb(CG~l!EGBd!)eI(-)vGXt55i}YiC8J9UB$CBQ>%OB@ z_ENEC)+4ac%F#KQA2hqYJH9~=mNHP;N%OpU%{Sb5a00XVV++q3CKcx++;s--GeYJ! zw!W_)Eyambe|>S{^{%pyhC~EZiwwP?K7+vv^K*_|ZsA|{@Oa3#nmWIOo9bM@emrvPx60w_&!vbDe&9!{tXT9O9r2ThVVasE2oqgp^Cz^MF^M}udo@fk6zg zoc<79yU)Eg_Z%dU!o*}0d8E^%Ms)QtnwsyYhtirZHK;i${zUkoCJa`24bU?)9visM zT@*P9135drC{;6GbZyG0h`A*y-hazU^oO_n^k6nnlJQAL%0oRd>b=852HQyEy&2rK zR#{nJTZZmKgjHWq6^3DB-&p+cpp6n{C+?ZtL8@9Nv{qO_d?PrndphXaHKx<2b7N?3 zt+uVr5+gd72;EP?Mf_LBZ%cdeyj$yTQJf*dO#Gyk(DBZ%m>M1rgA67Crfr!G+4XN! zXQ9vvNxk|43#+>O`MhCoRX%?$lf<$@XFnTX%LmErlCkv?z<>DmC-kpyji$AB@qRe6 z_hMzxoZkQCuAO@DAc>bv)yPr0E&JPy#TqDea}BzMt@%|YY%TJEuRDo7zQz!HkSCQj z30r{M=zCt~Rokh59J}tgT&ZgLoc}tTQK@wrrI8Z}u$*Mwr^ZhzF$qRsd)>FVsg_&wDAl?bua zA_Oe9UCoK~AdrDZ-fnd~$hMQ(q(I1Uz$$T_n)eAdYd4}>&l*a_Hsyd9a&R@E3H?0vG2tw!3q7NT znY#^z#&)%jvVvSow+^jkl7%Ds)V3HgX4fj4PlWccGY0YsCSg z6jK*a-OkNN>h9rmo^)36`1?SHPDkCnGRyLr#oQD*Yi4-O0Nt6*anQeeI{J@&XHm$A zArO7DyE)bK9D`%R_!3HKMw8NKxwx!$%?0%b?b)O)Frwvm8D}@ulaGv_^MGf*S8ZRu z(G81L^ziBHpG*cPH{FLcH|%dF2|~KOk}WLyhCS~*|Ki~|pCxR+t82U`Guapo)9WmN z{+%t)lzA>)Y)iJ$=1&43MFpr&d%9E-swK(ItP*taf zg{p@)YPQKPf7e{}YzvogF}&j1A^Qt$$7hVIAWaUwvP4VuqHa^xOSoFj8rlbFx6G>q zcc;Zrj_>B;ykdZ|0Zh_ySm`DDcl1e(`h(krq?bos*?rKrcjU;^O>Y?S6w5*r-q1Qk z?As5NL*eTKA6N^)zAQe1!Wj4P6-`OV;xqbu78u%FrBBsVrD=S5F?!KRLP_kHC4#jbhni7z!{MJVh$6T02^)gzQ+E3ct12V`)&CN+>)Y0v z1<^#ib}nKmuXzrp^q@)0fPh=L{!jt| zB*T@$;kp+bk>MjIAa7Ay`>w34te6y+lvHR)NPB1J0}+v-l{sf0ZP)J$IoyNAh@i`{02-#%w=4Dft1j}&aeWW>_FgX~Qn!0YYtJr* zMPC&pxHkc1_U6CweuD(j@Izh^P@TcdSGj{ zpVS~KbTQ}nbA<66!va@5Ei{-u+;^4m+q{)IFo3A@e{#u+`h}1*FB;F_Jkfs-A_BY0 z4J2MP0c@7S=zl!Nwc2Tnn5W?YK8^&aulC$l=+5deuYn)1XaigFyRoa7YPWP?_ekn% X^5yI{6)_M2uqn!_$rL_+`|OlUY{zsEK?a1+qk>6b3GX&nWpSnBVc_oQ!)!I}a50nl5K5b4m{UyhFy0~~p zjpX<4$-=twd=$4qEnAa=06>d|YQR1jE*-jwUByTmYacn)m;Wn1T@pstr znGN^-=|;&CPweT*;4Mwy??B0lQu@T@!PNW9ii^4lVRsmddqbvTlgXNaA*+ChjI5p9 z>U~d0yapUE5Cx zEvv0!@arVUDt)%69Ox&049-L2mx#M<^l>%TEOy;=iyiM1BL(U7IR@q>c(%NBvCL9kOFw8_jo?5y$ zZ_28}HncHMZgsv*$LfYnJ6Lu9!x*jX*`kw(Qx(0kQEF(^WvFkXlEAZU+=6#-mxYNJV?5s|(ZZevRi7Cbc)HhNB4V-0 zWh*bU9?tD%3A2UT8~7~R-T538QW1g()W#m;D4M-i*Am;?yE|jfx=ht+RhdXlW2jX+ zQfe1TWZd)FrN*E{a1E zsJbrx5P1l}wxZuHxg3pVsi|)xO{gKwJN}g8ElPP-tT|$B3N@k$DpxzY<&NMjQCs)) zid@tgw=LPXyg#8yMpBv5q{|YPeeC=1uNc7BE%@>lkk3Es?D#UaN35_w5)u z*KuPP26vz0VfZ1h4|6{;$pC0>1ojhlmTsKC#$-y4a&H@UpB$KP7b%JoVUlw%zHQFs>c6 zp=2Q~5m8KhD<}g%nd+6ZJ&3VR^2I2pYC5#rewhqjy*9Y^=T3Px%v;b49`Mk;%OBtm zO<|3G709zjW^OXXdVJ@TsDUWO&~n4)K=efo-zJmVQVi*XqF=?4(*UQn4`n+wrn2Cq zef{K+BkIhB+5h2EkKF$x@iZqB|pJ1d_#k^HNKzD zope@v#y-}*GJ*V>U7)p)nma=4y`LukF<|%!Vk{BPZ($T+Ny*BH&3t3}E5pOJ0Iq*r z1w_=YZ~$BD99N+r#62YF^G-FZmN{p9l7tJ(yX+iN=@G?Ebw#k(PN(4O0nq}sXSa^_}TqW>0$K>jI}BJ=gz3s@RR~k7qbxa z1I8Ct#ckxEl5I^p#S$$Ee<4@Dc*@x;?t_uz{y=n;J3ULXJ2jm79~$AS*@@3) z?SynuiXx&*aIFyVN{eLWzNWTwv({}2ia$zk)%`9q#38s#7lrB|a9~snXd<@@9~nS5 z`R+eMHM^nm_#1l+;M%C zAo3x=LkXBw<`~JAoQ|5S*r*Gn9JP?N+#^&cYNy&~#jN)`od|NmgShrGXAa~9zH~Dm z>bc_V})&!d{Ld9n6 zDh5&g1X)9pfPNr)1?InyII`j-2iZ@0+S&v`?|mBS_{4Yo$-^!w@eQ3%SiY?`w>eER zHW`xmqa75nU+M@!kJShSD=+eCG@1oUw;48y)Cb9?Pr*d21EUryw!Zg0`Kj^+%*+N+ zCcLdB?YvFiwDv!1mxn^DTwuzOmU|>AVAEZcIF!JVJnr~gO{jZQMBJeoz9__}qXIQT zaGf_?GvV}lhXL^fB$0W`%-a==rfBd-FzyHmd~$~&A&wasXubH$?x}FGkP!yF5sp0%_m5B-Re=EoJO2*q3p9!!KU`#r9Q`ipr|-S|ZSZ5MJ+X(JR5 z2SOeBnvF{AH%XaJW{*GVL}obkK`8(kFZzIJmr z(xT)A{Yi>vi{fw{$0Z<(hy=u6fv=8qBd^o`C+y zAfgr@YM_%qL%1_pqaQu=k;%7TyRhQRp`C2(r|LbJih=emBI!ca9T6WV#XXhQm`8NS z5>6E;=I+709ln-&eq~16=RfUF?bx?e;@6jvXX9|#EIN-VXXyX>Sz|o-lPH$u4S#<{ zurZWZP%U&m?s$rM&~wZGvM3NGs3YdCVeFK|wq$Ezn<8-Q?pEr=K$!~_(L+NcGF2vq zPXcSg(AQ(ce~z9(6BM|cSFRYasgD&LqYX1sm(i3^XU*H71EfN zm_LctZ14I(!wiTqb$rw0UFEer+$?vGoaT=<+JuLsMLU+l*{zEFohOu4F3e#03QmxM@ALp*^-S7Ddeb9w%>P_2#mD0UJG$GUj)@MEhg9 zSX2rA#!QSZ=3CS$Ggwt1EnN%6xmicv$MpcNo?Q(=EKsO<#AO~)UP&&AL99qPOGi@h8*MLi+(yxWNz&K7Vq=Y+k zB7%6`hGl>;KM{+!YEsJgBxhh|j`TIP|B2pXNNNdcAoq?hE&fq&n1lk4C;~&(r58%m z`vvt2E9*6%wEiAX2A;wbbzvYuKv6RMFEYN}QGd=#2A&J~4HA+M>e^-)Spka=a9?)+ zI+YWQkal)`RHMX4D6EM0RsJ>;y0q|ImqzLZ+J zPJy(|MJV-AY*{kdaUS&tOw>cc+UN-qgb$$>)cSSoTow4WKld1>2%hTaDEc_T^TlD? zv^{PtRkANwn?8EIhAzI9^Xh4Nveld|mkh9orF-&-&XYwem&%b0)X87`!z;7f%B9Tl ziiNk5er-HX<#+A%e>m4fzQ)SrRUSL2kJYY?X`9rFISQ-Qpni}~KkW3SwB|0C;8vIZ zA%$2}lq@FZR;?bFga4LW3-bV3Adwe9bPNo{$!9N3G5z5N}IjcAK zlX77j`U7R1I|w$ZCm*tTNZkyjp0cmUCz!OD=&-yOQF!i>xfM_0>tT~%$J~t=A1S@@ z+oa-X&7SZ)htcYO{lb*0-BmdEuXnywoR9d|LX=*YVLyu-`(#ozlnEi)A4qTNnVk|y zPg|MbBu^;9?xqCMr7+Z2<4DZob=0fc{4#oTw@H6DuhC+Z#$J@ZQhnEkQPNiXE`60a z{{1{QfD^$mFmCxU!8bsv2MdWaM&{T6FT!QG> zVTiB+C;F(@LY_Wx*K>95csP#bYp8svBH=14r5srBNnUvDZFeT|6m?4a20v0+5tZqx zkvo@yh)^{|6^VE#?wfAa%Mix~X&nBD{=hw^&(RK9j@3&wJ{?^7)NO*(8(t+r;qu-F zYt-9?ww*feBLE)~Kb78c)lCS4fV`DPay7mGx0XvY5YDod#_H|*Gxzx%(G z2=(HTO2Vyzc(1dd)`TU9JQ?;7GJ?vZSjEs}NJ(t4QZ*|aeY3 z(Ym{lYzV()gTbCrR~61_wewk&TskO(n;1mXoXZ(uf;px_xU`xQ3a|wNqtb;Q)#j^B zxy>ZkNqY`x=lS_0A9K_>&n`)wOV|iALlHxH-<3P%b}k zYLNxID`8_o4!Acv42#V87M37=i_`CP5e>nJ<@+l5hY0IacwZm2c#6=RtA2l&`sT2` zMTa16%Ox3htCbm4DqT)Spn5?D+n%Nn7ibGTD4iDi! z(EBP5AoiRqITTadC~M=z90Y7B6>kq8M_1h!aCZ7OpEZRLtM$@BoJQUZh z?B4Y|^GtJf7kvE*B6TKmcqf6UMMJ^9u~XRRMxm=QlHT_H?N78&I3w11RYiIg(?Fky ztuM1eU$9#*735U@sWsS9KENODcNB;GseT1i=?AmY{us3o_hiWrb~D30WtG>>KSs&Ldc`$dCFq0wfwzUAo%;8?-LVlD(sm>9;ol|qU-5b z9qE3(b6rosgu^JQlOJp~_eRK%lKJ0&t3j%#LSOO z#;1U66n?Csg7RX8)Ss5z+&?5Eu@q0ti~{vxRhsBlq|s32>t|m7-stPuZ0c(77x!aqnrE`BN$OC|1ZFC{lwW_4 z@Fn`G#*BeZg$xRGP1-)WfmJGgB0(0g4P3zRPv~pFU&$HFEBv7?fp&(v>)sT=%4+i| z$O~QFZ7zA*<~;S9*yT*(F2|PtY4uo?SyX{F8^%I$6xy315|tpo7%4t!Wc<4Mnvzh2 zDM0o-ZW(`R8Vlv7_l?1iZ(1-I^}hNY&wrE*5XXn~M_1yaZ{Y{41Y%U^k1A*F^D>^wgcTv>?`W5s zZYlC;Ed3^kX^ZqwUbPVzjCi}F2{%`D=Bo}TZi?SLQMU!;!41X5pGiVo$+4$Zm3gsH z1R=3+He;u*x$n!nxQ<)(F7u-O^v_vF2T#nVZvT9wiv2!HaVD>6OkUXhS8FBb8-%Pw zZ&CQK?W9nx@3w(;cHc1a)}lW6g);1nZivKKCba8bUe{a%UR1%3eZde!skQl3AR*WZ z`^;Ba(nhMVignCaqBvjp@n{%xZg6*+;S^yG>QfYxu>t{6(T|e*G!V&4!Afv=RuVs;}!uZG!4O6{WKW_bm^=@tuUStq(#hehzIme z`>84`%kvK@=g^&MF5GGT$7&r=$6lqLm`@y@3daU%Td7iDJM{U$W4B33*{qa>(6I#mg zxy$RZ%0Q)55V_=~ zdYo;PZ}{|t#CI`A33Jt9-dYaXL~w$T_8(X!A3b8xn9kFw%l=xDaXNs{f-I=$lvl!{B zlCUb!rIil{6_z*s>`-ZW#J_Y#SVe{+58C00 z;^;xy#By*tGDS8iY4#ItX61ht?k$+0FbnKIn6I7x#%E-Mo*~tETC*8;%XZ9fj;s;> z1FYnWf(p6p7>S}FfoP5&3Z#SZ>U_N7BP4_mFPsHep}1qG*6|;oqJwiyz&8~v)`=re zM|V2jKKG0A_)|FcmVWm!Mc`X4mn>(|df(gB{p=r^EAkb(a)S5^4-mJHOGSq2a$ZA` z>Ls^VgO;t$t>Kj%q`mmD={?CDQ;@PlG|zS{u`=3c5o(dHb4;nNL@V*PCdRn;NhtD0 z>P*VysDrwf-4ubsQTOG|U!5$#e1v4rvYY}*e7#wr$M9pua6izyEdSO+&5@yG*_Wk- zofx5d2T?jGZ=wgHW4vLQpXlc)@}qk4MEQdnq(lkdm%dpyV{k&8B2WG zCXe~-p6B4DS_m`UF8$5~_{J8=BXTtBFf$-;WrZ_iEhiq2~d*1d8M?W+^5_ zS^IeMR;2?aJ+2~r_q>wRWyuAIkS|6Yf6690jR;?NB|wfqCS`*D&s8oaiwvQ#MUD`pZIYhEVu1Y;iXUhCPw0qoW`h_#TuG zMmuxXac{ShqNL&wy!zS_l1qJ-$Ecodh(T_Zjr|a(Lntns0qj?4oP{0*Mi#vFc0>VOPwG zpbL_Pb-i9o_Y#~l4XV02>|77l*Tzd}F}6!zmOMC1W8=^-UqWK& zbPa{PxL9oUEazZ8iey+K+nR~(@AR?zBXOohh<{W@EgRe4>~_AuE2xw{PD<=%lT^3n zDaBjxy7ti=)NC-CoU5iGNpNDCq9-2bcey3;9*kLj?s*R;>8GJJQ9V|G!@+1o!mo`2hqAMd zSHE~h5J9=|?iEVB;ZVTOxvU22D%hPT#fN-1C~Z(6PomPq#KcaI2j{aDOk)V(33-Vu zZaagiTtQEqoNmImHO?oOoE#WnH<6xt20xON1Ci%w7EPcN$OZF)6a%C0;^Jqj#MRjdT^Zuhim@H1RXs_dP zo12N0^w-=RJ2|;f3U?oiLEX~SRBex*_(gbRBt;|A#c`;(3d^yE`Yl=MW|?Q0b4d zvNCp=jMUV`FF}`=KfvPi<=>^+^^}z{bnS3)aZ$mnY;0_-tgxif(b4_PrSlfJ!CUPM z4o|Ti%`S~S0B@=Ed9we#{@(8H<)RUWh&el6n)E=uRa&1$wieUm@bG624jF0bIWzW` zJ3z6PmzRNM7Zw)4d6%7G;zf$BS~^=-wctE)Y3W_==%pHOJ+0&l!ouK!dIttXsS=8cicrDQGBSWBlRNPKhrr?*8hC?tie>Ed z^bxk`oGdIu!~^&^IIuzBw@Md#d)CjN6=*Qx;^F||(9+U6J3GJhTRJ;8E0*nY%Tl0W z9zy3Tmc=I|JpBgb@$|JYm7$IyBQ32=r2=Sz3XsUtU;ro7l@HnZxw~r=y%QN3S*~0L zR!CH-NE$Z!`}Z$hQh4`t&w&^XhGdaqmwJ0?)cDAVB3)7-N|j1Ra`J#nm8p8NTzTmW zMmOfuV!vHxYpa`zO0s0pHnHelJDWU4(aC;nRu*Hz@Na`Urfh(tFW>m2niyXY3A=)F zijQ6*Ks_Nni^wnP#qu;}=@YsU$tt+Lu3}$jZtB?f3U5TMqo#e@}s8$2C!)!f`{(e%|vuSS_}e0=K0_iUI>aBuVzO zAP|dKHfi_?^t=~JC0w}oY&1`qu>&gU*_oJ>)L+k#LmaGcmYzIp1dIV2Vu)Zi)xib% z%gInB4DZ?VIby?p*x%oOF@z4<51Dkng07IKVaJOCK3G^nqoem9LKVvrhmGixM*jTK zVoJHGm>3z!r;%j9g8u;Nt?qsHa+Vrz8=+ApD=xkX^$CztT%5jz#mELyPZ@;#R(yQC zW7UQy3jsd<=)(!EJ{&44>I)2C9GC6-rEXSMmQ*TOQZk$=ei8Z}P^SxR`G?X(rr=59 z;S(Er5`gKYxB8wE8awLAO)V`kk&(NmSYg6|(s^cJf;`PWfBqbZ5+zC=Cr&^}cr$2= z7ABl0zneV<=_f$4nUVX66fj8@6&2g{4hcEAgN&^2bV-V3M(PV=W6~`c!;70b0wH3BU8dXfiS^qz%_7CH{_T9uh2CB= zMn=YO-&WVx*8xsaB?JWpU4@kt7Gfk3YfnVbs*#hEdw6(&VP$3k!v|~?Fo1&T4!0XB zV9xaP^vcTDFJIL2no{{H*nhpP~Of>0ee~7Iq|e? z05oKD&y(x=<%+GFgjfU}{K#nm2K2`B@iNbbC`r=T%xuVKKPT!S!z)p;2#5v4Mk2;x zwoi+*vxYcS930;lnMvNQC~B~2HaM$C5n|*7b#(z_O-#h-DzTK6jXvN0ITbZeNtQ6| z7?XOe=wa&}PNxP)sjC6xqdvJ|L|cpLIeeL9>Id`uR8zEq6(>%C0y{JNk7&c=#VJfo zOxmVPAaV^b&2E__@LeI8n3!H*x(Ib1nsy~lDBV^;{Aq=@jw=$O>&yPFhI+-#unqJ`Y&ImZrcuaDba>K`dqbd-)xjR>`AK)%eBk<@{O z#l`7qX+Rj{K|{U-q{kX29G{j(n=t%nItO?%izYxpEt)jAZ2H^JhM&;4U<}!~xF$EU zCu0yMVeT`I?B0_bLx zsFJb`AUDY(AcWc3*?s)@kzEFGaY0~xQ&VcJ2=ny)!8*XRdr~{RJzeH=HkUR#zIh8P zJkjd^x)$s@7Zn1GUQ$x>4fjzktDE>&OVNR@hk1)gnezVbZm2NX8V(FX-{H~G-US2% z2s7IDFVo~J>l$osk+wW`A2kI93Rp{9Tes8Q*uX$BKJM5F@%l+~XQOHm$o`~0?MS4x zB|``V>EVd#>gqD3P*YQ9WMoJc%>bdSv60=|*Rd+O(r1&O)g$;o` zNwTV{3K0R}vDnoc=N>RDZ_YUJ!kU^I%PdZIc4=f)6MPAn}g_4EiZVBJiPNl~Ej*)#$FMdAprFF@1Hq&+v%okn zuXf5$z-a;D5iSV$&c>F2Y#A|vM*6$Aw-->P{L-l@d2ncUwoaa5)hzqj<|YYXXeWEm zNU$Fu-%s7iZ>FNeRJ z%&Z}?u(EEit^$giolPX7psubC&YJ>W7ud@-L=KqUZ3Ub@00KQ`$|Do=b$GwF)zmPLK;~X&^K)eCYb^zO#;S+?5@l#jWfdvK=A!iOF?vW}=HnQ!-}$WwuaWR|aHUu)1W37yg(&M7 zqKn}DJHZf3q&!WcI0ZsqEkj0TW+gr^(h~%zl;+~&<DVMl<>dC}aJ8MLD7hRB0yvGnAIy;=n z#Up?*H1NO!zLIn_G^M3oxBVS4=s;mbj@R@B816C6P30QfatGGX|5prwJoEK=X!B`_ zKp?&Zmh5r&VBkV7ARDXRM{veADp1dP^69?}xANy={2S+sVae{Op(Xmo0}?1g-ihJ) zAxQgg93bUr7Cs5||4s+KmJ;Z9w3Z@C{wvA=%C!%?;yvyZ`2U{nT7AK!`BzQ?@b6aeKT7fkiGVKifcgAJqq9>17DOx~FOLHEZ+Vmf zRlWw3ak}G@Ab9L#ey=1+r;~-M#Ts2UgxNYnF?e`*0=a*afo)jclqeF0o2{1PGc%=O zukP+d5Oh1*T`thTcw9DPKE~?zN3$hxL0}5BFWlUz85sqk|DE_2z>;kXs)=nr55M+f zb=V)n)kfH8w$}8{*J4^+T&y`A6n@h|03vJxm5c#Sv4N`KY-2z`fIN+~xOixII2Z>R zl%(P4c)K^6(okO?o+d_@^!NGs8#lLJ1hB#8EZh$N>(9n~{}*bxY!q;1Rh4Fo&A6P~ z)Ab&3BuGd|zLI^V<(W_S99!~eIuXm-o z85kHu6Mo}#Je0RW1y(1Cd`C6|l37t9SP5})ZeaLgy|b^c@8NV=X}|b!G=&)*{POxb z+QFRzR`~Zv=Ht`N!DJ4IR0Btu0h+Y-~cpDDv|7X+F)l#^H?w!x*IG zE{-h3_wm7_Q4*8vrO-UQCSNhL?alNTDg<#lUD8zKfdCB|)rW?{ zHfd-#cLhBKT-HOcz9@=_TS%L$*WZd{!Co+vheg+wtw_n?QY@7 zhb3J}saSE(Idyw}38Z76xQL0Yzs%|A?M%i{tp*j5dDPqf%H$Zd386HnFlqjN@;6%j zc6Adk$-AL((#Lx5^`?RopXlYw5ZpX)KfR{}bD$d^`5;Ge#bkB6;N+SeGKJb^Qm#tn zV!0tCX3LFPw~HbWaI*aT-PgY__skQR>Eho%7`lQ(^YZdSLd2jcMWtkReHhgqnl2EK zr%io&E#~n2F_jXTj{-v_WZ#a1u#MrUHO2$-j*cl;Dep}7X}7~U}Rz& zOH0jtoUT&ZqVQdK;ZsbazLbVrKKWC#jf)Tnb^L>iC=>X%MDz|jqmY65tTU@qEqvz; zdlvQ(6maN$e+^%=SMpifdVk;W%0N~BA)%aN&PB$buIPZKruK`#fGsz<69-)6W|`yd zBMV#0gO%FnTOsDBz1H1|6O$_Lhx5OZ;Zm(#9X^KC4(Lis4)}{E335gDfhfI28>_cb zK2DZ~WpPeX&Iu1U%kzL{4b`5_B^9i4SgN%T2S&v3 z(fOQ!S@-|=uV*6_E0(1xB|u13Q`82=R`vxjoJ_zipn%zt59ZLr)0q(G(ZF*pCCV+Y z$AvFvGQ&vf8>4GYtH;l21p0kGmZWDtIl@M@YZ}+aICj3eag|-1D>n31-h3jk(DHSu zy&^?MuW%-uZ^%x{mN&3cEim5rtX**sMPDAq$JU}Mgl$P*@|V}AD|4u`#H8Vf&tom{ z{Eab#J@bd6f-vHJ+z_M-VWcge;oXnH%{32V%XQ+#0UZt2LSsZRP0bPwZ{1gC#yHAA zBVuCpqUA|aJaFj#G_#J$ew9ks9Pr*QrfzL8ncq9I0{@ADQ`@xqZ?nrmv~>rbJF?oC zss$xu-EFTaeK8aB_fObrYjr)iMDx_z3VTE!QBPJ^@BgIzzVgXyo7}kdx@h)Zzq90; zIdcJ=pwIW7s?8Tc?I*GF_aCGNKwby``%VKlto0Kl1MidB?<>nK=X6PFTp zfptV<)6$-{`{CDA*CGx_a0aC`-yUZ-x^9xSPFsuDG$&*2BV{sj?%x**!{hGn!qT7y zy&AgC`!6h60#Wk2yf;N_v=_13Omd#VN~S!5sN*<+?=oLgI{Y#F1F~#%w&0@ zAcGM1T8lgn@F`aKf86Sf&VNxK;Nh2O>&~^vT|6;8U~yrhfRz_zJO5tUPhnXGOD!#T z?$`4om%Pl#i-+!Ct@CGd!gC*vB>uQ+siDoOI$pF5nLWOV>npb;w#J(-dLZfRo{Vw1 zvsvS|U!8|tXpp>}?@`949#5(WQ>sw!?6BvkJ1X3F58Pev-ek8kHNC}isQXnuTH)~p z-f7k;adA>~qT`2G=NIgD7l8s>tY){a0l7#G>`lf-?FK9+{)^13guO#qndA8~g?_DT zTg{HYE5rw1ZTX2cGTb`c@Uh( zchfp=>9D1aImOFxKI?jYy~c_+5c+f17jkB&<$Sv=;BvNOZTO6cYwUV=m`XSP!c*X^ z8)LwmX=wXL+`)cIt3CTRE5rD)=|m!GfP;}jYHDnzsDJKmOB zJsNp5m7sHpY<{P#s_=M(A6L24>a zmy%bL#k^U1b6p*+%Q?+Sb_3NCp=RxQ+;!EFI}z{4rb-L4VzbwBZ6AW8tL>Gu#6O~l z13MK*P!_oGzwfP|A2TSv+-Fa(jmzh%7MbeWo?rE;YJeN{VOrKp`Rs;itx&(VJ}1Yc&O^|`@ zAUK|08KmIq*))o2LAWM-E*a~qF{&JYyn|2_J=?-HL;G!VM#;mOmf{N7)+p z$8KBH#`s0?HJ;?>zUD?_^;*2baLMv?oG8{AZkcBjuD=f%zWDobAeayQTpx1NZGY*! zSh8d^p6+egZ>SI~vs#I=v`zQnuN$82$xyf2j$xXb$*88-&`{Wl5)Lu?X0IKL%K-}$iGcYzbHa%TOhO~QJaDcS( z#dSSfQ0hiz+|9}JY4SvNJz~trJbfr({yb~1b6;FmiR#%c7j z?{v{9oSbyBuV&v{1~MFKFq+`1n!QY*Z>^0iyjwghCwlJ+Iw12!I93p{>KvWrROzV5 zMDKp6uWFoJt57dmd^5eQC}6B&w6|?lC?*VXdbYVer|*7z1VqfzFk5beg+aQ4#+3d3 z^&2UZ!s)I-)-(K$@_ZV_0A+1qdPGjnYrPa#{1_AOrCEDffz?HPL<@SW)UWTaJ`Iyn zVmChqSzGTeZy;o3B0R%WSXn<$FdF5Fiz`cFx(7pIs8FkM5`AsCnraO!jRzx5;BvT4 zVT3%tpGd>zF;+5MThQ@JoJ%NcjhpBvX*QVit0AgD0_yC%!Fl4H8-+^xyY7Hw16s)? zTl|oHsjYOyUq(_K?HjlH{&%rxCRqwvzBo!7Sw_v3sy27}<=f+euWuEr!^m&WcQ$C) zkG0{GWUIY+WM=S|Qu`Y*o^)6>Qu6!RBn=PO4w@LGrad>`L0grVN`y?%SSWTjQ{*ae={wP&G{2C`7j{%d z5txHRIggzv>MRUo(0k{s&**WTObWIbvESWPknH(K?@Bl;Y||cPUs^oMrk+#SyqJ&= zXC><2mpq9bBEg9AsKUuauY>nm4u`utG}Z^b^aBs`R&yaWzt+XvTprd3%L^BE7kLFy z!J(qb2~}%%iy3|!DztQMO^wa+>!FecVNf!#)1qR+sH4Fu?4;6+8(8tS%vKyPtHUnE zMOhs|{mBih^FH_$)lGMn#v#0ol%a>B$Q_hw`9S*viV- zk}l6YolLswmtkiBw%i|AYMo(Jl{75xo1q}nk=|r%4@5#eH2hy$2s?%L;FjSV(-u9eWO%D?(M9BD0T@8>*_EnL{m4`d%|q_xzbrVj*(AtOn?^%sK5(fBLw>Sd%oc9DFv~gtm$i@!Bxv z)vE(JG^aV1U{buC7Ip0qO)^_O*g{77+ZQnV6?QX$YjyuJP{2`Aa$ooCtqSHmi6*~K z_{-A}uo?|b7l>&#Sp+#hvQ9x?@&JVvPzJ&2!tcD@b?C3QS58j6YIyB3qhH7z&Fvz8 z(%u!mqYa?EJqte!(;VWst zn)mCG$#|<}`fk(WG^MVV%l+cpTMysU@3c3h4I{AooO{dq%_tMRoZL-xeZ5bv$d`(gYd+>3}0qIK{3j;%&ljXdokWEZk zAc)Z%<)AwFZFM9?gdh_~*MlAf07Ke6JBzXhJ(~IZ`ybC&JWQ+nukVfhQ&(L;T6(O` za4;B&P=gk(c74Vn=Kt;jDB8pUsejeWc?|OE;^gHh&neJ}2Y@eH096O)0S%t_J$@Dh zaunE99sqHFpJA6#aHWF-Myoe5Eyvc}cB(k17s1PcJd}byRz$;Kv&!DFd$A4yduA5=} z4^ILCR|x(~0yw(f$30;akl`~Yb=2@;{~J~&Gxp(pJ6&$j(a`~r$|8*s%fW_+2?tBz z@s=*j97c=dt647&(m?q}0VA_>t#;!LS}BtUM@&Oxpw0)V2fOgJ>dLj|1f|paerl%l!DbaM2dc>P@Nx`lV`w?s#@!W zdGn-_6oMrUlIFxpaUP@hbCV1GiJ6V6Ist7=Z_`aRUz{|L2(M}YL- zQ(wA;Tm_;;?|_Ab2wx6g;+P$mL<+Tl(z4jM;IIUb|mVo`C40v6a!OR9?R4DAzH1IYY z-!EbL9Bhw|efoZfY5zrxh8KR2jw5}pl+WOp6^1t99V__tlGlaHg&jeArQ`gzn@#9E z#Nsa(`gZDnU&B{UB`8XHk|h!VUnC3w9Hu2;D_`Zl0n$*Cpbs5PQ$RXs&n=s9WhBHE zaTrmqJ=-CPte0>7;D1-hIaFJ!-E6TdM-MbM+6-y9eI_7H8D6DyPceyJjFSoUGnfime*bRCUS%~NZ+57e28Ul}U z(nNjo8h3ECp*k3Lur5D+}Iz@GX@#z^y2q7B4KENU|@h=!b@kvM;Msrzkib*ymY>0ce-S2l3N%IdTv2N{Xfdy zI;yHJ{PzV6K$H-qTRNp11O%j|yE`@=(kdn0UDB{A>D-_o-QC^YU3dDv@9&O##<=H< zan?Ty?7j9{bItk8C%(^TKLNrHg}(r*64@U?JcRCm18BHwj4$4*W~TRelabQ`KJJ@InqCce-Sh}d8j;hUb$pb~{%nuMdA97HftK8-VY3m{ISm3y z+pWsD>cr$B``~3H1v6b_$`B}k={ZI;Fp5Kbl0}gcygyr?7UERc4xARQ4m-}r@VN>6 zsxMv&)8lY;w1X}<{aR63v?>_2~dNojZOo|3>`OHxpQF6Hz` zBpIvT1u`Y|2yH{nb-Z)vNg3UlOmPs^AjK&E`2Nj9*B9QKxmI}HaYF08xu$^Px~M*{ zoVJ|E6-LX)it^3PbL+L8t);EKg&(IU9(Bn7>~9$sxISy1KMq`AjDp=R6Fb}p8D)t9gty?J4TZ9`^drtNX&&}e_@1i_G6eF8BW#;j%Z-*INRUNmWmiNp zvMf4pL6^)&zc=Stu$zbSQR|39@iEREJjb#iBdy)IrPRs;)&{*dEM$J%L{jDaVOt;J2y^W^?4nPi4?_aV+jH8 z6DnE8NM5dDqYz>7zYA+=mG-vsKW7C9rDRh$-voUykzTWy+RZm8Ly@V<-;uMfB3*pS zbbS}Ge^cxkDQ5np(Oq^o1-jCDu&>n&>%SD3m;H&h4EtIclvK`7MHv`b8=(Y|a!58I z;xjm?*FV%xdmz;iEk=SEGpuXU8j3OPLST4F?)hhljz|M!SS7YgQu}ELF8YW=CUhB2r~bDH0S~f-ADH4f_!m5hjgtH^4{Zs#jPcc3x4*lO^vp<(o6K zqVlHP=h>^~MSjTg3eUXvE9&u?u++*e40?W4_~ zSmC#MdQb8?wVup(GYt^KZiKO;#*n!$?#_LGp(NM}gok?ByI8U{Tgar?-CwdmtY+~f zKfK12h>*kNT$Ei$BKzR%mMS2s5G{vN8I|C(tui?Ce(+Cq|5yx5 zy_fM5YF-o?sS)=bXt}qIsk?h#X$jQ>Ub2$sP0w539CopkFz!MMzn^7l)mTcgU5?8} zkmjdqh*ym%yON=)TA@Pd16=w&8GA2|3Jn>CYoYUyfopZfz}2I+*Au5!26m@Y(+IGB zo{qUzc3LXiU+%IpPTzv!#0n3rSvKOSBw3E@OL};Yk1gB`3O`be6gVoGRi%^bIx7(_ zVTEim;x&-Pgj)amiOHw&S}_h5vJduVHh~w5ka{eGEe<>5#T%Ke>1v}{C%xmV#pZ74 zX-i)nIaH&cf_i6TLqYfa*8024SwU998*hvDEgmzIYt`JQ1~;>sL#~)WPW0yb2A9u+ zZnX|lk%D4x@Qi56?wWa9tKBk;E?qvZnCcWo-^QmFa z{A5w*+|F|2!8VJ@mRkZ{F9Qxrzsd-992oA&lLSMo}Z4>Z+PtgnaJ zMVA@=x;0;)6Gj_k=8tZ zB=5AtYi;5AZa&w(3|5cTW(~#6(JzdVF-G)ps$m3|gIPmtXR-oovgsY{eHhPCVjTI()9Z`%>9ucNuQ0;hf|z=pwk6f~&KEgTU`d+!yGniJoB%TzCcyo_GXG-j$@N_YPoF9GwkgMB{364fA8{a-aHQ>RazU_0H*q-zDP}eZp4W)=YmSpZ~R9B#cdk z1%9{zg-ZG1AaL+EQ!uwM5sy)a+!al-jtpJxlT23?Y%#=tqN=v!8}dU}IOiRIx@IqD z=v1tj@V-R+{2aMIDP`F2Q@}aFBsxaV)YNx!KNZ?jp^pr9#VZt~enXs0a<4^LM^_A2 z7c-ifm>F(uaP{)@zN5=oT7SS00cqw044j1i*E7Z85-RXye}33_xxxnxuY3YRxw*!{ zg=sIB-vY{JQ^}`o6HU&)s?{I10uJg*StySz4$OR;J+dA3mYA&XPGOCA64~O52Tk{k zWPXu-Ede&Hm8|*5WPZ_{>1Ug1l5X35_l1#vkPQeM7=>o{7Z2I4AM4L_d|-z+O+hsc z&UmrpwQqt81@6Ur&P4KXDqVUEe>Eqq8ve9JfS7*yR1znFh?B@dWRpTwF>X1cozK|o4E9zgB)J^5nKauA*A{%Wvt@XyAp z){^ga-fS|G=1Pbjw6b+)X7V5c`p$c1kr;s9(eqm_^%46?_wKD+&RbnZ3W$so}Y6&(y@k7boB)K5)5qrLV{Z_eH|rUrg-?Aq!$o1l`{ z3H7+v-Em{d=oRHTK37A1WbDmX&5QE@;fL~lZA@ko_aAwF9M93tIgi14L*dR%0x)fC2;@bU0Q2^ActJza1zJ^DRCkKtFY~ zZ8i0i?5}1Dy`ybY-v))J)EZpOX@FKK_@iFH@uqKCdZW)dtg_m6YjR)|?e-rl1a9j~ z#Etb`Ba7$z1dMqY?@@+YXgbc2$%o8JSRk)mR^^whGxxpjR$`#w`Fr>slLV)fgrwE? zdzg*@NyoHj$I-w%>x-H(V{XvdplG@9W+DPIHJgeQ)B+8xmziph|{ zbv55*hIo4*(PL(LEKTdf)kUYTiv#NH46t8O1q+!>)}_SjGz&85vNK? zO?e%nr9+!iY8D3@mWTJ;kJ)$I2lj$0GG}KcmaZuHbIj65!8{0r z?`_aW!2#mqq=zZC#N~!Na><*on^LiySlBZE!0r7V$ObY#=EQxa^f~6foV#zQqp3%32W1HV z77W0FwEAcQbi#2`C^A574oYl?TCoI6li7`Gh=`6_T1rKCLa_zD0%U$$^-kC8lV#et zt$FD}?y{<+*L_DrPL0@JopLFB^grS(=1PP%FNkW$Qtw?+*W(t|0w?!4hB{U8-c)(- zRf!f7b~m%aZo9%J-^NaaX>#Sr%j&s{rg1f{49ubKx6C@wwhmb>bv2(S4OLoo)@(Pg zlsD+t{BKf<(n#Ic9^Qd2m|Qxcm4||E9o!_{Lbsbvwp{0y&6`&$n?6Yn@iucXTZxv^ z`}t?qJ=?H+C2kRA*UJN+yi6J1@EtR^vbCTwj%+*Qf0H$y@jVNd4H}iEILx|hb#pEj z!CA>1Ru>Dod;JiC#!2}BnR!q5gpZ^T7RGErb4*DV|HN^})d8La_?_2BS1<&=9 zBMmuv2u*6tROg9jR}QtCl6W$qk_%L7DOHz$MohnP)sT%-FLwR)R<`4-jO6PAz9%!* z*_j0M#dtlWXr^&WV2B_^{pUGpG4OkAG(xNBrs@qw^@tZWE3Y?l7QOs!=ih(oS|`jr zV<0RVGgr*M`CiydnDa8D^(N3EYtj88{Ecr3jWed($ICG0huWPf>qWA9R}q@suY5L# zI~H;nSzb0(uJe5!n-_%ggzt`~7krmBXKE%3N^cT663G9`0KoxLf$gm_Xj-5P$2h45YhR9ONs@z!60{ysz8vT&HxcZF$eo4LAUpzzd)&!vG%#!yje zP*8ECqZ>jjDPIToByXmESE}@$dk~j4KdqVfe2FxCcdK<1wf)vdAPzF-Ia10quk$BD z_2Tisj-0GP?uj3|$S6A~Av8oLu+~(v|S$jIyt4 zoHIlzuedhjc_#XG^Nak+J6Nju79)tVkx5?klO}1ade~CW1 zxDY3UYoe#2L84~u!2@#L;dkDPsqM}kj7+nw=5dfN1wH zf_ZIqQjGKc3{Qk_^P28;Gf5Q&Wh3e$lKuT>wD+9wM!Q7XSPrW`y%z<%s-wN(KKB$` zicYs}KDW`W;yu}YjiGxG$15MSvN_V&=Es6e4m=U5l>ZXmp7C4K7|uPFp7%HBVPRp? z<0RJi-9(clivxW7z4Nl*0lb_$G&@Y+a z(c6Hxs>$2IGYei{@s+bvz!fVjEgrgGZp@`OYIHzA5qjY1N+}rB^$=HV-t0 zd;QR1rl*7HS^^!568Wsh7BHx6{ zy(Igfzk7MF+H%>PkZw;@bujm%)u+OS$6$3D*?&&Vjb56Uylg#lXMJ7fzgmxA+q;Di zQCE7KUyD|?M+fFMW>#liQC_Wv=y0C?{vGzH-c`~`jftbG&IB4nLNLg+AYPH}`UaQb%-D6zjKLC+JN`Ycs#>pv zPxJ3j%fXeo-Bh2R6%A2XBuGxi#`I*MuJWGwa0RSW&G00+kEU>tOnOThfV#oBHwTN%coaOtx-Hn-jyyeEloNLRhMT< z;^l$;DwgdfHt*FxrPCk$37B$5^3*wb6ykRSzL~8 ziklHd*c=r_Icq)(<`1G#S0a(^NJ!tJ3K$A(ihGKWP1}#fH;Z!mRhlG%(#NNRmd1*q zS(;~82o{FSjCdmz0of%bN{lUK-i`5HuSJj&+#S!67BvS@!@~z`&hPRwq*s*_%+B=A z)$Jj2y*I?fVd8t?rvK@Bal(pNfRvP(2GmYSS?!MSPvgqARJxQjqBu(aQLE0Im8A^L zx0qlK3i{r9X*x5cpkw4(jQPYSRDYjvv=)H6mh|Bau2z4zzYO0Wgn6rvwInMWE831_ z*%r;uHC$?J=l>m($Ffq+Yui`^Px~t72{e)#3HFPv%ET?72g1}!x2}Rmf2*L4<2>4y zTr};PKR8e^^8#?1rCLg_>tRKJ17lpqWBj7EE%th_jVyYCA-<;I6VGs+< zG``b55qkVH%Vn&yYECu4h9+Cr#LiOp5pg!8l)@2a+cZKhQ~q= z^z{Djk-8dkKlJ{}wp$Xn&_%(Y0c5ftVNs{e3;UIaQ@aY7Vj^Fuco^0!Vj*7CZv$^$ zy^xK!&p6d%TKgX@fG4E^YcLKRsgD=mj}1K$xum#uWr&c+Dq5I-GPVC?RZJ0RPXAZe z=Nau>{A<|k$75-bAg53{7WL1=rn{>vcag0AfgY*=Mc<~)OWG%eWCT&P%==E^xcZ52 zKuw*^=`v*2_P+WDKNqT8AHi(+|0u$UA49W4FeQWKjgxj3Z8RoX94Bi_tm?*2 z2yRY;CZ%G@;oeK`%s%Ws0ga~jH2gQ`CG#=KNs3|uC{ID_8*%*7MZf%?uVZ)X|**eU360n2_tQNC?AZAgPN#E>{3 z=Lm0HoZmBc`#?cUab}xa8N@($Pcyu+2NCrc_aLXws%_PmZ7Y2TFYC&Nvu)F=cX95< zElu>)_G8jeY67^D$6znAy_~N<=6KOFyE+C%<%R_%s*YfhRRz`4zPaBCi%yjKTiuet(-Bi1v=c=;4R)YP_oGe4J&3OYo%&y zfi9oUre;G_ool~O33$w-l+pT(86)ZRYy(@j{%Cc+ZFW45EBK@L`++Xe)gZn2Aj%eN z)(~(CUp^IqU8vAgud5NYx7p=XEIdM{Z z-%Cez^SmZZ;?N6(gjjq2r7wieysWq!jT~=hi1Hwb3!tOKh(V%i5SxS5n$LNC%cUQG zqLk&vd}n?U@n)=oi;I=LqIB4_bzzgo4}JXlu#piZN-t?*XuiM1^bw-Kusm`Ix#?(W zs4gGtY7lSiz7<7rlP{+Fzi*N#!K&MfJcrHcG?p}Hbi=B7X3RqHC1?A!*-B$vV{Q(Z zIQaT_GrkO5fVmdw@wZ-?QL|EX+%tkd`08kPdJ5(pE>&n!eeFY&$Ib4dE-!M&oP=Y_QZ|hw0 z+f7o3?|i4TS6HhUPXz0?kF&a+CoG|;d}BO{#66U-8T!z_T|IN};<=L+F!|(Q(*|q`?Q$9^M+IU%FB!U?e{$w_JFJw=s%$0*yEa(3DwOqQ3kj!kEu%voo&x!E?*T<<{}q9_OIB_ z;_nNd(dj3rl=(Nac2`eDS&W$F&u!I8hyc zwFXASYDkl~>D*Grw{{^-<`#=AF|B!Et2@o2>#J*LlIm#r~X_S zi%LkW&LJ2QrtabD;L2-hYOVRV@E8Q*3~0KY9dh9@wAocqsGJ{ExE>f<8Ic<*qa{?A zR5Ni2lxP?2ryfsuT8n6BO?9{Pav5|KLfIrkrS&B_aD;?zO%iMiDhyVLUuQjTGU?2VH%5h9lCOAISnnIp<%GFKUQobf%szJG}49`QqmjO~6j9RHI{#PO%a98!{CBfpqPCXJehStxs4IQh5l!C5qP zE@FEeF4^L;hB8?le_k66{dw)tR$5N*to_?JL-;sy*rj*p{=sEut6OX~ZVS@QLpuM4 zjSa|fxg1Qnnz`V>eaX!$l*{=;`9fF+^$Uc}JO1|K{M6Ou+Bvw0NliHs%Z*PMqAz4s zC_T!<`L@$}{$v-LegCafBXZESYzE`-#^ehg0o+xo*PL`d2zuBL^DshWJv_eOab_&v zkT|VKsrcKn7%a;A*FTXsXP$LEPJnOV)&ir6MNAwX_66NLYS#HB^L>04&9;vQL;RV_ zadZU5buJnnOS%M7W&|;e3;)+7%EoNJIX~P}y*aL5-O@iYdzbB2*kV{uD&gMiiC#Ww zKh^$fS~L&DP;^kH;VOpB<5u zC=q>U7fg_n8`i^x0%X?(i{KJuL1sZEz(-|)&uL$f=k z2#vSSO$$22?Ko5J zNMvK)ki}*qI8ZPE)B5;6t*KOe!6s6s>7(~K`E{IAjZY=EeMhzJ#i-{rv$}Uy$E5R zgs_J}da^M@i1#~lwhJ`yZlvmUIO60cTG-mO1D4o)qwC<}B1ze2Fu~*lT3Q~zK0ySM zH=ZeMa1ZDr`%F2uXN3+UB=8H>sAPVEVpw7ZxDntaWMjJ7m*UK!)JQAKZGpasXdUl} z!QWZH{{%g+-US^0^Y#ppkIeNYM5mEFq01N|TT1>0{C~&h6Ccvd?z1D()y(7Q&6h@h zPl(&`_V2Z2M&NZ%HVVVmo{1@puN@@cN9P~^?^d3=CEp@#}%89on^qh~@J?mAHajwyfGOck*ePU{Yn`WO2^DB^a5zq}oPgY>k| z%@5oLD|2G3X^17FfoB`8cg=v}enWf|PBylpFBUtF~3Tscl$c3VHw*;nSzpLYi( zS_|BqSsN<>}1S6x=V+On!QL z3b;Q>`lMuJUy5qrPX+bg#%~2)+qv2mL7j;(`F(f&tsg(sE{Y_Vn5l z4(Zh^h?5wc-R%Vg?q_wi*UcFavp6_8DJv+rT^$*?xw+-br2)A$#da`2Aps(dVY#}R z+9a?F{ia+B4j(>zu&|(orgtYbbbwX4`IMDM7|7&=d zg`Aw6ho>G24engs-q~^49`Wxc)rc}S%1v46j-dt*?p1;z77mWYhY!li$^c&WvF78A zmbij)wpK!PbZZ~&((&h=ogJW?=O;$}U#25B;fAxewzh>uVQ_Hpw{NZBc`r1BsFrzf^HdM4#JlTLWK61~YflY&!yVF~ zEC4G3NF+dG0Vhnd1{!#?02%-j$cT*mQCLVzO^t((pBx$a4$ua_ks8Ml;^1^@OGG9n zenj_cXy6TOD=aNFO%_p57#qv=MRRl-=J)1bSkCfdP+5)pcu#j5tC~S^4bdd>2?lQ0thuRpo4O2B!hjW##l5 z^gsae8%S0dT;LBxStv1S*B$LmvzbmRtE%GT;R$$N{cLEMnVhWkr`($=_jUX2biTBt zzp)RDke0fLhDH)abi&gM6BCnurm2InFue+^{@Z}#o(p)kJ+1ODb(($4EB#OZv9X*h zZrgb0BQYLY4k3+TcCZ+A>@Bur1SPPuvx|olCM6^U_Rn$(xSja9{Wh)C(bfi*A+c7# zjNkk2Dg=iaP@MQ&_RK9T@IVVKn11Mg@n7EF&46SEx;PXRFe<;Nrlx}Ds|zqZ zx7XKE6iLa+J%5hCTQ^Rx0bo%U@Wq0H?CtC#tI178_~6d=XD6qp-GHQkl9Cb-=iZ8k za@()`0W1j6M|6I6_8Jp2iN+PoUUpd$FsaDM$QT*>0l`MK8}Jzg>{mXBi+5}dXD7iQ z1qZ+A-hulCz+B)=yu1wnTmhCLoW7A!+vX{?OyZBMEJZMVbalOtmVVdOaT7;SThMoR zIMi!z=Ow-~_y%saIQQmkdv$M*5Cg;hc%}XO_wT@jNC_f*0c=O{+ETC@^DF>4P)~0W zm5BFyyP;r)o~C9n+tF++nDea6sDuC=x!Ms%z-2=ShlPbz_46r}yX{qt%BEFCWo1}s zD3~p9zq-0;`1l${15x{#+ASqs?N8U=TDM46-cw0Z4_u_I9diDV6J&Kss~q`3a>01Q zsdo6IU>Ch^*Uh`{>ohSHlnCo7(`dvWw#}1*Km7u6o|kK^5C$p!>bi*ffZ%}U{V(f$ zs-J1j=aYn=;580tlrL5=j(RolO>4>uX&sr*s>>62y)qFqAu4J<4R3-XzztWoi*kyq z&1oJO8`#(gxZBb_a~fV1GIiJ5DWIXlP(vuh+??*a}LIKoMUbcKb5qZjHOH^B_p_|Z~P5e>XBZbCp? zDObPS=uc5A(}n*M5)z`$5FctP?V1BN&k=SV1qA?XdI|?1VqkLyi?Q#QJ^&{+H8mB# zk$h49^Cw`38asg1%1Ty5LEvaZ!_0h`V%vOuF>4E`mvE$9TxzUsO~cWY)cAmHb#ih- zM@N@4`=_rjv~v}hPk^cfthncJgoK3P52f1m72fwZOG``lx0h`2l}=rZ(^IXjBHO1L z;Nl>Lw4h}UTs-JPh3gsw*6ex&LlfY0vbD^tt&0JY4imEyh;CjHa01J1Y-Sci5p-WK z+g;YaC)+(6pYW~(Tj|>xq*ofawn)gx28N$E{(SoQ@god%acdAEKkb9=8E%;Y6ZVA) zIhkbC2uW9>K68UJx07<$Y6fG^!$Ye_laKA7@Zz4^MT)^dl%(#dTKchoAoRe={y0Rh zLk4!>xzxQVdPYxToA!<(YsS8K%1&ijbPnJH|P}e6^PT*-z}(Ha(tJ&ng%wZ{pNZ^Oyd*gpZG( zn}=z1SgV^Cl-5%|DJ$ocl9K=boE4a+IAs|#L@jE{4$vm1*XudEn$4*<}Vii%3K z2RZsv0MY@k1%@dDkZdzD22CsX_xF>2F9#TaN#iLd27FAJPdcE<3rtW2;1527qoJXB zm*Cc`iE*0TwhWM+8*iBs=&@c<(vu^7t9Nb!xYLM;2nrop*^=$(T(emAy>3F(&b~fC z8og-sM*%w`m|1}2b9pc?EhB@4^z`f3ui8wmps?7NAmU*4zPm#T=N!Z^c?pJ03a0pe zgPV@PmfdvC@IHIy4`Q6GtSn%Q^W`%-Iy(vQ@SL|to>7n2-dE<9DB3t0=5%QI;^LNiayDUG-`t|OvZd5-+m zEe`m!SndpU(uF zFWmZ8WR)9-?-*wYzjdw#JL*cnJ~ClDVuhuq%JNkW+A_plY?A(t6iBM-bE30ojL^UO z+9cjQE$eyq@a9G+_WF??8$=YdNE@JvjnE&~!RFxT2#|}wod)*A-n^7Cq9ZUckc7{L zf#RP7IBCm_uX7f6wzkYIEvcxf6XN2gfp6E{t)i;h^Fkr9V0>sOa&Xhk#AF^=1W@wt zlQ|zqsUTmvToPYS?_qdvx_q!17jr^m#+64luumJM_9-^3- z*sBzOw;6307f!gT+1V#>Y`e|CPhn)-2YyeOoL)k6l%G?7iu%qY#A^JI;@pFxFxw+XI1Y>ILX%7bH@s${o?N}+Y37f$T_q_xG$J^c8S@{IF z(|5W`#2UiUzQMa|Z`npGuJSf+UUg1uX!2@Sb0j1@iTXsrwnrzxuk6uUPY1Vjxfti* zmi!zJy$4Fi5#s1Jm)xFG;F5iyLP;e2>mQ4spRBgxW5t33&ysE@>__Re;&{=GtK=72Zz^EozV%iDDUhne0?rx>6o(M4Gji?aeF3! zFBUF;xCw|-!32=va>(qJcUf%;;1TB9=IYu?u-O8N;Ne{T6F5My6v>RF=ninp@rVNU zAR|N1+??k0>?wG(@K2rtfS2^3kgb#0tJNd->9w`B=V-))*w`-jH_lXI0J{fFKu|v2 z5c~exnzEu|G;lW(6U~8`FE3Bk7W3@<95}Iw1T%or1$;tHb@e6?{J(v>3jCfv#{0x> z6xmcmxGx~~X#ewvy*w7+Z~?W8CK&i?1n>0U!`xnh?J3L#?05=bJ6Q{VPQ>Tp`7k}?Z1FI1NyQT}5XZhmLej6C?nm9LjgUOwex?EUBRj8u z^+7Lv^w-G5ID<#5ri?E(Je;w+lz19RaIzjAoyBBmH_pDiw)^y8!IKavv;!+=KMSF6 zqzhiN(+xKb4mOUhOtPa$zSxQNdWpsJ9p64EtYx;bys#v)A>mHq zHw{0&ok#ihX=g{M-pWeI(rQLQ1*Ctfsh|nzY9MJs(H4aJ&J&+XHW?Uw#-wjdJQEpg zW~gl82{AFND=RDe`y~YhUD}E$a5{}H&W?^ss;bZ7HZ=9%B6UC9aGZj8fQhXK!Rb!f;tcl$2t6*MV1ju{CV;>kIsg7cYPt07#iuRuKeT;hn31 zEe#eia2a)Ubd;6HK6LZ)@?uiUf#}gdP91oQA4}sCP+=5|F)1k^2?uCd1Iu=6>+2xV z@Eny8xF7Q9AAnEL78aMItfIovs9Xz3K!o8H6%NkM&ced*vZEu_RA?*l$!b8*9bZ~S5yq-L9rS_HT9x6 zI}33~hWPJO-L5a+vaC$pB_*gplG3uoQbap+_}t%emIWg;2iLrp4R5#fRWpwbBu47q zIUX+)4p2ahX!<;9IZlhCc0KDl##P}2(CXt(729X7qr+m4o*eGGAw55B`S^y@LEAvkmsO-pGyvKlQ-96KBM-IbJUPNLxKF>PwbgTN5Rc8mQB6m>%_c#kRS= z`P6Vz(PeOvKReuzTdj{CY}*ol!Ql;vj9uU!iEHab_dkL#NnEFo!fm4(1V;xNiBVBx z0*_6_#i8A#z#|A63HjJ!isau4k}ZHIZ5q#w>Bj{l-;Myg52Z6b6B8h;>ocvINii`p zmVkK(egSwh{rx63g;O88MKa$}QwMhc3jNA8%qnAnB^LA{3!JF9xEQzqfUevv@rp|| zdSp)#xH7=20Lg>;`ugbEF-e@MtqElR){_&5XbNd*X^^!7mf{H8b?b@lvmu)UWfD*O z#WWl=Df(V+LOD-UMR9LzxGk%#hyW%a7ykD<0=$24H}{TY`?z;9{G3$ea?p$0=37Y8 zI?SQQ^Z*HBi$Ee6M28=C`0nK9K5JzyVH4J2f1~2m7&?WX%*Yo?Jr+#GR2)V9$(*p4MEkx@HrrO9B6>jK^sboM(!@H@ruSfRzCASjy#;c(Os25B@~*W zTi*JO$l>wT^Za&AL+$0HUpsY6Q-#R(-EWB%s?o(|w=$vTpOsCUGko&d*(8T3?2!)$ zQDwfqRKy$oyaXxf7k5)vP$6oW`84%PHL*+E9MoCobC=I+Ve3+en~$DqNO0_0wTIAE zw8b2=KYEWH?AFVDOKQfLDWl5QjalJ#ax0ykc+R%1Bk`Yt9BAS8zy{5 zDozd#4zin(jp2BQr*NPA<>d}|FGz9PK7&;AW9NQY^K(3-6Woq$A72W|ZM)01_`W%j z!$(aY5aHMJ<1RYptQDh$O>_&kjZgJCOw${0> zQ$7iwHBy>uv%~7y~FCs)rscY_v02f7e%ABTtp0w{j-?7WpbMHkm7S*dY=Etq$gXtvUSYVV$E-Nx|{ABD@^D? zMbWVx()K{KjvVQlR?Dt`_v4gnM7I zxrb~zAO4ueVt<2JWQj(c@OB_1BwX^%6ag*4)Fi)fJfwU}^@5zgK^)|fc}UTm4>$Vf zRvP_Xp`dwmOwN7=(!c%xCh$KiGl%+=jYy?ydky{WpH=i9sK4z^ew!ui;eJx?QDwEZ zn~g|PaGSAJ^b#(ht>av?(fZMU@9U~_!Q37{rIFEja{ZIJaH@dfNjOq^SgzSChf2rm z=i(e(G*4?X%Q4nW*FWha!1*Z})e_5aKb~H;=y|3pij=E=ic*8H6nyh;InhYw)#MnJ zPzV3?A@-0!q1L_ijovsma{{%4txh)i3q}dWI-FBaTS$<|&J?m-3vSOoYeez?llL~b z>l|C`-nCrYf8PBkWKE4ZT2IpKmdgsmO#9YUcPWuP+OWv^;&x*UTS%oT+qIF()9I)S zMd4u9LWc<`{Z~$)tS7&^bIKiGRXefMr*Env903$Z(;okeFK$%AM%(AS>1X$kIptMO z?EbDwj9vU0&<3I}r%~XQaqPUH9qZ_FQEwnM!NiCB z@j>rn0@tmskfb8(yFk~OYBRN}Ma4!`=Y|n7oC)pa9f`u=^#SG)^Y|SiAwJ)^PR>S z(!JcB^ zW9?(e>7^^=g?+&dY=L>X7mUTN8^zJl(HdyEZqEDy11s&`zw(M^BC4a=5i)Ctd7mFI zoWaAE8XZpDq}E-YRO=dIH1!eF4HV{p?_|ko1rpn3y0D+!Lq4SJ>|+3~Hf;@1 z)8HE%GCYi;%6zu>-&~8$4J!msIcn}sSDGCh9895t(*a>|6G(6OKa@K@XG!{hDoc&X zODSPH_KE_aig;qjPMqly4yk8nz)S(E*uU=@d>a05rRksQmN*}7SPQmuWBF#sS1OiRjsZx7e&=t{V#=(``*rNg~Hj} zsZ^r-n;Qm!EXr*XM7+k*6std3p_Qv~I};DS)ldGOT2K-=^;1Z|9=TMl+3O6+m4$KP z;MShgMcZ;V@XaTsIS78-&-Nek%e%~y#paa4ZF@WB2fl;lZ%JjdZ*&xs0NlvJAjoY4 zcTp49gR5vgUv>7L@gROr(-$Toj$39;@~(||7M^T6*-M-4?6|zCJ;6P^s$QE!ZYnAg#CtJxwD^sUoZ3s)<*+w4 zCbBQ{6j{|KtyQGuBSv>Bc%@##t>iB{t)Dd9p9MVqvV*9n`GQKXxIhU(2b+k0uGPA$ zEQ*r-Q&5Tr-St6tF8r5Joz3F4%9C22C-XY{jG-ln#m(_ygIRwI80bNt2s%O;J-Qe9s64jVNE)T>Xa1^H2^C1Q65OG*$43|wRQfWpHJ|wQ;ypv;DnZenx zPA=in-@n%9VtZrXnnWp@{}fW)Qrj9J+hL8zx1F_r(7E~KB|Wh<;p*d$hFxyB$T-xn zgw@LHyNWjcZ6n+kMIP0$wWnK$0)Z15P z1mJ14;v#bd^v!RU(UnbET*Q$_OBQ;=x|Q0jteS8MHii6jlwEN8d03_N`OihlowB&s z(exOL#AIYTl)H$`! zUVE>(=9)8w%biR=BQ-hA(qI|wH*?*$17!lIr=U5laWQf%B@1?7CT;BvW6=+K9u~Es zK9M|1&OO|;uQmE9zj0+?i_PlOKN%R1X)3DdGcvwLaGdXzg5C8N&QZWuWO!D*gE`h> zDX!M@RUOnqFZSTS2pQStb!|hP1%x@}r9C@T&Abf3{-nHBA&|fVsfrif;t4CUR>v!k z2+v!j?X^rt!U|5YBC(3^7xqst>K8D?I419-jt%g2ePa55|+` zWWJ>y4q%FInz*<9HNydi-1yP~CKYD(Y+Wi=cnN^?x@Ny+WjH96z=ht8fWl` zbJvfg7~_=U;?U2%79tSsW!^&5)0Yv)OIFLZ5mJ99sUQP>pb|g!$7EDImO|OI-W*am z-CvE5+(&e{nc_LSn6AA(Pte}0xZO6!jt=j)zB@lgjT?)9eqpC0^4f#k70GNUWaJ_# zZ^Y>dfvt99oAIe=&cz{K)TLXt7x{1F8Q~wfp_IhCC2 za~ts$zTWaO?p;6;X?a*$+D$M<4j`I~DB*-1mNu+|XHV2vag znf$|ITVS3i(Ba16s|=RFN{5+v`>{WO zg&nA%h>(gs|3siJh_k-ZdGAw9`5ru_y2<006%P$au{~?jzcf%ftR4Q4m|DmkgPug~ zPg&QHT?*)iNaBKA^+wxKMIq4TCepxdeHV!wc-RcI#{kC1AN|FI zVSPRO{mW*m#E~Ij3oS}7#_08!~D|9&{Bu4ALFYFGWm6e z3Bvzmk{5&0IvLJDbHo#;3ynT`9Vh(Hx zP(ywNp4J&=Q_3jRmop5HVi%f(=E9XcQUC-M*s_%M-(LjOJ6zcSFBiQiS->wk6s6p5 z?~)xNL{y9b=a)Ux4CTbbt+s+NbFeKEtf!OFhSTkHd*Q;uewNoOgRaIYVy0>L9^QvE z3ZilgZlEfcf8hP{v8_49;a_G|s)|cUF))YaRI@nO3dTg$DTyb#s zbcw%3ycR1Z$iIe&HTl~WU|byk^E{G#jyCYWWR-!IQNkQ?pB|oqrSkG}o<+H7OBPRl zxZk_wVH7P$oTkGD#xODy$%`rCvWh}W$p}Z7s-_Mk9cSmP`xsF&U+*-}L5fof_F`s6 zw_#u?*OQWt+?H7KXY4r4{=b0(Oq~ulF9WyB)ps@rNs;r$C~L|W0+U)Xru1KdnAD+_ zE&T*PrdVf3tAm!)1ST<6B3|qGHtJVWXEJy+k4+B(JDe|yLH}VI`9laYYT~JwG7I4y zBMxazvmFyCcvVPA+A8U;zb;?QGv0a8=cRNqMGepJmabXtmcGl(DB7ZlE`XNC;?=Lw zq?E+d&Up_{HZL_lo`of*EBr}}k(o1I^={C??_~XZb|CB*QwD6t6#X!Gk}D`7wrxN)pK-5;nSR12Nr9F?Lo5 zJ}VHky@d_H0F5o1$jz*%iOa&EBo^!?V*zAZv`71CD50*m@}zcFCw#YJt1+Y!-ESef zFR+{22fN$BB-}y=y;47ac8dwZd1ymwRYXltoIR9e;YA0_Ed!VUU1r_>WZ^ugq`A*U zX%Sj{EJw#^9Z`oz)ZbEWemCqxth-K4c!5r=nX##L+IBMzO!#fD0E^Y?=J(cc1R>eE z$<_h?gbuf@%IG=Knk4oBOAgokrOYhw9caT^{yBisz(FB;lsN}Z{;2CE=psPs`BrsG zVWH;ucqt`K1TtT2l8-kH3tmQ!ceoz91^rP81-z?m^WPH&{KV4xpzs*FzTesexZhj`?iMc|B6l)!Pm>#92g>__Q@$)T zoF$!K{g+n5;O#yDl2@3R2%0Y$5I!l%{gtj58)C-4=`Hzj&OBC35B+SMHt>g1@Snkb zve>NQGJA&n_TS8+@&{G~z&vyRp{k)ES8i=f&hGl@)*P~pN9|!E%wgY|uh4=p3g#9TtV!iuU7sMua0ugwg*gio%p11$eQgN#;ER?tQ zG9^3Rejj>un9(@6Sr>HjupD3)dN~`Ma2pro1WDBtdG?(LPnAn8!8~#e#fTRU>S(iC zn%6%FXjC<8zJRSy#5E3${f8r@P}3Zz4JEpahRijZZ}8?G%}JPv0KzT%TT1=oMM|HRGglZN5G zgf|eQu!5SnZ|NdB-5C@O_}uT3XcMLH*+x-#9LQv6MII|;s=!wN4qh>k5Gw^S9KthQ zvBw(Xz-yyLTG#pMg}b(cv68OpCAEl;98^SXlY)8hN6H;r2^k>&xq@y(S z=M|>+Zhv~z-{t-MO&x!7Vq|T7-evLreTQ|~D%U@{0GePF=~f0PUe%Q#^MPdvwD5im z-hXs+YvvwnQ~&n=1HBvW7bV-j^J_xVH)Da;67!pNbU7%&+q}6*?7Avts7aW6&y3lT z!aScGUGeM6b=pd1w@3!hS|^{Zyp&GCiP0gi{*nh86N3V*|034r>Z@FiMRgk=YAfY1+AKI7cSuih?R?B1?r}DS#`P zkx#j!_3j7&IPA1B-RN%}ky`H?74~a(>rdTy%8Eq02J^HsU=3zv zT-y$=w$LSi>04)aQ*sVd-l?Ycyu2`L8vW1Fdey<}GFV6@z`5Uy6nXdRnWe=c^>@WK zB1j$i*6Ky(uvl5v)JtYfr^e0szTXzXOC^fwdO>uY)w`bG-gyJ_zOl0etC-Ti))MI8+>)|b!Ps?4H`4w@@2#cZ@>`;wWdke$~;H>p4r58lgnT+ z9xvZS&NyywP@;r@dlJ+&1kC(4(>K|krB&lVcTH*N$%K^eQCUUv(mq9qTiYWt++S^u zI;=p3u9}2u;%XgdD2_{IRMzT=ci2eW1`u1%me@#H8Sb3ivR=l)A&e&OC~3u&{^_$V zJ;gh2?vC{QehP`Hs?Y{{85Q`H-6r;qIZH?sg-j4#cdf1eFtA23UEvSm?;_BPbbxpp zCfSAg`BppJM$jxr@bb6+AL3N$kWPlZqp1KQ5|)F97C6DHNP@6{hOA@ix5xrE%F-90 zt$9lv#BcESpra&ybZ(A|mBIZBZ(dYFWoT|~>kk}o1d6$sYkvuj>Vu}KW3*b+m+B`? zb|k>uX4u%RF{p|F!Lw~n*tGjB(695KphJ(x8BlO-YKk4X~Lwrp?N3@PR z|7x;2XU4Iz3$p=28@H9!0Tx@=Ut4#?1x75sVAz#YRwf&i^^sy${H@9~azB3ne}$-` z4Crp*bTljhh$HztUQ*U@%m*~T)h^Nii^@}s@NI8awPGhvmPWYm9GyR?ICIdI3~W7C ze$Tm=EJ<(Ey#%(es=yIDYe#Z2GH_Eih>R*QRXZ^y!V+%_-K{pHcj=bqeZpzh_Y{fmQ#Pt3bfzPuh;0Gs%6dW&(fSRDwD2j|1G^&_s%jzj!lj#qR^j3WU02i{P zO0#c_>+#cqCe1P+{<)06p1avO^j@{9s_XXdg*$tej?qHS zyx4(U)3-@=DqIDjn0GL9*<*}qMTSHnJZ;W z5Hc@?i>p;+sM_r)3}^rFpvmd1J!_htOB-EM9?dX$`HlJHcWlE}OyJob7=ldSu7PI? z*U+7A)E_VFz?gn2=H+|_vZ_sX8`3uS7 zl~vRm{=ngg2r2X$s=E>(neD;V-A3GyaL@)p0e+d9nKO+jwk)-{Lz7jcGJac`TnrxS zXTG|a3~TieIRA5MoYC?8?Cjub|EzG67>O;^KVg(>ZS@}BJ#bPpt-umBH` z#GgF~D^`0I97;BtM1{=fpnfwWf=7X^HRrka#8rrboGD5CVTVBcqf1KJC48dqW3>tk zfu421{uHt2*WWt<$6M#n(mU{xfh(~pc`3TA8W5zwH2cxQ;3P)iT$BFQvL?t|4wctI zs_Kk#^Z;W(cW=2QGL<(n^*a8N;ZZI#zsanXWy10ZN)8DdptZ4Wo;5(XF5-bZrqfhf z6?OKx0aR<47)FWHyi7RKg{y5tLtdJ?aoN0;zM#Mu8`h66N=9WogPip@Dc`TPF|xZ@ z>fMlMf!n|0Y0sSy3Ggv$0z+*98Kg+jUr>?eDrlIWzu+GPVSR9$9M1nemdE&9`%hix zu%w}GWvG5fd2)Kr=!1=g>ur3Sm&e2{Tpoz8;l}lDw%u#D3J;CuEHfiHS+;X#Ql*WN zKiuv4=0IfYVAPPLg;h&DyVnV5yK8F@QS|+CqUk0fd!^_t*%{H zcCeMJCoivDJX2_|;jZ2JqbRc7wJJ?9!SVi~2Cj0yd2@XEHh1wTzlc#1>9nnwqj8(t z#GE$XXkU3=m5N8axUyo%)FBf)d!(*zSectk(|oALyMh=Ji~@EZ>dpRL910+d!;|1a zyI*g70@lMY!tYYE)C}#HM53^Yd}i5CsmW2RNu*pA-y)y&qdV7buzJ}bAG&>4no4ob zp*i1RY8W5s1XqF&@v!poMPTDHA%c#E{YBfhb-U%@) z^(SJ|HbiLl-t8*UODd}}YhFYZgL*YN9~rnF+S@(TM$|+b`5t~<(E=gBq;&NmbU*l7l0C%P5iI6J`0(n3|BDhTx+j%x_tO{gU%W)l*dOx{{m zWaMOV_|_ID{)Xxboa26DU@TmkM?^XMs$FYbnwDcEzJOLXLGG?6P~m@8jm2WmQ1Q+u z3D?bjY9__k{+8|k3Dp<~cGyxmeya@CAy{-~Y78%=UB}nzqN;fg_PM?18~CSWCkH9n zh0_+5#Ns?JoJrUdZd>0 zDKkF|(sa1cFH3f+dvL7xoqpJh@QG6gJgypN;y|e35Vy=Aq(Cgs;Ca2{&>8)yl=*pS zMkJ>-5?lP=J?MfeT+Tbxiplux$yROpY|%4Swd`0*^=^P;_nze|s4}&QR`xT1*!^)O z+#yBZbLD3HGJGrj1@d>Y_I8!(Q#5lOW_J~4r+D{yi^HjLW7zkDFh`Nwi_Mvfs_XCB zO&Fu7#QR$vA_WDvi@bbI+uvi2#<}-g&6dA4jE;w|uUW|MqRL;)uiCp5HSchuEIE(O zKGpd=_M1{snxWE5jt+&b?DUtdR8K@npW4{|h@P#pPSwsYrsLt;JS&OFvnQQ@avkN5 zyG(fx*(-Ir%ecMP0V65*Fw#DS+cq-dujy}Hv4ckb7Zk3=LEbw(HHRKZxi9}~5DLJ2 zYl&dec2r%QpTR<@Q!ik9Xef|}Oh?1lTs4Q*O6etPFAD=efuLVwdVxZQ1xgZaxb(2z z#BkY%sd-jQOZjh{aGyW+l)-<+Os?NpMfkIQ-6wh;=o^+iG$pw`p&FTl+-#V>X7a=1 zs6x)wZt?#i#FcQM57yz<+)V~I5RZD)T1R?KLb2Q<#x)2O=z=Ow!*_-6#x&=06@Q)eq-c?#o zcmzfsDg09d?&G1|3R9T(qcB%pxm2@UPR~roJ^*+aoz5a>Dm&V~*B}F9F7BhGRNIFu zKSt*Ij0}RkzCy~iU*w*SF)v?JTL{e+N8ns;BQyAl%5M+Xs+};!2*I{}BVJYl?jlX` z$Qi8=cSU=PWBu5Qb2h_pyNss1h!329?+RPg?%z_C#Av^8A>Z1`lK>8e!*S3i!Yj1L zI74hTToZ+NAf~bTAZS6+n-EJcDkh%y8^)S$_PY$8^_V!+OX@t|(dGy76H!W{u90F< zVY)@g-fnL`%iFQ~;7(&{SqSgu;IU{32l>E++QXTzy23f+`4 z<640d?x`VWf2-ByA(GYob%n2T6!VqWNvVH!#+)x<31Gnh0F3FPb?;s7?wBFZrt+7g zioUdN0lx1JzZLL7ZffULtX!aH$Ug0Iu5)T(KN$)j7CoTGONHKP#GbC>8BtS$q0{}#7K2-^&4|-OGLtNmbJXwaF{%*0VA`64w`4~ zFJe^_oVX15uiMrqHI~-4_am9OPnJiQkFtt-PA425%-$DQ-?5dqldwEGb={lC%Ly$z z6XCx~96oA1;kH6#*{LnYym<$VcA6`-AQg>zoeNIHtH(1Ho-JV4XD0obDk;eyGd-GJ z(1-^;ZY%fvs6!Bo-~ppPld_GBKXQSU_VUCmmO_`ga_OEJFLh6u?g znUkj7SjXNjnx1Jb&@b*i?Vk{Gm-jS3+wwZ832Suy+Cv5wTUYwyJm0C3urR)Rl8ad^ zUm2N7cpSa`DXZhMNV}|CZK}%ZsvD_N(spRc?a3cpfj5JGc93jwBwec3k&}|)!m{*9 z#g`g1gC=Q*P#|4hTRS^FmG(oXXCRKvc+X)KXwEb|^4veh&L3Hd39vgXH8mn>V14BhROJ8@k){%CsR(cAsG0pA4Zrj*x{LB z=DqcMM@)e73DxUw$7#mf*yD=$e^Zm(iCdhQN&Bp;-L|Heak8!x?U}*99e>9TZ_mgM zo9qbz)pHiG&YYi%7kpMJ8J(cLhm&l-wr05VK*TjWJ??P<*?zCdSa(Qe(+)SGm9=Ii zTfCc6`%fLi_LI3z#s(TRiR=1w9q*QeUmfBsAWEicZRQZ?)n|^Ywkeax3dt()KLJ}+ zWw^f%CE!U|1`7bEa!%AFcZbVnsV8zvFy1pV0>oNx(`G*VTcJEdlBc~};HCa4{FIDi z?E=~)9xk|spqZiA8= z8j-MoLC;@Lp7v#VmwG=D^@L3B6a0-z*@PLATlN(7V?4v#*rAx5+_mAnOp*Bd2;pOa zPiD5c{?FBW9FTR#j0if2L5-xvBMT`)nWeT(Fm2<*pSR%~Hjf*@nVb-&V5*?fME}G< z3?BIEZ@h+OiWkbU)p$Y6OcaPzwJQDSK}GT_NtLd}g4?_tv`=NQ!2K9bm|iW7PoBx5 z$7&|{ubIaSXQ$Koy75FNq;=GiGz!uP+tkGIhM)b8qdCZNbE2E0{?2CR(njL{#$)ib zjy6xlSzlcrZ#naS@TVN0Ep&|%7b*(N}!Gr+1j~};Rx3?RPSS@_yC#+w63@cavt{knAB1K}e)w2cX z`U)WcAZ$YZb0&~ni^r%-CAvyRhgSh8H!2PX!0UNkf5w>p|E?i^1r_vJHd~b z>0C%dvxDIl=^lR>&Oq`M64v$wP?Q#}1V>^`YwMrdm3F?I>!W;)Dt9_8uhM_nfJPH3 z5y;3%xO=bvgA91f4y&9|Xx+u_;kGunG{)s`%3Zwv3cQzRzv$=7D@tM4`J^W@O z9p>JaJ0|UU(p!Z`uE+Y)R$S0s;G{9pUmOJUahFC8`~ApySKL-zMnc|F90*fr(hJve zJ|h&;p?>-z9#N28Sy3_edcR9;27hyFKAa;m{E|8uzgA*x?H7R~M9A214&tfGWN3DL zF$(DAML~i>pb)h`XmKw{y5OJo`oo}>$oY&s{mtOPevCo_H<@5x;%e(01_q%?@smn!tm|~7S=x{8Zy}^ zPsHYdEn8F66=hU+#j+lZMu2N*WUIK+*VfGzWAHGFkPUW!PwWoQvk>W@zMkNjR6Q+k zY&FC(a{oD`Gdj70NcHbhHirY23O#$+IX`RE=}PIw-LYJqcQ1z8{Dr%8R$p1X;HXsS z%S+K!lmG?|)l;9u4rT^wBDE1SaGG{$o;Y0}IrV}g|E&a=64%38cKtTne~O^}^p2TD zmAFuI#B~#NJTkDt(Y}wjqW3pdqV2U&is4EBtIU#^PzBWN-8{I{id6c^RFqvOP31#Pa@4=hfqvkW2qNGs$e#}S(9Kjp4} z%1T7jdE!y253~LKyI{=7y#HuCK+YuJHiayI`a39-~ zM1bM{d;F7j!-)B|Og)mofQM+YW7>nEcpdUbN3DO}_8^udaQ=r*=db(X6;yawbyxLl zvm2uqJErSZ-k*lFjaBg!QQyNK_TNj%s&TXnmnmse|JlD9zQUg%M-?#P~xa&*L3YFXW8-HzhGa~oLPdQM|DTTC& zwaC8TUfkDFg~NY2U~%4SbbI7nf+%kMdtXf9));V5VlK#E4_3u>fNI%=^sg}?jX73p zm{(&l4sBAO-d(mKx*)nq@0zE^!&HFc8nshoy6Ty#;y*e9%Xy@XARy zXWW~EvCm+w$u!D!yVb9zSD4={g@b2@4^%o7Rd8Z~Ef=skne7*@!yI?NAJ9j;Gyd=3_b_!LO)j8vCfhU6F|Ip$E@UO4 zuwh)=wcyuoSW0V)eH}U@uC8H=hR%i%X}t_^>)n-&*^q5!GYVy|X*xaW6X6%Q8hia# zS=9l8#rK3;Ae+Y*B{YC?S2IMgGtEoDQdJ74%8s4nZ8$(p6$1z5yV9?k_;N9Nd~;Nf zO;-fbVlF3^Ft3N^WExNWm?K`xT94J<;@>pqwj#BL98?9VCK;9C0xcHP%N*-zca>*l z3l9Y-+HIRYvZZu@L{$`&vYy37d;}g=p$bKad;$T%Yq7-C)D&b&F8&9TE{^z@*mmUj z(R*D;?Md1t*w|KP^^=?qZ&?&cOh$^*tJ(PtiMaW11r_o` zjp0#Y;}Y}Yd67;3+JWeGyv`2Pn(ifvrn@LQm^!yRupjj{`>`Qe@A#Bi4rIEo>gsPButR-uv>r1$P*T@vXXnAb)#(w;|< zQ=C5-o8IDWroaXn7)>e)ihf9wih@E-2rs0yDkLNX(uu#Q{ojS<7eVrL)9C_p9upqG zezyLR*AuaJB;~=qM)!Pa#fiZhPc~hrOIN0-7* zJZJ99p?vC**gqV6^vIiCy;+@x z`Xpnzo(-^m2E}6NAIe$tNzw1>dQ0mUQ_G`biULXneu*sHi#MiAQEzPnw$%(eI^XG3 zc8q@4HpmI=4v-wniA=YDTAH(VJQutZgM0FL!lTMuwWF>0G*BALaKe?Q`@LHU5e5)V zpWdnp=CTda+s_WoZH;VnScn9d)!8yzce4BD^ZioVpz(VSE3|S`{HQh}Ox#84TRUNk z)>Ng<>2|l;Kf=*Ns;4+&3%G#jMO;VmJ6%*GNVGVYpzT-oW9bP9x|j-5TWnVb()3kT zjC(QVzLCtEsD!dw`M%%@{&P0up1v{1D?d3E$1~DSTsjA1r$cUrQna07suAgEK#KZ2#%x@>@&KNM99u z%>di=qFZxA$s>U+VT&fus|e4Ib`GZ99$sG2QuG3cLnxu2%{x4SLwDsOnUqCQ<}Fkr?u>|z#}t*Q+y;i0P0x!Nids`x$*HlEfQQh zs4UXTHW>Kb@U=sm#G)K^ka3=iI@k+8j>>qCz1!)b+Q-AqeolpyOb5?L*V$NsaKHu~ zI3o!3xzPE2hvGEpv>|XnY4UhJy%^@(UIIZ?sU`C#mF>%U|I#6aGN5`ss>(Y3i8E3X z?72@n9W2hBxO8t%K+SdRKK;A-Lw8!0s>O<@vmLRRlhWjpiAp$;H$hrOp3U)V<1a4* zN8k(rjTtz+Qx#W|8B-&$@-_NBpik}R3z8~?NDN+)6poQhEGWZWzE8t`0WFp@$e=10 z0pSVB{pw)~9PChCfS#jUJrB94{i47A+VR&cKtd~H2bPerpQmcPf}d163WmqXF;09V z;?c>U`uC3q#-B({d&6}+^kT&F^+^sW06}d@p|Fhw=h-`@yk$wjoiTSc{5#;(Q7x#u z1*c+w{RV2h6XD_LL??X2Hlty{ArVgHOD}RiviXaM?b-#Wu5j2^nn7;3RoH|WL*;w+ zCec+-mnAL$VA;Kn1O3Z9P|(vvr>QYNUllYX7$z$UAReTyt;hNRPzRml^)csMI4s^a z0aVz}mt@-5A0Nwhe6NciM!>8tBr6cp0i6c_AOeK|peT1F*HtuA*!AIMQ@X1_mbqCd# zu!WL-USB%lh2Xb>-abZ&5U*E~vV7H_(S{~kiyEdw9DPDP!#7Fy0tSh;wqFxtBK)|5 zLVpF=a^(5n@!#QN0=(5c+P!$xoU+^av3{wfROz(8Y4=bKGTVPX6s-z#_~iU$Ft~%E zbu|%LvG&4on*8St6d+gScY@o(GA{G#s#DG7x5oqr@AB^N^^I(XN-mzkd)R|JS`4{aDISob~iw z?xV=fD`+QS*Q24t&bAu!b&Dqc65aa+&f$>RCU(80?5}8<;#TBH>}oqW`JIvO>dT7^ z@XK}QT}$&7x|*MU1e2qK*d>FZ0nIqCv)I&`GF%%FBc~sz02}Q-2dEHj!qwWWhXj>v ziAkk;vf1!C5Fw&WMzuT<4B#S@fCp%5K&LgSuF4a56iifL{>3s};%$QW8pZ*Nv}A_9 z_6KHpkW51$Un3Z^KJF-jI6JHnK4{$aX>)gE$NAtV+{dfDbD>%qI?dgpW;KbFM~Z~@ zzwlV``rBruBEPiUknlOHyTUT*pya=*NU5EZbawi=X$|iWh1BK70H2Gtilq0`?UB&v zi}Gr=!)=jq%(+YI__}Zq%ISW#BJT5prS0}1>0^nDWFyEg2K`5SC0to}yJ2k%C98}L^W^pWFg1kcmPqoKmlCtav&BVGRp)|gd~}CH zGdqD~N*@xlRDU+z;vTJlK`oqTmwsv#_yeB3fi7Azzx6R{AGV~#DVDYCwRjW}MO2ld zl;ZAMHoI}kSx@aKl+@aG@lhlKDzxLWbRwYJ3$wk&<0=>i_o2MiurM!@EwF^*IP6SR zJ0K3UCzVvvo|lyX^8v(wmO0Jwj*h3>`x7DQ3ON+dP3$>bg(s=Bdn!j1coEVVI;jQ7 zigq=QXIz9a@m51GIXh}T_u4(v!Z(kfnu~>D&--Ii+dmLoTa)0HL^NRnyS5wVyDn{LZtlf;(D$Wx18QYhf^N6UXi9gG0WQ|DI2 zE#D+`)tbfLVm`LzxyfA(@!RIES0~*2GJK1?Z6f1Hn5)dmzssvf>74)j^3Cs{KdLFB zenF3V>hN=9=ZtR}1t-8k0TF37O%?W6meYOoxm$hqrqh@la>l7uUk+{UsK@-;Sg#1; zW)S1e60Xj*O-MzKkI&&?_Gl|)N5MKF;0SYLTg%1)->is!eQ%=1;t&WW<6}APHhze* zYLscM^>HIqDk_OzfT9 zzq{Fw5gNEu`cfQ9tH!wVI`?yFYaCc}VS<@X+Fm@>$qOY$h7-eXd4uA#d*Ic?G~uoJ zc7O3ydTTvx7$4Ht(BY%K*F^BB*^yMRBG$;_d5%d}i|JzslWAI=d(-KVP0OVuIA?~2oDOV zltdvX_CY9qfr%qqZHI$GIQ~|ea~7FC1f49Rw6bhiMvk@z08qc&zrk&+ETkjl@A$HN z8F~{h1f!&-j|HI##g}*MO-J7;iypX&Ss*|Gi0i^{b`WQ3%_+)%_KmR241f8HoyrO& zNG+{oXKB`p;CmAf1%rVH{Rsw!TBUzhIwLD(3YC>K^a*&A@Dq;s+mQzDumlYhqWeZ4eo_sr&#fP&Y0nXX zwj&T__8l%Ywfm{fb;^)>MeZ*+Gi|hKNOAkeGe`<&dmec>r})?$ZdwV^9{|vu+PBXv z?KC|o z)D6_|EQe|iF@TsEpN#@!YKrtm+f>}>6x#SCm2r>bv&Y*bPD{m1S|SsK$Jpw4qbO4a zukTJ7&L)QpAG*cf#WvVhrM_@IS9t5BNjOjYf{LA)BVbVPH(27ZIdIYT^+{NqXP7;% z@8o=+;`&O~|A4-;I4~@2y(kY6`@HRfn7ttQ`J6H2t+mu6BD2;iP7Gc+O4RlP$exdS z)MQH?qh|qEvYm(r%h$id?u`x)FHu2LGd1hVrYpPY`^w?Nu$5=`Pz=lBU;}8cq%^gs(y6W?fit{IPYrA3E-+Am` zOBFvrT)h6H3&5Mc+12)q5=#NnoPBVkew3r|%3*lVb5)vM%geaggRX|X>#;Zk9rdDK*9iKUsmb(s;4MiK?tTU^*DxKGwc#6YBKt(&4! z-4~qq%U-s^sqi#7WZR45#>ac^+r;FWb2@enLAFnMa|k$oxyMbq!KzquH@8mD5YyG; zClTMKBDqc{Tmeay(5he-nLRRTUnj%__Qls zX=2B+riOcM{!tqJa}J!ofDdZL*(4^b4Ppg~+>35FWJn}sM`nHeawAO!HK8-i$Fml* z-_U2mRM$h4dnpE|MEo()l`ZeEgbEY^O^w)q8d`c=EBYvrJhn_2-@&P!Xo#&ENC_C0 zK*`^nuu6=Gv(c>CJ1;GwTB$%KqAJ_i31@rN!ke3Jp)^QMOXU|Y(aKPx{k@=M37o@ngA+bXCsE)0_1|rOVnE$fGvO z%PPp0U(+V#xb}9m_3`eXCqriLQ|OFREH^pcyRGzuzSF{?5kZ(^ru|Qh2rKF`0^yRM z=i-M%g71;vc}!fHQ^=_wzTC3|$5h1?M&>JDe+^h%r2-IPFadS&ct-fOJT7eJzD4mu zKON(6T-jNifd!3xkL38bk_>DKq(B`V2190{D~_0N%AV zZE=`bn4X{czL>TiyxO}#CQsQwtRXbY1Rqh;`c#haUosv@m)Ef12SBOElZG6kYeIxW zRlCida1#s%teL`x?By{a`%!oAN7EBJXQ#Itt)PIUz{6o;!M`q3p)o=27!)N(J1pzR zUQ$At6^#xB7y7b+MlR(~Pe_E2u6$ef$qtCjp$XhSAwN)-A)(Sd|CWTWto+jgG2r7y z#3m}}^|1fiqBYFTE0XTRAM-e(^`AHxG;AXj?766n5rgwnq#_>U6=+7rTe#z;jbQUf%qsJvNQ4Imot>oF*$;vrWVk4RNy=8R9p2fb zDrURd{*nc7h@~x@(U!&XY}qtY9n`|Ha{Wu%V*Xk@lgw$Fp|zQns~r;>yFDlPv5|OE zBAfx#w(9=-T;KZixEf(ZRR?p)_wzSI4H9d7^AS7)a6Ff=Dc0aN7WQAi{epzv+w+pH-6?H4InzwI?dsmAaz^}KoxDmqYZ0I^_ptN? zF<=0Lx8T>FfDx~optU|`LO}69Z?Sr;97OuI>-p#8(p65#{o;~YK4CRw0lfG&&q%!( zeNHL6-Q0nUO6eZXjY$M_&D4#3!a1g+W4oE&Exu$@HpZVxYu}XK&5E1$9nWJ}=9u6@ zuznEIZGRM8&TaIUNcaGNCcRL87WggCuY%LSkm6rMUCU@JAoL zNvo)Z1tHlkMM0>Gk3pICRx~k^;gN~bZ-LH-WSQw{%kb*He4HZQ((H;V#Y+-~lHjlp z-j}q9p=B$l6dPD2)=I-iHu7qjPm~3kqFO*~G#vsF1u3l@CW;n_lS((l4}AJqEtCv_ z`_t(3ea%q6_GbY8wi=e!BE0iSIp^4I4x|%Awy9NL@91OG2 zW6Qp9r%p$u1=9oD$3$CIh7*^BqT3@0J1%((0~3Fg&; zk$R2}DXC6S7y^z&x^1diDoh`~+`4#unw#3MGA?du!E3;8*%XB(h}y^Te>#N7K1Y_$ zZ3Qn6yZPjl&=XMYw^~$)zw9+|q(#0{raIrv|7`hvW+)@fRNS{`vuL04#4f~ixLxvi zc$JcDgh+m|wUVPd#|}DEw0|0+ORKR9!c%S!nLvdC0EDt@X4!BRjE6nCGOfkSC>7)+ zYUAN-o{?s3V5e*b5u3oZ1SPAzgR~(% zkX%uho$=;WR>uBW&EY6_=XrqVSTK9yV$ST|-rl4^G?Acz0XZww4h}4d{E$P*d1fbl z*&aMvY&eu~@BElz#7BTU$9LJNkmhv%9BEoc4!=sue#UdKWI_x{%#Mo67n6{mF7b&i zpLbEwUg1O(d|Bfw^Ms|s8I`N64YLLHTrY>?KDV`ORc+^4Q_Sj7OGN6PYz#+R7NK;{ z@5c`W0>5od}{Ea5ZkR*b=JgGXx zyio^#OIkpiH~b~FUn*eiWoV-IEjKk(yEy63&@!MA4b1tgAXWxBNP+ouuiFF7=~95C5&>h~%)=^+p>Tj;=AZy_Lnf|K$3_9i zRm3s+EAs~G68pEnc7adQ)TnS5tw*^NwwnX&l@CE2FMWDAzr$2DT^N~ISF9{|3QCrd zIMQ3y(s%>$c`})dJ+3RF;oSQE_CFIe;#0sO;dxSzzprq;Jtd-R1_72a0 zc%>@;q(Dq39W~oMR#m#b=Y4&D;pzwK6rQYA@Ld}Nm9*@QOLGn!{da*YwLCMf&H_C8 zNQUwkN2`@}--a2GTSdBI0UJ>KNh4V7Yb`^h<4Ok=3zQTHLji(J2WCDMofs_jhkI=P<4^`dR1D93PSRxcfi9 zeyP3t6*{6wB*V+aTVH`1Kdvms9INCan6m8H*IJm1&V(d0XQ<$v#J`4vIaY)WNu^0C z`Tp47U?#1l?Z2MdIE!(xYo@-?rJQVKL&uI=bE?i;i+bmU7bBpLz7)2dtT5ka_h(8V z2m?v`Yw2B)t4*G$7y9SgMv|;$@ZPF^ov~>PRT_D~ z{>T8JN{B#w|ETGvrvG_itW4>%f-*amX)@cZY`qV2VVj(_gIvLAXaVb86aY#r17 z11rMKyg4Sl;{A|dmc-`^vwEFh7htQwgSF%@4aNZ>w)dQOc@_FCC#C3AJ=Wp--hbo= z-8qHL%P?iu7+&c{ttII6fPG-IR{2^Vt1>(z~3Fa^%A_)QWrNV8h`KB$mp}TOVC0P*iuSazdI24pyL0c>@9%m z*t%}fjU)s}fZ#5{-QC^YgS$g;hd>DK8l2z~+&w_>;JUFL+}-^)=bTU8{qL)HAGM3x zR5jJzt5>fz=Nw~>0TOx->b~%8N5As5x`GLGuDqS$Qa#Qh-get|g= zRxp=GRZ)MNUXOdsY_Z5V;74im{WlZNxr;mFwPZKak3XW}=blocsL4I#hh}DKvD(JU zUWug@PJR2?o~Moi+7abEj=&}wuSe8NDlr$#iFrp|AU&p!=GC5MRhAY@xzVH`=u0OA z*Sju`V01&5=I`}U@al=DW~%VpJ|Vr29gp4p+P1S-8j-4|suI)1-l|YE6lyr}ALGfq zyD8C1#3!vihiaM>NsURz4EK%jFGx4|eunPB3lG%MY7-dKh;Q1z{?HWwn`=v8eCQbm z*dLFK4xrd%9!MH^Z9U3Q9n*30Z8$DdI)X z)EPXZSAnRK%7fFjodmn2fLEKb8el~of2k$-<&ZWjtpdD%a^G3bL_s03q|qP)H-*xj9`wp#aj!r&cOz>c<~9x;#Otij4fUv1T|tTBY5K z^%vFV_96$hG6K=0rsS6l{4E?}l4}*B`4JE&lM2a#^>8nw2HOv|%8-Rz9uu2id!=Uv zum+);bvnkNV@Z?&2j`G74-8ED{R5*Pp;&z2jw`lKe?xZ!wqf`6R=Ku_e6*#Ip7jsi z#-t1KTW0$!{e1)tfLX;Ep78jdfXKe421;Dj*+Y@AM(u8%Iq9Qos9H|x)fb<`=LGd< z&W~!8wo&z1eO3K})1T5EO+^J4#&9I1cn|iQxhpDq`K1OqcY3d~GTo()8h@bYJCh8+ z8}M5!6|;~?y1{{}NDb{|>=y(% z1AB}~{Suh;zcqm;R(k_8X#LLUk1tAi^~#SFZ_CA6G7yFXI0s&lskok?_2bW zQ}z=Oa1ZMfrfnJh)=1PeOux|n#1RI-t}nRlf2yoFtjqEfe&_dnSjGqm4cx=-i&=Du zEZ#qp(lAM!+~)6$IB;D&JG&M_k%!5DSgFSKO)gUAlOPxo%n%he{#SI&UNCM zRU^|Quh2}rbPf3}`}8#!O(y{6U#PH$X!DtG@^R+w;hLdcvB`qFnTOxLCK4hV=i-DH z{Q?iTwMd6k7Hwa6|7go7*9EhL5|qPmIAp9S8Vq!AdUkGd)&`wi!~J{whzWjmkUwWK z5fW_*c*HszybCU+$((sWgi$A8e_bSgl2PS8nr&v%!veJOpQ{ocU9%Q^02<_k{T>_9 zZ?k+f)wCbBLS>hhjP|q6_nc3NmLE3oP%-WqHkS&e?Xwj!z4ZJiL;oD^CLCw>#Y|F4 zrSi{fHh7}9d;bbGJX<=6Jgb?uL2J4Xj^d8}0Lzx5e}#igI?4RmOk6B^$Fe{$lImvw z)25MFfJvo2i$N*fK>K;f_D|A`PD0%bi?VSyYX0N@QD|#xa9bDb$mHJp^*B&;s_4F} zhtCUC1#QaDV_o9BpjYqp@+g65 z;C;kWPsHzV4V25LyUHXXVHTlCfPF=@zEW5Q-lMVxFF=7lpP1})Nll3#7cH_XgS7aQ z>F_)}j&7SSqk&37{PM=vEL$K2F}jVszJtWaT9n!8Q9pc3_^wS@<};&AESE^*9WfE) zzOB%4)I#jimI`POUe?jGemM|f@Jp-y^>d`hXW~(^_Z)+isIY}WPr3E(X+4~JnUsi3 z`?iTA>us23CqIk%^2*uZHsQmn7*;!8)&ZYq7A?#xQ1R8S1wZ|cI>%PUoV9MSDXUR5 z98d3C_Q6GV?FT&5bcF zvN$(zxMW*|pr9h!1a&`cUha=8V{p`xJc#c+_TB$Re&g9RI782~;q&#{o`?eav(nJP z$j>upM5>QG2f+?+K6)+W5OWg2NbnpT?dco~Qmb`54-K6wb?#01uS78XJnrB1JWz8; zB=sO@s}DXT66lFzxDw+P6PB(P;1~Ij0Lt#~U(6R)=c4OQ5!`3bVV~2^$in7)N%>PI zl=!424I%(W@n5(2*J5%z;pkoTcD+{i3}iI9umB2TNK=-5}htAK0k*6d=1yB(Wy zZx+aUNz%rATx<|p&9s)PR_}+!|4O}9DeWtP9)w6_q}@Cqtb;A7^@q;^<74QXdO^Kr z1L|r_=gzMUxvP|c-uw2Y;sghxeEz9Zt>MXHM@{Ze=bx5Y$s3y~1Pc&9qrL|b%PGqDYah{}PqV$;4pmB?3Yviu37w*|Jzx@dNs{W1gBlkSd-BcZZ%0}k zDkFkS6*A%i_rA?+#jCC#|OCSQ(; zm^%5oZ6-3?Dv@$t5yg}XW+(-$CLIUP;@>U#*2PfJWM+x6LgFZt;gH)(UxVH_R~+#t zK#w(j`Oo^DEnnn0GarE084rSLqgW2#KHU+wpLQIn5duXgUc;~7zsfOmq`2v!zid1~vDsL97yBAizl zeoq&2U+#9@K3?lzJ)9rw@&673fztIW^7*$jyg7MSDue^KV*QT>ADIn(j(6eg39w5~ zG0gKW(he@|qccB>WW}!YJYH0T2+-dYOxF(QPCcV55LkE%hvgNU?tvlE7w?}8i92!N z;o)E2vyE+ID=YXY5U?b5(n2MWlcZ z_>Skw)4-u`eElmI+xvXg3HYnN>uSei6ByBpXi+A;ryA6>)yarl#EAkCxyg~#&mTGz zF1{nlSu(s#{fGV%KX<3cp=Hf%ats91#F-2Fr9y`l{uNm7j-k>0ncwbnh3p;pjYkvD zbUp&~vK>2>fq%qFL@&+1o&!LHOrfKkcck{^+)%&*88h@8+8nN2Td$oSn+TpKi?0QE z$4ePFrep_v{~OZcm+@8i+|pLZJ;jx}9l4!%z2Dm7I9lx0uPtE3|8Zk>a&;)oncXo~ z^2^eCOX0D9%z&>qOdJIZ5mSJ-?RMnF3mu5mQ0Nch zRI5b92n=E=LOQ}PwaQL~!@PRZEir34ft1*kluPEbrR=;`DjBR5lsfa35yna&e)o0s z@i?pwbB;DMT!W>FL>Q!Iq+(#C8WrS`3g$jiadY$(20jvo{xS*0rGdXWiztUzzHN8% z>Yo(g`~4nFaM;`l3SGCDVx~rqO+;iwNI#zO@9|D(7LJK$bz;djSmFDO?UVNtrpOQ>KawD9pM)Fw(fd3_X~(b1B2c*49P6JlOqBVBxCZz&a0&o zD{ey7q)(=GshcOhm9(dr5qn=>-mkYGoeft}+}$Zz&nsX!mKZ-TBfbF&8nFg%Sl%x) zO`2XZk+x)PY}#r$9-Nw)0L4nDZ*mRMU+;^_CG!x22=Ha4z=z*?)?9FWP+ykhjg%v- zQeO8tY5u4F_?{F}eSexYzZvIK4YQSwyTBs*Vn`DU0b>h>PeGsW z!^zXSWLjZRmdB8tA{2ac(BL(p`QB}$ORQb0-qMc0=-qpykrk9krn~4P@u>FurZ-rX z%}l#TU*y^YNDs`65bxcBh>#-joWuF{WmJr2?`8d#U`#0SWiX(*x3f4><6>BuKAQ=8 zs^k`=KJ7S?AO)4g5MnG`yF9G1>c(PqSpSJ#KN#Uu9BaU=PRzPKuFEpQT%4?|Tr+RfJd|&YE1`5&(tjg_dt}Gm?%wuZ!cbk0 z3YI>Q!#Dx89iE1Sg>$^&z={wdVhDVA&(NZ~26ytxl7MejUUGxcb;*5JlGNpIG;_Gy zv^{HF%i8)M=Kb9EU_Kd)N11?kxfe6@$*Nf&?YK`vM0-B-CVQ^_;?GSn@TVB`$j>(E z`ugV{8+M+VO{3x-35M9@@^On{%d_*t-!E3d|G-sD-ET~Bx>`PwAa9= zkkz3Fr8*C}?H8g2+7Al{Y#R|#_;8JcS;e_9ZdZ2oP$s?Q-z$=07$yZVguX}BpR%Uz zLn)KAx)MT75w8iOctuar+=Ua`&D#k)?)oaa(sH*Q2aukebrXSDCPQBzv-cF9`%^Ck zZ15?{KxM#}0F};)AMrF#E4|jGweq>~4X2wZE zh6odwaqk~}Xp~!0T57f>;Arva#YFtjw5&ekzF$%R^P_Ga|H~0n*RhO15W~q{ZkIV; z%LsS&g4<8w8^=~!i}BJ&=hvPWpQjg)Zxl`>pp!eYVDh&MEDmMAfmo` zIrbg07#(U4kpHFfj?W5Z0-4zwo6EJV00>f8TF1WDN02c+x1yyJl~?Gnf8Kd6y~GF> zFV#zNH0dR_v2&$23HiR?UGr7GhvEIb=FywsyFIuHCdXQWk@FZmDBld*5qW5a6$8s0 zfkXQ|e!=4-63DeB6jD%F`r*bs9fWskvA1hMslV=c=)?yf^chQVg=11b;=5Q8E7zR@ zqW!G9`e{u{NTDZoEygCsJcTc2MtPPttGRBh4(wnd_lTslO!x82S}m0_JYeJE%M-25=>VMt z&huKFN0;k!XQyuHDCvmm=G0#TA3j)R<51~|i+Kqf`N8M@R+H$pi5^!^6gE5!0rdW}$k-s_5~D>p@x2s!T? z9P?Mj4+i@!Ev4)ns>0oahwi36DX+Px!uZdi;xtu?6=Pxt$bN3mboC~pVE2g<3zn${ zet>GPqpJgifn0E{6b$%3f6?PqrL`fK2lDn~!QYdYI7XD4PQ0Mce-6JtAJXBuax=5C zo~u5TXOc#hyaAgGgKzarb>{^A2#B6pJThKCoqm44QQg?pM6In|$v9mnB;>udv=)8P zxV~9J8!nGgVKu&X@ojcdd&Y3Izt5YR%$?g`xremue@NM!6aVT<=(BOOj&%y>ONH7; zmbE;L??guTf#zxj^)|M7@gpN@&txFQjs4i^(mfeFC-0{A05lc``kPKYb*uPQScPK@ zi)>1>?ffOZ@@vbdIvAoL)M-q=c|pfJf|2?dl}X65HjO_$Sz%X{)@~W1( z#H$IPDb^Ofpn-G_qUX}7a}3CgS$bKoVOZ^&u_1-b-bjflahn0EWLw4it^{oE8S+P) zh-0^FuViSN^b<>y#XAL&9FB0CO)qCe@IgPl37u#H3_RSzn+pRf3cs&U_Ad>+gdt2} z2%%%*Ob3VGQ@tL2dI0qrN1@OoOd6oRz1r_zkS6^3EykPu&eww#?xx}&3G;`=x}qAtE% z&&#@}pmc*+Kv*FmU&I@mF{}T)c(Bk!vY#ho_z5Y%=%G{2L-$uMsmhE zD489H9(|s9p;U>i2pPQmaD;!E3e&2|t7TMOSl`?*I?Ba)c3_m`shu@Y*SKwtX zbXbz9ci!_hXq_RYlVl0ixO{~nS*Wjs%`RUvWSL%`D!VWhVQFLp)BKwCTLi|#M(7V`E=Ln7+BoprHZ))7# zg#I8uJgcCH30mzR{}NXi;U?c`5f2KRF&V50AjcZ(pQ)!od?}dF@S&YW0uWYz#@msz zlWTR!f)OMjErPtFd+uvchwIVzWhh>oQ#b3+db&5JX)nt}dOveQIMM#WWjXr31jALt z-squurZwx6k8fuBJ0cU2mom=@%_I?AcFe1m;E!Ub&;>rFPCh9Ln(g(w$6SQPUf4b) z{chS?4^ulS$`g!vxdy!%=@ppX55sY;xj=*)almw}=zmZQ`SuQLokhl`S^brCj6ykX z!%g6~UTD+)=JdzC=;-V^R=$!T9nFO7Pe7{L%*o~4D91)DHI5&fx%J51aCGvGd4H_m zhXJ5!mm(%)@hesY1eo@dq`k#k*_;Wew@4`a^kZ%0v_3?|uK(>MP>!c^{B(kV~K36iQ z`O^KchP1Q^-&Y%baIEQQtigyzzAES&Zu#^*^3oNVQgUy?(a}>{szU>xw3a|XTDXBv(6*S9hYDZ z+C!%UsFFe%Bxn7NT>%=>e{O<7Xw*SH8RcqqIsrN2A`0>xC z(STuR*4j#SNY&kOtFt2^uko&sDyHO=)AW_tew2G%qUdwTh|2PuAt9oT~il(lFA#pOSZQ& zbw?G2VjwAvBYr7$XgK7eS=#+jT$t-6?j=%duV?Ta%jyJ6tirwOPNWQ8@t)9_@1mv1 zqz2YvKPyYc?Nr>eT!EtCpc9kQr0Kw?eL#|006yq2CIIa%Kove{@*{DpPBJ-{cEyK# z^TLbRj7p!W4nONtJvNPeUCG7c@#+soZ}vwnuLYtOh3!5X(l^j2ed=BS(Pz**UON=( z9Xh~@lNp1hY53s)-=CJu7Ct2t4)rD)H{Jc&necVp1m^ogcMWw|t-jM{)+4QqChRFy z(bv6B(Kqv1{fl9>HY@0}&_b_)v|H*fD$2lQtcLN5uFSGO>;I#Mw^=DaUqc7l;Oo0r z3C?b64|jiL5#Y*?5otHb|9i1ny`ns3GMl@l&h0ee8RhdZDcq^-)2qOqQwG{$h*>X8 zcgJUQWzr)=b_7CHeSqE!bU*pkPHh1DuDMomM#|yw?Is+>aff6hphRQAiL`;f=B{m+fZ#4bmTM~ zqBo4C3qD%;FVO!*l)9PH=M;WHd{k9RX8sA&aizSSpQNYkKu#Mn7Hm+C3Njl7aBl=ocPu+8i?eaQMMPeU+>;$*Nfd5rH?NqtYSMN`7ODw2`}F<@HuPo8o;ivK~S3%}p~c zacKNl+M#{rb`w{NCsGE{cgS$K7EzpEOS4sCUO;e5u<+O=`0@IAcUTORd%$mjxj(7o z`|jN`NeHXb6u3Vos(69*r{TG&r&F9c z+{Sb102GvGc6FUdVz~u2O^WfwuJU70_Gea^Wn1ZZR+Nz~*uxr6wtC4JffWH~(#Sgw z``~^Vld&h~Gpnv^g!T7#<0JQc#xN~z)$Y6Oj~zxtc<~#jp^0T>aIULV)HIIx8m8|M zme@bOf-2S*+9@xf(WF?c!oa}($k8*auZY1KDON+cZ-L^xU9$Df5otrB^Y2BR7y?E2 zSe#w(z1iyAUxH!y!|ga5P?A^_xjUvp2?Jc0BO=bPuN^q8bagY*(-&hZ&w+3Z>ZfEg zay4h&)|sb>9F=5}{GfbUb`a!!Rl_X=1QLGu$QxsUmaUs+LqqvvDD;__seUSoUB<6 z$^5?p+5bnKSWJQ;e%&puY#;Ee%!dyI%&()L99z-w8w*F3>N)EeN~yq}yV?Hs_zo7P zYja$5AHR9rouDQ3dShKF6%fDC2G1``H~RI(&buz$4RXk_#MyHWj&`Pe-p^5CVsA-fAN}dH(qz(eGyk6%tNEvO+mG*RYr1j2S9N~t z$=!wv;#=C-!z2Jg3~%@0p4`R36+Vv9k)gaDz)t+}wYpIm8{rbYsGYN+hck`hJM*aa zp;sWKwrJC(tZvYUvHsVe(|xSghx9b{^OH3f~dUn#*``JaP!eE`!guOPe9yR!DjrMezwqaitCAdu2T z^xr2MP=u+^^gNiGJ5yEo=;lbM6UOa-G7S}-6_57(Aw(QaPEyfPdWre?xX6?5^IQ@I zzgHZ^)A$JzVdyeK+y6%GS{|jQqslCaG$kuKBb!yoC;!*F`+_l|?Xn$534S7Nsw{7% z`65b&s_Hc56b@A8fhOnTZycL@dtk(s?HM40n6i@lvob;R2IK|xy)iavm~xSBxLCv# zn@5Ac=y{XAhU&lAD~o4Umb*2aUx)sWjGDr4zux%nZ27)l2bQSsWh^rXa2M4i1yT<9 zfxC5w5!qwAR(^7N^1@x?Wg#%!62`BCR%M$l-F@SVF9hK{Qbau^zD{p`?4kx%LT zVT*>r7_mx!zjrVaXtvEA5a&#muZizn?_~RB;f@qpEb8HG=2@(N-?)Z#SyRuuc5j%| zzfKds$K-K&_0G} zlm){2Ijb{hJ4It+c$S}zBX`7X!|pDmahE8K^2-r$PXxKkbL{_~2?kLcjs5<<*p&~4 zBvp_b+PSuvC~qRXmsXU2Bag7qp{-*p!0P)Y_+=RWIn$es)++OnG=D`dghRyt;O!_< z7EnOp@LvZ3ujEgre<4Sc;9@UlR;)_4e>w-X^G1|FWK85CWAVi78neB1EO?y^U>rkq*N|O;*{_wRh*JP8~ z+)BwMpehRK9ndenyxG{UaEV0I-D@+`QL^cR#doXH>~z|yQ=FD7(I+fagMf&E%U(tT`bTf26hD)hKNYy)YBiBH`i-Zpx#4&} zG*jGMOB!)x6(saWyykAn zEbn}+dX(X(6(Czdk!_%wcDvVyB&cu^o;8ZbXv!H*W;xbjpu8w0zwo5L(J(h$sbKga zet!~R-4()G{B>#Pl4Ei>mvc72(_0*< zpri1@0cIE}>&QLF>83d!!Cv~I>xf9>o}on<9#kxQV{_9qd@!SUHpF`TTP*r5(Y+$g z6~-LNUsb=qhl>YUOF>sR>nRq8^auC_32I5b|E4V}_a7w4s!5Juol45*Ui!b0pzi<@ zgeRaRWyz{+nwB;-EzM6&T?z3?jj3!Q^5ALgPZL$GGY*WVe6ye~q{8shV;UH1Wx?ox zyIDLOn-I7C?IPo5ZpN2%SIT>aYP*oWz+a`S4)6 z1rGl^zRda4eH1CmfScR%Z3ErjlcqPy$59SZDfB*!1b^*}CM{1rowtwBB5wM=hSRaP-K9LTF-B{MOG{EBcf~n}ZQOChGH2ti2xj`}zxqd>jmw zrfWKvi%~IRV`XocAMAsl#+jp?=xa#{#$#U^3-`0V-%EEBZV|90xVYY?tQP9EUnG{T z+7QnfMomQ5jL>zxv<F+P+j2S)0PW&8?i(2NHZVW@kD7=Ea&mKJk$sVe+zOnOt8GDaRke2{PVtDD&ceTHFZujZ!9E(7-getg4b`B6(b7v7~ZfV zBTsI8;-ceOw!D+ww&U$9{cb>AC5)b~Fh_(nvx{B-;o6$z<&R96&>cCg@-E zP#a*h`8S-Ss|2fspX9LjHt+A&v|d~nE;gYgaOlGLpJ4vuk&3b%xy})XN`_}Ixax`S zp~71IMfadp z{V1(L7~j~$?Kec>_QciDRwh08<2uh7?1CAZscZ$Ko~dB#1W0Q9JK@hRfa$)_s_Ge+ zBfLdsI|ZDXFD_gJvKdL{^a{=v>23PFX=(b67oDMv01E z<9?sS+ww}+lT^}vt*xRL>n8trm}BiHtjNg~C+#HTf{OzM0)2n!fvRf=&LOVEHY%pd zi+?yXS(RWo7F>oq|2#_Rdi)>4C;q!~-@a>4`c z0QIubV*~6%#P<19CjBn2dA0p#2|ZR8mW#_vE4H*CHo(8Sq@?5pvj%p<4MfxAk@@Bx z_l#!LY!dw6DkfikkKsV)sQX*uy@&+JsHzvRkC>xwVA~>v09_gC27ISGS>oGSM|e!J zA0+-LwcH3;wo|dAO4^y77*v*HF}81b4r#vnr<2C#Y^pU9*vE2O8dOlQ(|G&>1U~3P z5euX^W(#~wXUz7jUMke7P1*qU7Z_+75cocM1%EVfCl&d!#g^O>ED<4Xtvl@s?<%~= ze(ApR=H)6lTAQv+bTnb5# zbpN0EwQ`D^S#=SKsIvBQ8{{lq`(2Uxv^YJRQnp*8kp|{{TWg39B=42SyNPt}K~Uy+0@GBr-6S5QT&dyricpx7z7UvIf@dYomyOeg;XuDo^e#28_s z7s~!OBu{T-8V7;xRfF^~cah*HD8QfWtANhB4Ix7{I~!n&gp(K+CO3;K{QsZ4`4zT} z=IN)BsBboZHHJro_~l;`KmQwX^Xa%QC$xWE8gMfLvEfGbuXim%y)3&=>xR!3#}(_j zQV`H*K~_8$hAKMQkUC);sZi+G;RrPIJ=jMVDo0+-dW^594C>iTD>!q zVLZ=cFi+>L1$cp0+M!fD$ukD&v5h2>^H--$J5weqK&bv+wI?q#pOrUZI4_Y+&E10; zoZi+oTy!>CK98^W%53h6aIjA2{nf*19A%@awBKEbak!i83^@?=PvhXCT6@aFQkKQIlD}hrEBX;stN<_QCl>jq zI8xDz5MB?{pPcKV9^{Qq5;X1}9lKeYtf#|Y7r`v4q0wG`JPRFDzRh{90ZV*I`Q+?Z zVl@9&vLmC;Dcvs}@$Sjj$oCp~dr+L(zh$UK%eH~8@iEkJcj6v-tlFF{&IqykhyO>O zDv#~(FEOJ>{G>aqCgER_%?Sv`QU$r&kQVSx6;xggJUGiAiWgsl2_5ZH!Rwb_>~3Vj zaWUI5b%|d`AFcdSIZacUXOa0h%U^V?*r@0DIQk^K;MzZxJ8id&VYZ@*i%oVE30ih3 zPdnawT`;itcy{aF?7(!h?-DBT+Mj^6U+$xP`r3{`e*vtx`cFCe2RZ<}iA$bqNd- zYF}BK)6T7Bz_7U zm5KMj*TKg6!8HFc6mi=`3#%plzQ69J! zz3ue%H3zvVawsA6&ceK9urP8SCU)n__{`B(P|&$ABht>NX2_cRu>GB&;N)d!(d~qv z;>+=Woe|<`1xX@~lmVScXP zFdOia)DC{$WSLGw!SU zDKaQPFHGtTEjf0=>{L_qT)r*y-Mqo+FHCW?jqOU4JgAdl13<`==hv@a^Yimc=;F$W zQe?SSAJrtO&}SbEsL->x9CPK3ei-X!M6ynUuP^(eJyav9}ab>fK`zfEvK+0&o40Bn4YmY zev*(Gt}1&K*uq+p-%|K`y(cC%C6hK$OV_Ns#3031z*%tfU9aJ|!}+Vi6^Gu8_@vlK z%kf-3YCT_jJKd3S_USKe2f7FgJFP8ea|WH6m0piVyw`f|D}?&)hxUZN{IlbBXq^lQ zSON>39f7=iGD4DroCzf8NlDh}W5%^YO5{K9U7$h2@veD*5z3$;lR(BI3Oc!f-^GW# zoy<^@;fdM?o1(IxpyHtzf0TQgBDpuPgBs(tuJsdi;qPJ?--i+E2@t{Mmzp&)1Yg=` zPjaZokF?AFqzoHyBRhO0)bs1KG6ZlT+>cx%n-vg8b}Rem+!0W_rxh3ZVNv)b?1 zK!5oIl1$?=EA}S2tot9=|E3#)0#$^+PM>+Wl#4Gb(Ld#?g#P>vB(%A`F-LbzGOuE5 zB)tsnU0Roakzk^(Y^_p?l9&o2mXTK|VAo~;h8muyawUh4Hu-eZYjM<4LzaXy-*fOu z-V=C&@^i`b+}b^u>R$`CW>$FB5}$b9vEet7fqGh6BQBa`c{h)DTFb}BD?X_sw^g;? zMb`|w)Lugljkqg1HoSYr8XGUFYiTpNJ>Ff}_+E3mn3&L_h(O?2 zcs^ZU8w}_FNc`Q6Us1F0`w6X`r-jqmyt~^yRC{CeXNUuoP@=2b{=~1e<22StUM*GS z?{N;6Afu~-!;ozMGtRIe#%KNddueL%6#m6VpSk^tr$?80VEkxhhJ{9cWiZM@>*3ei zL6#SeB@$==d8>~iP9t+;fUgsN?y}YOd!S~qAAfch}ttQ~p zk$yAXmfiTbs+^R<=3aWydbhWTvjZncl1#-gJS=3I`%qdpE*n6Zpxh1FDjR zz2Gx|E}ghqznT-0Otw7zd&urre+ZtciO7gn64f{CT=!eP5|J|gz5nC3MqQ1K$<$v_ zN0U%8VbGMqyvP(|3j})3OJAI67_=T;CAdYCoX=94Ra4<`KQ`(2f(L|9-|E&L&JMs6 z{800-{&=NN$noQs;*YOt*N$0Zg z(vcUw?w~7I92IIsB5$J(^WA*5ne>uwbtMT7BR{Y(z|5Q0?v~<+S%@lJ8X1+P5-j@h zV<`iI#rfMhlcR!-hM93HIqAyTnpIhLYc(Ol#WAswG^1~||?h9H%=Jq@qR4C1^ zt$x1RL~Cp;=3<{K*v?{jjJ5UCJLq%Nab-7}xj(#HOJM&wx!Zo`a-3ugEqrt{9)9ZD zId}n1pZyuamX6-i80uyNn2 zPWyqkas>KI8u&XAbgJgKOw5rLEk7%Lw7JL9@{WWNpUAU4c4e`{4~+*titknN&^gq? z0Ml84`jv~eg0+HGQt0b=a{3-~Kz)v#(~OvAXjnXovbyOao(1drOnquDVaU((*^EMV zF6U}1BD;$BZZ7vK^~^FYYakbtxK#OL5)3h`Yg0ToaAq>zh%nO(=?l z5JX>H5;AOCZnFwUZ+eijcHb0SwF8Z~5R)0V7s260K1e9s!8{GucmIMmT+L>C*Z9M= zpI+`R)5(Jpztj?s#({t89Orl?yuVA$2 zD-eTP85*8sLQ0-w4(J`nqMpAM9bTUTZJ7UPS??H3Ayo8nMz6xONqD;-X`i3>!P7#w zNkqtNe3607%75=4rMp|4zFNef3^y<-8h=I+82XQ5^m7N!`9(cfT6z7jc;&3S%8qx= zw;w!!t76RSp2(%b=)@z_-N zHXKaG+eEWXk1I4JN(~sHkq>USN6xb``^zH*vO2X_E3}ncO7iG%NfZ8eygDb`;b-Bx zwS-ehoyD-At|ai|tYAe`^Uqlz#_<{GaFMaCiJ9oVhNg7moKlO|RGVoys(;eAqYc{K z#=2rrO-NE^-)-KIVOSPp75wlrAb+YY_Y+s5kq+fAM)uv{;4cBeUPtH844zds@#)l> z(!y~zTg?0OWilX83)9*)$yE!!83smlp>mNnR`|&o|3A;qw`JCeJ?qMuz|di`Lq&-^ zSM0C!$pJk_0CFJ6^XseTjL3bkX(&5wErEeeqXJ!t~LRP7A#ED9-k3@>$1cz2qj-l>|v`!pUx37Hn#Y6r>2&Mj@OB6l0tL4%o+){N_PVA z?u@#OPdyImr2i5=joERPfK5RPoM5YMr5b*HhUD%2nYy3v-HBk!cFw&zvpl_(-Z9>s6n{k;&Th3XE4Vt7-Y#Epj zOYYYff9BQQhHR6Wj?HX!OOwkx;w#FR8`Jp!W$6P*r(pJ&!v}eD^DS_#g=8dl!10Tg zJuo=mk9GI8)Es_I!F~SGozYzrZ~mXyo9o+4>}}aWG|e_`eHR#;oE)dBsaXupOiVV? zM1*xk{3-1U=-q`7kudUVQdKt%1*ysgb7|x3?Ck8~@l=Fkw$c03nv;8;4~l_txK)Dt z9{RqBmpaevm(r8I3#1A7Rj_9kayJa%Nhm=V_v}|exiu<>M|2!zZr2ohq#V9IrRIg^ z2!!SCjZ9?|ehV0JCx>`xMgpvs4v@+Ab)Nm=UG5tO?o74IatcK&E2}AHKG4bS13;#I zb_!ReUgYzDLB{mC)qGbRx$NulcxAqxg8BD!xD)QVN##}adHzqp+-u(S-qsf0 zQcNL8*||k~0IL&D|D&Q}QU9aL-C$fa6+5-M*0qTfO?lUpp$t{D44BnXE_60NVoYU9 zRW<(j$H740!k<*)&xN}!C-N#a$k=>#`ZN3abfx01iQ{r#jVx9s*yN{N%yvB9i8yhA zeS8IID*c?X0b#OTz!q@b01)pUmR^}ict>or)w-9B=Lo)qx9EEhCpp5EF^9V**TOU) zsi)j)yfD);_(5iAt?#hr|PI2nDb2I6jh`ffwRvqstZWVF)Bq>>`ie`LzX6;9&l_mc+ zlZQSWe~C>sC_TLgng_pdDPw}pAF1>uiaj{fIoxj}j1mY;<`f{Fj78xQbnP(Igm1c%k{bSgl;aXG;#8ZB_f3{#VlJKOt91Z1( zpRtec9o>gll2}uJ|2hDS!SO+VB7D90re1>4D^7{|1sB&t=F>E7B3?`o2!#e_&el01 zb-Zh6rTTtjp8^O*70dq}iudkCStMS38IH0(1BA9 zqjE>5`nqOjmsyKb^5kSTOfnJ)F&WvFeqM?7X>IX^^~Wt$x`Rd!DeS7o_2igyIo#BS zT&n}UU-vBfz@L)Pxm!2{Xh$hEp~o@8EK)pmtY~PdZFuNLPgYvN2JQ8~PGS8|@H=ZV zX^}11I-nVUw{+MyC8Q$76xpoun5%l|1N_VsybSjC6#MM0!>tWNUiuA!M}RDYqt7AX zla(A-e%+lAW}GEQOtLsMpK0Q~kiKVSWsL*AO2>LAwV&Ioi|t)Gyu4{CM1s-OA4Olq z!~1)85o9RL2=pl{wk*gw`<*!+!{IgG0{!!gW{kkXD8~iZWyE6Y9)dMfKWiyvxDkuI zyEXG*(y`MOviPmG#a8a7N+{s4nUc4}Z?x}eF-37{C3kIFHzmuv!H4I1$zRTMoUBQ5JG`I&k*(*ic*$X3^|FH@8V`8~n>yv2a+oXawDzjC` zOVx+^!4UdP6o*0!l;RcK-K}VGhoUL&P+WqwSn=ZS zPH=Z9?(XjH?wsk}yYKg&?|IIdAAb-sA(P1^Ywx}GT8l1B&lM+hW;KcF{DuBr78IN3 z>)_brg-w59XP7bohik@hE+SUGrh6Rt=yK`Y48yjm5a8X;-B~EPTQ)^jSss)>^GwSq zM!Dg1#(Lvn$C<1&wmeSq${@=~m49Y*$ldWk6D$7{ z_u{z}xokU%AH8hcEx&zlYBF6Ye|3&(*B!&5`)4r%QoSiB{{xX#(lVZy%R+2l*K*Kl z*g7Bkb)nl#UOMe$8Lce-a9)s#1>m54L)IcA_U=sJgK^ATjsX^1YYNB@28x*b?M)Z^9bqz zq0uZ38_}oy;P5!Z2Lv@2dQea(Enh%~Rp! z=7&c@wyc^8On-_hRQ+D{z6MD-Gm#9FUO6C$s7_^H5lwF%F7k#_g9IYobhiBUQP*Dn zGly=!wK?rS^H%?%!{pxaX@cEqm#&L>AcyE0^7V#TJDaCzBlRJO5#cI?U7zLQ`xx=V zRnLs+JAO{wlge|Nx))&Eor|vO{FtA#ZFc*+J4_G=cg^|vF8fNZ4bI%`-6|t(_Q9Mv zCf`U;PljXjPW9~heoK4lpV_1iinHL14t;F=+BMXdlFv~ zyT|O5u~iu#_${f;5(U11(3n!4vnSyvFT9n^y3Alt#BE&3u)9?()|a*5()hksu{^y1 zN6gk=aQCh7sPQuK%Fkt>L+9V<0dNUZ&#_#nOX9T6E-1*m!=s>}sHv^h0sjl$f!Jc3 zKfADy*Jl0GKEfZ6KO73vj1QPw{TUsVc!kTR_fgXttI7CJjIwh_YqfTNo&i$g&Dq$R z!Bzxq2u{J5hx6r|Tfvwr&z*u_C+su(uTD)cjmT zI5=i2yR$FG<}BS(N$1uM%o^*a3Aj3|q^s@`T6}mmIvA|*uE}!n@0&3MJ*f`Nl&42| zp9CDZkySl;6M9bwk_Fyatq1*kvALC|($zJ#Rl8WrtaXM+50DF->8V#8#ifedXM2xo zmYw-!r}2cM`_Agu_g_3CzLgaa47spLMz5|+z;fBHwP=1!SKx5rH+ zq9k+L0kTBOSE@q)8KCHRCHln0sNPH)Ln$b7ce$<$>*FLFi!-~@3l&|sxhmL4*pGe( zC}zQ&oN;2{P5GyuF`R?ps7 zKR3U92uZ=h;=37Ou)9qk>tF%gFaJvcCSNt3f!nSLvcwzTyuiWPrV<9CGFSp|K8ov; zvx=O`wOy#*zFkVxRld5mCU0vEn)_N&yroO5My$h~YVc35D=7as&%I!{m7G4HE%(sG zv})RYIc;a@&OKw<+(AM@)=7*H6=LJ?DK$7=e%Rkp9bJqhNx|2u9WXNfqH6)oe=j%& zk03JdasJ*kueC|M*;o17anGd5o`f%0h8pPAmTstZi>+m$8~7V2qpme$q_mZ@n}Fri zD|W_12;U*7mmrK8u9m%2>6M~9(0)AZb#@U_xvr4^()$LDXjhQmUmODl)D1)dHmoXP z?>}*_!32`q|7gZllf(ZyX0>*SY9Du>`E-Imhp<};0twTH?xQlNlslI-;-P%TlR4MgK9|(zX=qB3d^~gFL1Z6$ zG4}}tEJF@cijItqnmEc_R(6`o7@MHFx~Pm+<0bsp%nH5v>*#8=G*>sypYv~Dm}07Vd#SIeskr(r{RuKeu30e_$3 zzusNIXhku2y#W|uig*p^dKB{HMe<^Hc^lK#UemDhvXb5m_J+_n5x*}dPzBE#*mqW6 zogTN&2BS(hW!r6StenuBl4fp@9BtolUc3YRe|nim&17LbDVS-Yzb;(TYw=z^hhd>5 zOC_(3-&Nkpb5^n#+$kOt@anSAjWhrZL>_EE&~fvx^mD8(=i>UE9ryi@Wf=ek#d{@s zX!=*Epac8-BhZXH)t-nV3R+lJOxq?JBs=TzDmO>CizgZbCfBD6fxa;>-YxGk3nQ$gUAlw``U?63q??@Z-yxg3Ujvl+PKIpaT-LA802{EcB`tV&Tk$|tM zWN;j}WNr52)Q=HfvJ?r-XD0s*>$+>tNbS{%In?u}jA&~qPgz?#6ze$9z7j0y;`NBhF;Al3$k(uG2C5;r5QBWn^05iT+Ot_V!1j6FlPAM;{GRKCS3btCFhNC z>;5tIfQ^j}C~9GmzVbJYe?9RM*@yKB z2ib>QCee5-8x8Qx5E!!)7w@@pwe!Oee6k9Ylx*+ptRjKJBE0xnSXFQQKgrPeH%<1+ zP3Jn>Q88BDpb6({_5u!??X@{&Wbm`UGcf+w{o~)1X2yW51Kd!J@zNok0oxs;X;gX0ZE4Yd;SQho34=aTeGx#^G=wuU;yzyEVL z<*2_0?v9|#C@b5qcZUHCo<~u(1OV}LXX`ondn2)fD>R60sHtwpfA)i;5w=EJ7oHYa-&==92!E4&l6eIqa4|N}=8jzc89zEQ%FfNd z)8GG024{GcIr3Dq*)g+dW%@&C3NPdb#=$frgkN&aCE(jgrEmuWF zg)bVu!}0RRFhHsq6<%+;L`Pj+ec*t+hHXs3!+l@~HN#Ue2B$*r8K~!odr%_*4g_B` zsP4fljqx2`vUo|LJeXVv1s+YgIEc$xzRv2Wv==6VfK4MADjT3Nna;I2UhDW!En_QZ z@N8N(f&B}(C2t$NFMh%a3+mb7&LbpR{>ufh*F`WOqkvqMCnf0f8vMxPf$hJ&Vp}?1 z_Q43s^AihQzg%QkiXw+goq{}iFC-0#HSP6<#p*-=9Ti^(-+B+T>*?x#PXdyE+hQnd z_+7^^+8O1@wu6gEaGn5~Br(j{N1X8hN(UBi=mWrGBP)*u1Pn#hT}4l+J7O2h zvf8t>Htg<$MpPmuHqjdC>#wh^VG~$Jglc3%Xq6s}(iHld^0<;2PV*0Blz@rC3ez3vJ}oJ`y{pv8G&AeRK0{T*%HmeSn{YU1kY7j^!4_dx*N|Bc~=Cy zPN82aYbR+QYPp2UYDp>8+A0s+RVZh~O!|#{`8uw2%3SXAr59)mGZZZ<^PP=pz{1_t zq_a8>;ohqo2gAs@Y3R0j!s8h|{{!a>6`)U+_ldmJ4&M7uFR0!ZbRsypT@eueJ~Wb( z^NU=ICEl8HoszOZ?xuOU7_8>(3m;+oD}tw)Zpss8fK z{JIh*pwz%4IGKIR>^zd<+Q$MuC^D85wFl)w}8QZSMODkets#XFy zK$AICtxH=OkWV!@Pk9`C?HZEa@P4YGtD=pb3P#|ofkX2}D77VB2`jLV5SP&>JwvJ& z`i~k0wz*D~ZbVu%h9)w@cy7jo-Wj$0n014TY>Et0HPJTuzSaCW?1p|F4R4L$(ddt= z*;xxQ&2cUFuWG7s^!b$a3k_{^NnjdB_KDHaYKN3lRVhYNM#i>w$9$vHbl_}XFLeDi zhJTp?brsPf7ZoXcAV|bz)OV_v6K|u#OIn(CZ%%;}#P)fsWfjNJsS zTla@k5M&xAb^3z&;Q_dsyRPN#roxOv5sV(H^`UTN#Shj*Tf-3%gZ9Fd+44+J-)y7}OMvMO5F7);S-P z4)deiyNIj630%Xo*5s+cwTb%>{o4u2{<5cyk3bMIzJvl27&Kjg%1)bdCTgii+I+QS_e;ESJ@kP<8EwAh}We z?)zxEbPgaI#W@^4hWUCeTDC-m1PLy1r1|+9(R*7qFH>vOCpOC=xtJc=TjJ(Yw^SnF zt+70ut}M!HHH^4VG7-NQ0vZ3F)J;^xKFfJ?M>-$_^#1|=@dP?M9V4No0azbY?ELz9d9x;sUhFf=dgEX4Tce9rY--ql>EPJ{PC z-s!$894xHNfl72!7~KaVka}!kyS~#M_x}kc!QpC=upmurG`7HnGG1ZaJlywkhU1Tj zctv<5VdNdJqsMt+gQ#dJu|4GDH)?LfkI?v+7Du}Vi|jTrKrPEAXZdvG2J&BqIl_z4 ze&GI-F;{G*57}Zv49klw1dx6OzxzpCeG!eg0sJKcx27V)M+^X*jn$*180V|<3_?L) z05f&KiCam!3ZfofxUT;fcB!XKmge$NQj?Z5_(2QU%AbUbLk?-Dg|1zX=m906k@Gp6 zkJJuiT(?(a?{GT_3-WS@yV+Sh8SX|e+lELNG_?QUybO@1&LRIIqx)JAe}+xIXAzw{ zwmbjE+FTMNjjyyrkQTSwR%7DtG}G#O?wINt)bsxi1{zu|o z{yB(tKt-47-+LgZfOE<%$503gkI75{dQ0k$B-@1WO~CYG|kW z^rhcZa;ogJG^VcuY}K&2gJZ z`@@!scv~mGhv1i0Y+70nsRqNzt`NB4RrBAebfJI0ka6VyisV;;{e|SgB*-r%DtTt4 zgn6Wx2&M(7Lw^w1sUvzQadOunLbT}Py;1>-5MNA_Bul}bd&*LeISozF}38;h*8?}gB{Qa*OzW)Q6$5Cf zO=Kf|XoEaYYa7H?ISN(I$M8fnsil9stkoso5aZ$9ZVn{S(*Sw3;*JsX!?#TC!GsBK z5xsJks}_&K|5PvKJfD=wp**oLE6r#`ne7M36VU~*DG zQ92lEb+B8#TwL#*PUb@Uba0+rt6@y?aWm0OJLbk#ww0bCn=6FZ9Q+4aB zz0_O)fr?(gsWIiEPQn)!Xg?TtHY zcsCxOpD;TTQl&1EOF}dS5nHgj=YohZ(*2^5@~#TkTcz6zP2G9 zU}ad+djtN!&;Qiwg96Bqrc}g~E9U@EmQ`|l3EJGEO;elP?6(x?oSYo-)iR{XZ(ZiRS23@QEc>#ny+QuDuH~AGIt*h(Y$)}nPzP6 zW%S_Z{IxsDn~Arobr8I4>+bKnD3YdA+pO&q;LsmGzYz{v@X(JdPD;)%2;!*@K08(x zW51>d43!6-y}rRnp^uSdD5PvenI7%Z@csw*z zhxylQV8v8Wca2lY$Ui^}EH>C|M206{&eB3Y0Ereb`+Sd-U)NaWSHf~ip3rBWr?z@% zTo0$85kalwP;RJAorMe*jDY?5EBpx0VMnwffd;oaqtAC$LJmAs8Td3c7>)DG{b$;> zW>ul}P(6rbJxud_ZY?5>#PocyS@UTcMs8wP=qc)52>!5&kS}RrrokqQu`XD#a|=Dd z8&y0y5(vX9Dp(T4pD|3cHj9gwc9Y#!`JX(nm8ZKe=tthXUJxxpTjY;+Hr*k1+#BS5 zWp9yZf*yfY{@_NPVA_|{@FsqzpG^H-&Vuvm8yttxwJj@t$3YL3ok|^7cbDvvwwACL zc;*VCa|W5!Y9_5v&6i4D1h-pJZ511Qou}rc(6B!8H%lm7kEdhR)dDIqi(*q-W{+*? zhQEiY$QyJJi*&Qg1r-Si2{kp8wC6$d4&a344Xm6fvFtvjiJ~OcO?bDAR97(3QA=>t5L;T?b2)Ep4`J*3T$>}-N zgoSPfd=~W_MKe{b59;Q^ab7<<+&z@FI$lLzohR0Ax#YVVJ(YURGHd%-Cd{`%^ybC- zJ|k7i2$8$sF~K1EIPi@b_Qx_VO6S}@_9hdJIcoK7LWXXg1Io|G^!gfjH=d;@a>J--~(ySYoP!`gp}p4)ga4>>-h`Dh>5)y8*fk?(t`oUeA% z$WmL-O|=`Sf3;c2Okd)eXK(B4{4q4fRCb~5#8j$aQ}rF6AARQ46`gCG;+@06z9@o$ zYwTV)K3r5Och_YF`^4DjI8)gHJN>mXslXb1vWL7CfV#Czb)z$vYa6-W>>Z;K`W9eU z?<%#Ax@c&p_fJE#YC@hX4dz&L0=NP zA*509p5H%E(PDm317S4QIechKJ$kEw6d3ZHeQPfM4ZGnaQo9*P9XxiZ2=Gw2_6V%>awpX^bEY5Ofv?FlAk98MatbdB;fC zw5wRXW<(9_xKHz{^@@!GZ)+e|MOj%{d3h$7J=cHZ#RVMnvN#1>H&{L>OY}E?B3SLf z#f^<&Xu!fd)@3~fNEE# zb<43CRRVr|6zUQD;;3$avB`redJ`r7y3sKQ79`M7*^(r?_)TdFEJQ!RLIPLnQbnlR zwJ=l1ZQ7YaSKzWGRx9zN`HW>3lnf z<2Nxo&Gnu4iPcf=)sfcrCl5^d`KBH(ztD(gd&BfJ@ArwZAUQ(o`^y%um1evsaPl7OU~#D45Zv6+y(ZUvQICZbN8cVPpq)uk)3VGSizA27h|IicS zuNxLSC1sOn8Qw3wo+d+p6&cw(3%t*fLau0Hn+rOThs}$$;N}yC4|ja&4Y#mONYJ$S z-3gn;U^y0~-R?hf?}8mRoPJsCFfgaYbT4tQuc$UM7gVDvXaWeBt@@E)64+nFt>irr z^I$~u-p>u)KS#;UAJzS4*o>Crd)z%6@tz!AThHZiC#y4@n5o~r?bd55#^E3XQAz&e zyIfmN+CnpF7r-ogCvG>M;8x9@5zh2zPe3&aTlu76azDXp2w>;el;moEv>KABO0fm{ zq!b#fJ0E8x0~QR#jn@hCdw@!2Nga;tKLDn>lpOq z|8N`WDGG1x1@jR-e@-q_v73K?dvU+oba0J4YL3h4T-t)p4d~XpJd*#q+WkNU!e}Q#8MMQl z1xxntdClmok6YrQIuYX(p0Y=f<4Ra`6}>6;c

        +dM_?A-XJ#{thQ~G)*iW9e^*Dj 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 rybahytA8pp^utqp^)A6*rRRhfS9Y(W#xG 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 F{{k8)%X0t# literal 154293 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%0DZ@F5W-{`at8_` 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ⅈ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

        M;hLyM7 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

        gl#7&3uW&W?_@xSJam5a>D06 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 z

        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 From 10c747a877f33fd79debf4b52810c90239e22364 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 25 Oct 2019 17:11:13 +0200 Subject: [PATCH 384/457] fix calls to old projects --- Jenkinsfile | 10 +++++----- README.md | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index a5420343c..6d0e34f1f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,7 +7,7 @@ pipeline { parameters { booleanParam(name: 'E2E', defaultValue: false, description: 'Launch E2E test') - string(name: 'CLI', defaultValue: 'dev', description: 'substra-cli branch') + string(name: 'CLI', defaultValue: 'dev', description: 'substra branch') string(name: 'CHAINCODE', defaultValue: 'dev', description: 'chaincode branch') } @@ -149,15 +149,15 @@ pipeline { } } - stage('Test with substra-network') { + stage('Test with hlf-k8s') { when { expression { return params.E2E } } steps { - build job: 'substra-network/dev', parameters: [string(name: 'BACKEND', value: env.CHANGE_BRANCH), - string(name: 'CHAINCODE', value: params.CHAINCODE), - string(name: 'CLI', value: params.CLI)], propagate: true + build job: 'hlf-k8s/dev', parameters: [string(name: 'BACKEND', value: env.CHANGE_BRANCH), + string(name: 'CHAINCODE', value: params.CHAINCODE), + string(name: 'CLI', value: params.CLI)], propagate: true } } diff --git a/README.md b/README.md index 47f36f310..9b8ca36c7 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ guillaume:165536:65536 ``` The first line should be added with the docker group (999 in my case). -Final step is to redownload all the dockers image, go in the substra-network project and rerun the `./bootstrap.sh` script. +Final step is to redownload all the dockers image, go in the hlf-k8s project and rerun the `./bootstrap.sh` script. Do not forget to build the substra-model image as described in the step 9 of this tutorial. 3. Install dependencies (might be useful to create a virtual environment before, eg using virtualenv and virtualenvwrapper): @@ -83,7 +83,7 @@ BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python backend/manage.py migrate --s BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python backend/manage.py migrate --settings=backend.settings.dev ``` -###### With fixtures (fixtures container has been run from substra-network, old behavior for testing) +###### With fixtures (fixtures container has been run from hlf-k8s, old behavior for testing) data in fixtures are relative to the data already set in the ledger if the fixtures container instance succeeded @@ -123,9 +123,9 @@ docker build -t substra-model . ## Getting started 2: Linking the app with Hyperledger Fabric -### Make the subtra-network available to the app +### Make the hlf-k8s available to the app -[See here](https://github.com/SubstraFoundation/substra-network#network). +[See here](https://github.com/SubstraFoundation/hlf-k8s#network). ### Install rabbitmq @@ -162,7 +162,7 @@ Go in the `backend` folder and run the server locally: BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=backend.settings.server.nobasicauth BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=backend.settings.server.nobasicauth ``` - It allows the substrafront project to work correctly too. + It allows the substra-frontend project to work correctly too. ## Load data fixtures @@ -194,7 +194,7 @@ When you want to re-run the testing process: - Stop all your services and containers. - Rerun `recreate_db.sh` and `clean_media.sh` scripts. - Run the django migrations. -- Relaunch your substra-network. +- Relaunch your hlf-k8s network. - Run the owkin and chunantes substra-backend servers. - Run celery beat and celery owkin and chu-nantes. - Run the `populate.py` python script. @@ -224,7 +224,7 @@ Now you can reach `http://localhost:8000/` and `http://localhost:8001/` :tada: ## Launching with docker -As for substra-network, you can launch all the services in docker containers.| +As for hlf-k8s, you can launch all the services in docker containers.| First, build the images: ```bash $> sh build-docker-images.sh @@ -239,7 +239,7 @@ Check your services are correctly started with `docker ps -a`. ## Testing fabric-sdk-py A directory named `fabric-sdk-py_tests` is available to the root of this project. -If you launch a substra-network setup, you will be able to play with theses tests. +If you launch a hlf-k8s setup, you will be able to play with theses tests. For `fabric-sdk-py-query-invoke.py`, be sure to have run the `generateNetworkFile.py` script for producing the network.json file needed. ## Miscellaneous From 7b333ca3f4698b48303c77e63481d293b428a361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Morel?= Date: Mon, 28 Oct 2019 17:37:16 +0100 Subject: [PATCH 385/457] remove duplicate declaration of property --- backend/substrapp/serializers/ledger/traintuple/serializer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/substrapp/serializers/ledger/traintuple/serializer.py b/backend/substrapp/serializers/ledger/traintuple/serializer.py index 9efa6ded9..32edba29d 100644 --- a/backend/substrapp/serializers/ledger/traintuple/serializer.py +++ b/backend/substrapp/serializers/ledger/traintuple/serializer.py @@ -10,7 +10,6 @@ class LedgerTrainTupleSerializer(serializers.Serializer): algo_key = serializers.CharField(min_length=64, max_length=64) data_manager_key = serializers.CharField(min_length=64, max_length=64) objective_key = serializers.CharField(min_length=64, max_length=64) - rank = serializers.IntegerField(allow_null=True, required=False) rank = serializers.IntegerField(allow_null=True, required=False, default=0) compute_plan_id = serializers.CharField(min_length=64, max_length=64, allow_blank=True, required=False) in_models_keys = serializers.ListField(child=serializers.CharField(min_length=64, max_length=64), From 221404e4193b43e2201a2bdbc9757b0f464def0e Mon Sep 17 00:00:00 2001 From: Clement Gautier Date: Thu, 31 Oct 2019 15:53:26 +0100 Subject: [PATCH 386/457] Jenkins to Travis migration --- .cicd/agent-helm.yaml | 22 ------ .cicd/agent-kaniko.yaml | 18 ----- .cicd/agent-python.yaml | 22 ------ .travis.yml | 46 +++++++++++ Jenkinsfile | 165 ---------------------------------------- 5 files changed, 46 insertions(+), 227 deletions(-) delete mode 100644 .cicd/agent-helm.yaml delete mode 100644 .cicd/agent-kaniko.yaml delete mode 100644 .cicd/agent-python.yaml create mode 100644 .travis.yml delete mode 100644 Jenkinsfile diff --git a/.cicd/agent-helm.yaml b/.cicd/agent-helm.yaml deleted file mode 100644 index 5ba0de8c8..000000000 --- a/.cicd/agent-helm.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: Pod -spec: - containers: - - name: helm - image: dtzar/helm-kubectl - command: [cat] - tty: true - volumeMounts: - - name: chartmuseum-secret - mountPath: /secret - env: - - name: GOOGLE_APPLICATION_CREDENTIALS - value: /secret/chartmuseum-secret.json - resources: - limits: - memory: "128Mi" - cpu: "500m" - volumes: - - name: chartmuseum-secret - secret: - secretName: chartmuseum-secret diff --git a/.cicd/agent-kaniko.yaml b/.cicd/agent-kaniko.yaml deleted file mode 100644 index 2af6ade41..000000000 --- a/.cicd/agent-kaniko.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: v1 -kind: Pod -spec: - containers: - - name: kaniko - image: gcr.io/kaniko-project/executor:debug - command: [/busybox/cat] - tty: true - volumeMounts: - - name: kaniko-secret - mountPath: /secret - env: - - name: GOOGLE_APPLICATION_CREDENTIALS - value: /secret/kaniko-secret.json - volumes: - - name: kaniko-secret - secret: - secretName: kaniko-secret diff --git a/.cicd/agent-python.yaml b/.cicd/agent-python.yaml deleted file mode 100644 index c0abd5a32..000000000 --- a/.cicd/agent-python.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: Pod -spec: - containers: - - name: python - image: python:3.7 - command: [cat] - tty: true - volumeMounts: - - { name: tmp, mountPath: /tmp } - - { name: docker, mountPath: /var/run/docker.sock } - - { name: kaniko-secret, mountPath: /secret } - env: - - { name: GOOGLE_APPLICATION_CREDENTIALS, value: /secret/kaniko-secret.json } - volumes: - - name: tmp - hostPath: { path: /tmp, type: Directory } - - name: docker - hostPath: { path: /var/run/docker.sock, type: File } - - name: kaniko-secret - secret: - secretName: kaniko-secret diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..25664d1ff --- /dev/null +++ b/.travis.yml @@ -0,0 +1,46 @@ +language: python + +python: + - '3.7' + +cache: pip + +branches: + only: + - master + - dev + +env: + - DJANGO_SETTINGS_MODULE=backend.settings.test + +addons: + snaps: + - name: helm + confinement: classic + channel: stable + +before_script: + - helm init --client-only + +install: pip install -r backend/requirements.txt + +script: + - helm lint charts/substra-backend + - cd backend + - pip install flake8 + - flake8 + - coverage run manage.py test + +after_script: + - 'if ! git diff --quiet --exit-code $TRAVIS_COMMIT_RANGE charts; then CHART_CHANGED="true"; else CHART_CHANGED="false"; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then helm dep update charts/substra-backend; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then helm package charts/substra-backend; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then git config --global user.email "travis@travis-ci.org"; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then git config --global user.name "Travis CI"; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then git clone https://${GH_TOKEN}@github.com/SubstraFoundation/charts.git substra-charts; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then mv hlf-k8s-* substra-charts/; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then cd substra-charts; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then helm repo index .; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then git add .; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then git commit --message "Travis build: $TRAVIS_BUILD_NUMBER"; fi' + - 'if [ "$CHART_CHANGED" == "true" -a "$TRAVIS_PULL_REQUEST" == "false" ]; then git push --quiet --set-upstream origin master; fi' diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 6d0e34f1f..000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,165 +0,0 @@ -pipeline { - options { - timestamps () - timeout(time: 1, unit: 'HOURS') - buildDiscarder(logRotator(numToKeepStr: '5')) - } - - parameters { - booleanParam(name: 'E2E', defaultValue: false, description: 'Launch E2E test') - string(name: 'CLI', defaultValue: 'dev', description: 'substra branch') - string(name: 'CHAINCODE', defaultValue: 'dev', description: 'chaincode branch') - - } - - agent none - - stages { - stage('Abort previous builds'){ - steps { - milestone(Integer.parseInt(env.BUILD_ID)-1) - milestone(Integer.parseInt(env.BUILD_ID)) - } - } - - stage('Test & Build') { - parallel { - stage('Test Helm') { - agent { - kubernetes { - label 'substra-backend-helm' - defaultContainer 'helm' - yamlFile '.cicd/agent-helm.yaml' - } - } - - steps { - sh "helm lint charts/substra-backend" - } - } - - stage('Test') { - agent { - kubernetes { - label 'substra-backend-test' - defaultContainer 'python' - yamlFile '.cicd/agent-python.yaml' - } - } - - steps { - sh "apt update" - sh "apt install curl && mkdir -p /tmp/download && curl -L https://download.docker.com/linux/static/stable/x86_64/docker-18.06.3-ce.tgz | tar -xz -C /tmp/download && mv /tmp/download/docker/docker /usr/local/bin/" - sh "docker login -u _json_key --password-stdin https://eu.gcr.io/substra-208412/ < /secret/kaniko-secret.json" - sh "apt install -y python3-pip python3-dev build-essential gfortran musl-dev postgresql-contrib git curl netcat" - - dir("backend") { - sh "pip install flake8" - sh "flake8" - sh "pip install -r requirements.txt" - sh "DJANGO_SETTINGS_MODULE=backend.settings.test coverage run manage.py test" - sh "coverage report" - sh "coverage html" - } - } - - post { - success { - publishHTML target: [ - allowMissing: false, - alwaysLinkToLastBuild: false, - keepAll: true, - reportDir: 'backend/htmlcov', - reportFiles: 'index.html', - reportName: 'Coverage Report' - ] - } - } - } - - stage('Build substra-backend') { - agent { - kubernetes { - label 'substra-backend-kaniko-substra-backend' - yamlFile '.cicd/agent-kaniko.yaml' - } - } - - steps { - container(name:'kaniko', shell:'/busybox/sh') { - sh '''#!/busybox/sh - /kaniko/executor -f `pwd`/docker/substra-backend/Dockerfile -c `pwd` -d "eu.gcr.io/substra-208412/substra-backend:$GIT_COMMIT" - ''' - } - } - } - - stage('Build celerybeat') { - agent { - kubernetes { - label 'substra-backend-kaniko-celerybeat' - yamlFile '.cicd/agent-kaniko.yaml' - } - } - - steps { - container(name:'kaniko', shell:'/busybox/sh') { - sh '''#!/busybox/sh - /kaniko/executor -f `pwd`/docker/celerybeat/Dockerfile -c `pwd` -d "eu.gcr.io/substra-208412/celerybeat:$GIT_COMMIT" - ''' - } - } - } - - stage('Build celeryworker') { - agent { - kubernetes { - label 'substra-backend-kaniko-celeryworker' - yamlFile '.cicd/agent-kaniko.yaml' - } - } - - steps { - container(name:'kaniko', shell:'/busybox/sh') { - sh '''#!/busybox/sh - /kaniko/executor -f `pwd`/docker/celeryworker/Dockerfile -c `pwd` -d "eu.gcr.io/substra-208412/celeryworker:$GIT_COMMIT" - ''' - } - } - } - - stage('Publish Helm') { - agent { - kubernetes { - label 'substra-backend-helm' - defaultContainer 'helm' - yamlFile '.cicd/agent-helm.yaml' - } - } - - when { buildingTag() } - - steps { - sh "helm init --client-only" - sh "helm plugin install https://github.com/chartmuseum/helm-push" - sh "helm repo add substra https://substra-charts.owkin.com --username owlways --password Cokear4nnRK9ooC" - sh "helm push charts/substra-backend substra || true" - } - } - } - } - - stage('Test with hlf-k8s') { - when { - expression { return params.E2E } - } - - steps { - build job: 'hlf-k8s/dev', parameters: [string(name: 'BACKEND', value: env.CHANGE_BRANCH), - string(name: 'CHAINCODE', value: params.CHAINCODE), - string(name: 'CLI', value: params.CLI)], propagate: true - } - } - - } -} From e82479bb1c1218b92cd23d31e16d8b878da8f72a Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Mon, 4 Nov 2019 11:43:03 +0100 Subject: [PATCH 387/457] Fix flake 8 line too long. --- docker/start.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/start.py b/docker/start.py index 13c499673..d5bc0a0ec 100644 --- a/docker/start.py +++ b/docker/start.py @@ -308,7 +308,8 @@ def start(conf, launch_settings, no_backup, nobasicauth=False): no_backup = args['no_backup'] - conf = [json.load(open(file_path, 'r')) for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/substra-backend/conf.json')] + conf = [json.load(open(file_path, 'r')) + for file_path in glob.glob(f'{SUBSTRA_FOLDER}/conf/*/substra-backend/conf.json')] print('Build backend for : ', flush=True) print(' Organizations :', flush=True) From 9fae11eaa4bb43a9965436b6b3b89de5a86a62a0 Mon Sep 17 00:00:00 2001 From: Samuel Enguehard Date: Tue, 29 Oct 2019 20:44:19 +0100 Subject: [PATCH 388/457] Update image registry from grc.io to substrafoundation. --- charts/substra-backend/values.yaml | 10 ++++---- fixtures/chunantes/algos/algo3/algo.tar.gz | Bin 1571 -> 1170 bytes .../objectives/objective0/Dockerfile | 2 +- .../owkin/objectives/objective0/Dockerfile | 2 +- skaffold.yaml | 24 +++++++++--------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/charts/substra-backend/values.yaml b/charts/substra-backend/values.yaml index 61c70353f..d7048f5bc 100644 --- a/charts/substra-backend/values.yaml +++ b/charts/substra-backend/values.yaml @@ -9,7 +9,7 @@ docker: config: null # Images to pull pullImages: [] - # - eu.gcr.io/substra-208412/substra-tools:0.0.1 + # - substrafoundation/substra-tools:0.0.1 # Inline secrets used to pull images of pods (base64'd) pullSecretsInline: [] @@ -21,7 +21,7 @@ backend: defaultDomain: localhost image: - repository: eu.gcr.io/substra-208412/substra-backend + repository: substrafoundation/substra-backend tag: latest pullPolicy: IfNotPresent pullSecrets: [] @@ -155,7 +155,7 @@ flower: enabled: false image: - repository: eu.gcr.io/substra-208412/flower + repository: substrafoundation/flower tag: latest pullPolicy: IfNotPresent pullSecrets: [] @@ -173,7 +173,7 @@ flower: celerybeat: replicaCount: 1 image: - repository: eu.gcr.io/substra-208412/celerybeat + repository: substrafoundation/celerybeat tag: latest pullPolicy: IfNotPresent pullSecrets: [] @@ -199,7 +199,7 @@ celerybeat: celeryworker: replicaCount: 1 image: - repository: eu.gcr.io/substra-208412/celeryworker + repository: substrafoundation/celeryworker tag: latest pullPolicy: IfNotPresent pullSecrets: [] diff --git a/fixtures/chunantes/algos/algo3/algo.tar.gz b/fixtures/chunantes/algos/algo3/algo.tar.gz index a5f48c539bdfa9ed009bf64a07180790968f1f90..f3bbb776a7f326f9b9a4226f28b7a70bc131db80 100644 GIT binary patch literal 1170 zcmV;D1a12tiwFP!000001MOGcPwO@m=Q)4H8TTQn)Q0A^fW*{?yUPV#O@j%z8WTd1 z+c?D|u_N0BvT6VOj_ssPX)jEZ*mNiVUSc1gFP{(FA;nz8RlW0;7$OeFWAjZ8_ml3| zU_46R?IJ5@qQFY&#${*59G!^_3AWJ)o? zfj*J4DkwZMeFy5kphR-y2v}JOsi6?_Ipgzo`kNBG9rHz5)j$;RD#)cMTj{u99KUHP zGFm{xe0h5Ou^?zNXH*8Q3bmLjEr}MQP)3s-1VQi)PJ{$59{a5W=wDGFMZ=VWq(+)% zz&Knw6_BHVqO*l$x<&?qj;f#$j;BPi*+;>1Hji>vP)DO%)xuw&$e21IKK6Gx8I zG-ETJrpwigXo9PMEC~kpv_66dQY>h!MZuJgdcbmEigB!EKBJLc>|-ioo)IZY-2+-E z>V(#GnLwewzFRUOG!Df~(^5sfHC8l%oHv8y7A6x2(+~*H3<au)Q$SRdM`oc9p$vPbG4pjl8s+9Rh>gl9@2zYo@<2Bm z;B`}vTTNLTrnlP7c1>a9Gu~La?nB+!QnnQCC&P}pcX-kv`%JrXY{_k(GoFhmJf&Kj z!^W_Lt5{yA)({rs^^#UEX?4ejDG2PpjQvj6?NpL+9bNaH5$df*+$fe*-I0n$?cC08 zhPQnfB-`Xn^AnzGk>b%DwPG+Z3neAIrSyS3F@@3T!Jb)DI@??dI=jl5ZrV}sm%?|# zT=*<+*iq5;vda!`!8DMYxMRw62AafRZ_P{c6xsbG z-Tl;QCGqZ6|iC(bf7+@KO7<#CBY<%9_CMXsNHlm%eyxelMCsCkTEy zzxeU^^9AfFykV!}DF{9sA49xH+}|w3LGbD9>f+a*&p)4C!Od=CVz&>w4a@GWKQKHz kJUl!+JUl!+JUl!+JUl!+JUl!+JpP~f3+nKM(*P&{07FnhDgXcg literal 1571 zcmV+;2Hg1{iwFQuz^+{Y1ML?(Y#c>&4FZytP(Ua|qCkUF>|VHA@7~9kI68?CJBcAV zNA@K+vaHSA?d*ASdppa{oP9@xpg>53PXP@`NJK)SND!ib=y2jVSdfEfml8c1{9I6!@_?>Q1O^&B(>gPI8rO+u zJ8PwKIiTxh!CH+x_rl(#GI_nzayr1=5pM4AQL9kQTje8%ixWS5vnmC@vj6Ina=h8Q z@m{c8eg8)7#=QB}2fv2&3*LUwLkxP>yJZ!|NF(&*5uP)*Z=zbm%9zy{{?4p z_Y}bn38!|h4{TTeW}z@v|D|GaT0!GUvm@}3*MGi@+Jd%8#VVDpa-mSNiblS4qg3-~YvOY4`rW7jR;6;S3@jquB@z%BFay&P9lGdGm15%J-Lo zF^|ufhG|%;x_GXNa3FF`B2Xug_wdpFn)=`;&qKK$s&}a8YMG zv$M#U!d{aZKxnAyT(!1%;q1bEwT4zE6BUzLG?|c0u0G^#F7d;T>e#0Kiv=sHf2&j| z6sFCxtbh31t^a!gnx-vv>TSw7Wj-QZ+=j<9+Mr@BEi<4{X**z{Kpty0;c1>OFLCCl z^SClGM}DBXA#11HhDUuE?KX3WhZ5qYle5R+9nYytNvNhGl4cY28YwB7sH%DponRsI z*+w=s0PKUF;4^{h1cgL$69;+)T8c#=7Z^BcbV4e6K!Cwet|rVz9dp_^&U}|Pb$Rjm z7@j{`WZ)Fg#HJcB(?B6vCtfAxoSl35+{p}>)R5MrV^BMKWThdenHg1;pH2>Okpu3q z6Bon+bxu4ti=sJDrr%juh!9m`v|-y0Z3x@$@5&Dt*uC6GNNADX3|hxthZur+lnXtB zsEa6%nx)?$dbF8^P#C_0!w~l}hYY3XIM4=a8=`qf2x8pYiNQp^ty0|$xxN_mt*RpyhKZJZ+MQ>Tp5CIUA* zUj}9iS_vFJO~K20bf|2s3St#SDrV1QHZjTo-nqC~%DC?%iZSO8J3YW+ZOG=R3$TFr zy4=VjEz~lyFx^o*65+BN7*eF}W(GPqUMHIiV0%>?TdIn5$l6K|JFE%{pZbZG|?MM+M<8mL@>*IPuI%GmX z{Wxj-wUYHZOg;&wVrY=C`(10;cg+G@6OSC7tP4WFlH2O-=Ym55bNWdjaER>!H3 zA>t&{W1ehm)E1o{L=B~7B6N_L<5vLaAzX~)(*PAshJ!Dcw~T$vv^n$=KN5LB+#>KJ zJL=tq;r31i4VyYs%mFtmq=IeB8`-wwYsPLv3~XDA{T1J~(W8}g;er=Lk8WWw^?tvk Vc3~HGVHX}O_z$JK%a8yZ006y{`*i>S diff --git a/fixtures/chunantes/objectives/objective0/Dockerfile b/fixtures/chunantes/objectives/objective0/Dockerfile index b3ba938a0..a9166d836 100644 --- a/fixtures/chunantes/objectives/objective0/Dockerfile +++ b/fixtures/chunantes/objectives/objective0/Dockerfile @@ -1,4 +1,4 @@ -FROM eu.gcr.io/substra-208412/substra-tools:0.0.1 +FROM substrafoundation/substra-tools:0.0.1 RUN mkdir -p /sandbox/opener WORKDIR /sandbox diff --git a/fixtures/owkin/objectives/objective0/Dockerfile b/fixtures/owkin/objectives/objective0/Dockerfile index b3ba938a0..a9166d836 100644 --- a/fixtures/owkin/objectives/objective0/Dockerfile +++ b/fixtures/owkin/objectives/objective0/Dockerfile @@ -1,4 +1,4 @@ -FROM eu.gcr.io/substra-208412/substra-tools:0.0.1 +FROM substrafoundation/substra-tools:0.0.1 RUN mkdir -p /sandbox/opener WORKDIR /sandbox diff --git a/skaffold.yaml b/skaffold.yaml index e819de845..e23ba4528 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -2,22 +2,22 @@ apiVersion: skaffold/v1beta13 kind: Config build: artifacts: - - image: eu.gcr.io/substra-208412/substra-backend + - image: substrafoundation/substra-backend context: . docker: dockerfile: docker/substra-backend/Dockerfile - - image: eu.gcr.io/substra-208412/celerybeat + - image: substrafoundation/celerybeat context: . docker: dockerfile: docker/celerybeat/Dockerfile - - image: eu.gcr.io/substra-208412/celeryworker + - image: substrafoundation/celeryworker context: . docker: dockerfile: docker/celeryworker/Dockerfile - - image: eu.gcr.io/substra-208412/flower + - image: substrafoundation/flower context: . docker: dockerfile: docker/flower/Dockerfile @@ -31,10 +31,10 @@ deploy: imageStrategy: helm: {} values: - backend.image: eu.gcr.io/substra-208412/substra-backend - celerybeat.image: eu.gcr.io/substra-208412/celerybeat - celeryworker.image: eu.gcr.io/substra-208412/celeryworker - flower.image: eu.gcr.io/substra-208412/flower + backend.image: substrafoundation/substra-backend + celerybeat.image: substrafoundation/celerybeat + celeryworker.image: substrafoundation/celeryworker + flower.image: substrafoundation/flower overrides: secrets: fabricConfigmap: network-peer-1-hlf-k8s-fabric @@ -78,10 +78,10 @@ deploy: imageStrategy: helm: {} values: - backend.image: eu.gcr.io/substra-208412/substra-backend - celerybeat.image: eu.gcr.io/substra-208412/celerybeat - celeryworker.image: eu.gcr.io/substra-208412/celeryworker - flower.image: eu.gcr.io/substra-208412/flower + backend.image: substrafoundation/substra-backend + celerybeat.image: substrafoundation/celerybeat + celeryworker.image: substrafoundation/celeryworker + flower.image: substrafoundation/flower overrides: secrets: fabricConfigmap: network-peer-2-hlf-k8s-fabric From 2f477b8605bfe86e6aee45e0058a05c5c1d554a1 Mon Sep 17 00:00:00 2001 From: Camille Marini Date: Mon, 4 Nov 2019 19:47:39 +0100 Subject: [PATCH 389/457] update codeowner according to orga --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0ecad7c26..19e65abf8 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,4 +2,4 @@ # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. -* @inalgnu @GuillaumeCisco @Kelvin-M +* @inalgnu @GuillaumeCisco @Kelvin-M @samlesu From 897a2976e63c0effce7f26c317b69ba6b57a3db8 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:34:36 +0200 Subject: [PATCH 390/457] Fix tests - docker - add session authent --- .gitignore | 1 + README.md | 28 ++++++-- backend/backend/settings/common.py | 1 - .../backend/settings/deps/restframework.py | 7 +- backend/backend/settings/test.py | 6 -- backend/backend/urls.py | 1 + backend/requirements.txt | 1 + backend/substrapp/tests/assets.py | 1 - backend/substrapp/tests/common.py | 36 ++++++++-- backend/substrapp/tests/generate_assets.py | 7 +- backend/substrapp/tests/tests_tasks.py | 8 ++- .../tests/views/test_views_authentication.py | 7 +- .../substrapp/tests/views/tests_views_algo.py | 5 +- backend/substrapp/views/utils.py | 57 +++------------ docker/celerybeat/Dockerfile | 1 + docker/celeryworker/Dockerfile | 4 +- docker/flower/Dockerfile | 1 + docker/start.py | 29 ++++---- docker/substra-backend/Dockerfile | 1 + docker/substrabac/Dockerfile | 21 ++++++ substrabac/libs/sessionAuthentication.py | 19 +++++ substrabac/node/generate_nodes.py | 65 +++++++++++++++++ .../node/management/commands/init_nodes.py | 26 +++++++ substrabac/user/authentication.py | 29 ++++++++ substrabac/user/views/user.py | 71 +++++++++++++++++++ 25 files changed, 334 insertions(+), 99 deletions(-) create mode 100644 docker/substrabac/Dockerfile create mode 100644 substrabac/libs/sessionAuthentication.py create mode 100755 substrabac/node/generate_nodes.py create mode 100644 substrabac/node/management/commands/init_nodes.py create mode 100644 substrabac/user/authentication.py create mode 100644 substrabac/user/views/user.py diff --git a/.gitignore b/.gitignore index 807b86293..7b17fc603 100644 --- a/.gitignore +++ b/.gitignore @@ -115,3 +115,4 @@ SECRET # substra-backend files docker/docker-compose-dynamic.yaml **/medias/* +backend/node/nodes/* diff --git a/README.md b/README.md index 9b8ca36c7..479873d78 100644 --- a/README.md +++ b/README.md @@ -164,12 +164,21 @@ Go in the `backend` folder and run the server locally: ``` It allows the substra-frontend project to work correctly too. -## Load data fixtures +## Generate nodes authentication + +For working with node to node authentication, you need to generate and then load some fixtures +``` +python ./backend/node/generate_nodes.py +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 ./manage.py init_nodes ./backend/node/nodes/owkinMSP.json --settings=backend.settings.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 ./manage.py init_nodes ./backend/node/nodes/chu-nantesMSP.json --settings=backend.settings.dev +``` + +## Create a default user For working with node to node authentication, you need load some extra fixtures ``` -BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python manage.py loaddata nodes-owkin.yaml --settings=backend.settings.server.dev -BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python manage.py loaddata nodes-chunantes.yaml --settings=backend.settings.server.dev +BACKEND_ORG=owkin ./backend/manage.py add_user substra p@$swr0d44 --settings=backend.settings.dev +BACKEND_ORG=chu-nantes ./backend/manage.py add_user substra p@$swr0d44 --settings=backend.settings.dev ``` ## Test with unit and functional tests @@ -224,14 +233,21 @@ Now you can reach `http://localhost:8000/` and `http://localhost:8001/` :tada: ## Launching with docker -As for hlf-k8s, you can launch all the services in docker containers.| -First, build the images: +As for hlf-k8s, you can launch all the services in docker containers. + +First, Make sure you've generated some nodes artifacts: +```bash +$> python ./backend/node/generate_nodes.py +``` + +Then, build the images: ```bash $> sh build-docker-images.sh ``` + Then, go to the`docker` dir and run `start.py`: ```bash -$> python3 start.py +$> python3 start.py -d --no-backup ``` Check your services are correctly started with `docker ps -a`. diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index a2f230791..7ff0f4533 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -161,7 +161,6 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 - BASIC_AUTHENTICATION_MODULE = 'rest_framework.authentication' diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index 7d7062470..d44975644 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -6,9 +6,12 @@ 'rest_framework.renderers.BrowsableAPIRenderer', ), 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.SessionAuthentication', + 'user.authentication.SecureJWTAuthentication', # for front/sdk/cli + 'libs.sessionAuthentication.CustomSessionAuthentication', # for web browsable api + ], + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.IsAuthenticated', ], - 'DEFAULT_PERMISSION_CLASSES': [], 'UNICODE_JSON': False, 'DEFAULT_VERSIONING_CLASS': 'libs.versioning.AcceptHeaderVersioningRequired', 'ALLOWED_VERSIONS': ('0.0',), diff --git a/backend/backend/settings/test.py b/backend/backend/settings/test.py index 3fa8821e8..add578481 100644 --- a/backend/backend/settings/test.py +++ b/backend/backend/settings/test.py @@ -4,9 +4,3 @@ import logging logging.disable(logging.CRITICAL) - -BASICAUTH_USERNAME = "test" -BASICAUTH_PASSWORD = "test" - -# by default, bypass basic auth -BASIC_AUTHENTICATION_MODULE = 'substrapp.views.utils' diff --git a/backend/backend/urls.py b/backend/backend/urls.py index 0ffe8eb38..e9661c764 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -30,6 +30,7 @@ url(r'^doc/', schema_view), url(r'^', include((router.urls, 'substrapp'))), url(r'^', include((nodeRouter.urls, 'node'))), + url(r'^api-auth/', include('rest_framework.urls')), ])), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/backend/requirements.txt b/backend/requirements.txt index cb6ed95ce..57e5ca70d 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -9,6 +9,7 @@ django-celery-results==1.0.4 django-filter==1.1.0 django-rest-swagger==2.1.2 djangorestframework==3.8.2 +djangorestframework-simplejwt==4.3.0 docker == 3.5.0 grpcio >= 1.0.1 GPUtil == 1.4.0 diff --git a/backend/substrapp/tests/assets.py b/backend/substrapp/tests/assets.py index 1c8ad63cb..044a96213 100644 --- a/backend/substrapp/tests/assets.py +++ b/backend/substrapp/tests/assets.py @@ -605,4 +605,3 @@ } } ] - diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 9e41fa64e..999685ef4 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -1,27 +1,53 @@ +from http.cookies import SimpleCookie from io import StringIO, BytesIO import os import base64 from django.conf import settings +from django.contrib.auth.models import User from django.core.files.uploadedfile import InMemoryUploadedFile +from django.db import transaction from rest_framework.test import APIClient # This function helper generate a basic authenticaiton header with given credentials # Given username and password it returns "Basic GENERATED_TOKEN" +from user.serializers import CustomTokenObtainPairSerializer + + def generate_basic_auth_header(username, password): return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() +def generate_jwt_auth_header(jwt): + return 'JWT ' + jwt + class AuthenticatedClient(APIClient): def request(self, **kwargs): - basic_auth_header = generate_basic_auth_header( - settings.BASICAUTH_USERNAME, - settings.BASICAUTH_PASSWORD - ) - self.credentials(HTTP_AUTHORIZATION=basic_auth_header) + # create user + username = 'foo' + password = 'barbar10' + try: + with transaction.atomic(): + User.objects.create_user(username=username, password=password) + except: + pass + # simulate login + serializer = CustomTokenObtainPairSerializer(data={ + 'username': username, + 'password': password + }) + + serializer.is_valid() + token = serializer.validated_data + jwt = str(token) + + # simulate right httpOnly cookie and Authorization jwt + jwt_auth_header = generate_jwt_auth_header('.'.join(jwt.split('.')[0:2])) + self.credentials(HTTP_AUTHORIZATION=jwt_auth_header) + self.cookies = SimpleCookie({'signature': jwt.split('.')[2]}) return super().request(**kwargs) diff --git a/backend/substrapp/tests/generate_assets.py b/backend/substrapp/tests/generate_assets.py index 174aaa135..89b7340f1 100644 --- a/backend/substrapp/tests/generate_assets.py +++ b/backend/substrapp/tests/generate_assets.py @@ -1,6 +1,6 @@ import os import json -from substra import Client +import substra dir_path = os.path.dirname(__file__) @@ -9,8 +9,9 @@ def main(): - client = Client() - client.add_profile('owkin', 'http://owkin.substra-backend:8000', '0.0') + client = substra.Client() + client.add_profile('owkin', 'substra', 'p@$swr0d44', 'http://owkin.substrabac:8000', '0.0') + client.login() client.set_profile('owkin') diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 497fca61a..42590b28e 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -53,6 +53,9 @@ def setUp(self): @classmethod def setUpTestData(cls): cls.outgoing_node = OutgoingNode.objects.create(node_id="external_node_id", secret="s3cr37") + cls.outgoing_node_traintuple = OutgoingNode.objects.create(node_id=assets.traintuple[1]['creator'], secret="s3cr37") + if assets.traintuple[1]['creator'] != assets.algo[0]['owner']: + cls.outgoing_node_algo = OutgoingNode.objects.create(node_id=assets.algo[0]['owner'], secret="s3cr37") cls.outgoing_node_traintuple = OutgoingNode.objects.create(node_id=assets.traintuple[1]['creator'], secret="s3cr37") @@ -435,10 +438,11 @@ def test_get_models(self): def test_get_algo(self): algo_content = self.algo.read() algo_hash = get_hash(self.algo) + subtuple = { 'algo': { 'storageAddress': assets.algo[0]['content']['storageAddress'], - 'owner': assets.algo[0]['owner'], + 'owner': assets.algo[0]['owner'], 'hash': algo_hash } } @@ -447,7 +451,7 @@ def test_get_algo(self): mock.patch('substrapp.tasks.utils.get_owner') as get_owner,\ mock.patch('substrapp.tasks.tasks.get_object_from_ledger') as get_object_from_ledger: mget_remote_file.return_value = algo_content - get_owner.return_value = assets.algo[0]['owner'] + get_owner.return_value = 'external_node_id' get_object_from_ledger.return_value = assets.algo[0] data = get_algo(subtuple) diff --git a/backend/substrapp/tests/views/test_views_authentication.py b/backend/substrapp/tests/views/test_views_authentication.py index d8b748f8d..ad0ed0307 100644 --- a/backend/substrapp/tests/views/test_views_authentication.py +++ b/backend/substrapp/tests/views/test_views_authentication.py @@ -4,7 +4,7 @@ import shutil from rest_framework import status from rest_framework.test import APITestCase -from node.models import IncomingNode +from node.models import IncomingNode, OutgoingNode from substrapp.models import Algo from ..common import generate_basic_auth_header, get_sample_algo_metadata, get_sample_algo, get_description_algo @@ -37,14 +37,15 @@ def tearDown(self): @classmethod def setUpTestData(cls): cls.incoming_node = IncomingNode.objects.create(node_id="external_node_id", secret="s3cr37") + cls.outgoing_node = OutgoingNode.objects.create(node_id="external_node_id", secret="s3cr37") def test_authentication_fail(self): response = self.client.get(self.algo_url, **self.extra) self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code) - def test_authentication_with_settings_success(self): - authorization_header = generate_basic_auth_header(settings.BASICAUTH_USERNAME, settings.BASICAUTH_PASSWORD) + def test_authentication_internal(self): + authorization_header = generate_basic_auth_header(self.outgoing_node.node_id, self.outgoing_node.secret) self.client.credentials(HTTP_AUTHORIZATION=authorization_header) diff --git a/backend/substrapp/tests/views/tests_views_algo.py b/backend/substrapp/tests/views/tests_views_algo.py index e9407caa7..c40d0c794 100644 --- a/backend/substrapp/tests/views/tests_views_algo.py +++ b/backend/substrapp/tests/views/tests_views_algo.py @@ -4,6 +4,7 @@ import logging import mock +import urllib.parse from django.urls import reverse from django.test import override_settings @@ -95,8 +96,8 @@ def test_algo_list_filter_dual(self): with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: mquery_ledger.return_value = algo - search_params = '?search=algo%253Aname%253ALogistic%2520regression' - search_params += f'%2Calgo%253Aowner%253A{algo[2]["owner"]}' + search_params = f'?search=algo%253Aname%253A{urllib.parse.quote(algo[0]["name"])}' + search_params += f'%2Calgo%253Aowner%253A{algo[0]["owner"]}' response = self.client.get(url + search_params, **self.extra) r = response.json() diff --git a/backend/substrapp/views/utils.py b/backend/substrapp/views/utils.py index 69c54f1d6..a98a78534 100644 --- a/backend/substrapp/views/utils.py +++ b/backend/substrapp/views/utils.py @@ -1,14 +1,12 @@ import os -import base64 -import binascii -from importlib import import_module from django.http import FileResponse -from rest_framework.authentication import SessionAuthentication, BasicAuthentication, get_authorization_header +from rest_framework.authentication import BasicAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response +from libs.sessionAuthentication import CustomSessionAuthentication from substrapp.ledger_utils import get_object_from_ledger, LedgerError from substrapp.utils import NodeError, get_remote_file, get_owner, get_remote_file_content from node.models import OutgoingNode @@ -18,9 +16,8 @@ from requests.auth import HTTPBasicAuth from wsgiref.util import is_hop_by_hop -from django.utils.translation import ugettext_lazy as _ -from rest_framework import HTTP_HEADER_ENCODING, exceptions +from user.authentication import SecureJWTAuthentication def authenticate_outgoing_request(outgoing_node_id): @@ -52,46 +49,6 @@ def is_local_user(user): return user.username == settings.BASICAUTH_USERNAME -class BasicAuthentication(BasicAuthentication): - def authenticate(self, request): - """ - Returns a `User` if a correct username and password have been supplied - using HTTP Basic authentication. Otherwise returns `None`. - """ - auth = get_authorization_header(request).split() - - if not auth or auth[0].lower() != b'basic': - if not settings.DEBUG: - return None - else: - # create fake auth in debug mode, if no provided (user case, not node) - debug_basic_auth = f'{settings.BASICAUTH_USERNAME}:{settings.BASICAUTH_PASSWORD}' - auth = [b'Basic', base64.b64encode(debug_basic_auth.encode(HTTP_HEADER_ENCODING))] - - if len(auth) == 1: - msg = _('Invalid basic header. No credentials provided.') - raise exceptions.AuthenticationFailed(msg) - elif len(auth) > 2: - msg = _('Invalid basic header. Credentials string should not contain spaces.') - raise exceptions.AuthenticationFailed(msg) - - try: - auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':') - except (TypeError, UnicodeDecodeError, binascii.Error): - msg = _('Invalid basic header. Credentials not correctly base64 encoded.') - raise exceptions.AuthenticationFailed(msg) - - userid, password = auth_parts[0], auth_parts[2] - return self.authenticate_credentials(userid, password, request) - - def authenticate_header(self, request): - if not settings.DEBUG: - return 'Basic realm="%s"' % self.www_authenticate_realm - - # do not prompt basic auth prompt in debug mode - return '' - - def node_has_process_permission(asset): """Check if current node can process input asset.""" permission = asset['permissions']['process'] @@ -99,9 +56,11 @@ def node_has_process_permission(asset): class PermissionMixin(object): - - authentication_classes = [import_module(settings.BASIC_AUTHENTICATION_MODULE).BasicAuthentication, - SessionAuthentication] + authentication_classes = [ + BasicAuthentication, # for node to node + SecureJWTAuthentication, # for user from front/sdk/cli + CustomSessionAuthentication, # for user on drf web browsable api + ] permission_classes = [IsAuthenticated] def _has_access(self, user, asset): diff --git a/docker/celerybeat/Dockerfile b/docker/celerybeat/Dockerfile index 18ce90983..218b913a0 100644 --- a/docker/celerybeat/Dockerfile +++ b/docker/celerybeat/Dockerfile @@ -15,3 +15,4 @@ COPY ./backend/libs /usr/src/app/libs COPY ./backend/substrapp /usr/src/app/substrapp COPY ./backend/backend /usr/src/app/backend COPY ./backend/node /usr/src/app/node +COPY ./backend/user /usr/src/app/user diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index fdbc9f497..c81309db2 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -13,5 +13,5 @@ RUN pip3 install -r requirements.txt COPY ./backend/libs /usr/src/app/libs COPY ./backend/substrapp /usr/src/app/substrapp -COPY ./backend/backend /usr/src/app/backend -COPY ./backend/node /usr/src/app/node +COPY ./backend/backend /usr/src/app/bac +COPY ./backend/user /usr/src/app/user diff --git a/docker/flower/Dockerfile b/docker/flower/Dockerfile index 2d0371344..43b082012 100644 --- a/docker/flower/Dockerfile +++ b/docker/flower/Dockerfile @@ -16,3 +16,4 @@ COPY ./backend/libs /usr/src/app/libs COPY ./backend/substrapp /usr/src/app/substrapp COPY ./backend/backend /usr/src/app/backend COPY ./backend/node /usr/src/app/node +COPY ./backend/user /usr/src/app/user diff --git a/docker/start.py b/docker/start.py index d5bc0a0ec..03ff5474f 100644 --- a/docker/start.py +++ b/docker/start.py @@ -22,7 +22,7 @@ SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') -def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): +def generate_docker_compose_file(conf, launch_settings): # POSTGRES POSTGRES_USER = 'backend' @@ -111,6 +111,9 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): }, 'path': os.path.join(dir_path, './docker-compose-dynamic.yaml')} + # generate nodes + # TODO make sure nodes folder exists else warn + for org in conf: org_name = org['name'] org_name_stripped = org_name.replace('-', '') @@ -126,9 +129,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f'--master --processes {processes} --threads 2 --need-app' \ f'--env DJANGO_SETTINGS_MODULE=backend.settings.server.prod uwsgi --http :{port} ' else: - print('nobasicauth: ', nobasicauth, flush=True) - extra_settings = '.nobasicauth' if nobasicauth is True else '' - django_server = f'DJANGO_SETTINGS_MODULE=backend.settings.server{extra_settings}.dev ' \ + django_server = f'DJANGO_SETTINGS_MODULE=backend.settings.server.dev ' \ f'python3 manage.py runserver --noreload 0.0.0.0:{port}' backend_global_env = [ @@ -150,8 +151,6 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): f'DJANGO_SETTINGS_MODULE=backend.settings.{launch_settings}', # Basic auth - f"BACK_AUTH_USER={os.environ.get('BACK_AUTH_USER', 'admin')}", - f"BACK_AUTH_PASSWORD={os.environ.get('BACK_AUTH_PASSWORD', 'admin')}", f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", ] @@ -170,8 +169,10 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): # load incoming/outgoing node fixtures/ that should not be executed in production env fixtures_command = '' + user_command = '' if launch_settings == 'dev': - fixtures_command = f"python manage.py loaddata nodes-{org_name_stripped}" + fixtures_command = f"python manage.py init_nodes ./node/nodes/{org_name}MSP.json" + user_command = f"python manage.py add_user foo barbar10" backend = { 'container_name': f'{org_name_stripped}.substra-backend', @@ -180,7 +181,7 @@ def generate_docker_compose_file(conf, launch_settings, nobasicauth=False): 'restart': 'unless-stopped', 'ports': [f'{port}:{port}'], 'command': f'/bin/bash -c "{wait_rabbit}; {wait_psql}; ' - f'yes | python manage.py migrate; {fixtures_command}; {django_server}"', + f'yes | python manage.py migrate; {fixtures_command}; {user_command}; {django_server}"', 'logging': {'driver': 'json-file', 'options': {'max-size': '20m', 'max-file': '5'}}, 'environment': backend_global_env.copy(), 'volumes': [ @@ -265,9 +266,9 @@ def stop(docker_compose=None): os.path.join(dir_path, '../'), 'down', '--remove-orphans']) -def start(conf, launch_settings, no_backup, nobasicauth=False): +def start(conf, launch_settings, no_backup): print('Generate docker-compose file\n') - docker_compose = generate_docker_compose_file(conf, launch_settings, nobasicauth) + docker_compose = generate_docker_compose_file(conf, launch_settings) stop(docker_compose) @@ -291,8 +292,6 @@ def start(conf, launch_settings, no_backup, nobasicauth=False): parser = argparse.ArgumentParser() parser.add_argument('-d', '--dev', action='store_true', default=False, help="use dev settings") - parser.add_argument('--nobasicauth', action='store_true', default=False, - help="use dev settings without basic authentication") parser.add_argument('--no-backup', action='store_true', default=False, help="Remove backup binded volume, medias and db data. Launch from scratch") args = vars(parser.parse_args()) @@ -302,10 +301,6 @@ def start(conf, launch_settings, no_backup, nobasicauth=False): else: launch_settings = 'prod' - nobasicauth = False - if args['nobasicauth']: - nobasicauth = True - no_backup = args['no_backup'] conf = [json.load(open(file_path, 'r')) @@ -318,4 +313,4 @@ def start(conf, launch_settings, no_backup, nobasicauth=False): print('', flush=True) - start(conf, launch_settings, no_backup, nobasicauth) + start(conf, launch_settings, no_backup) diff --git a/docker/substra-backend/Dockerfile b/docker/substra-backend/Dockerfile index 48d624fc0..08dd0ed2c 100644 --- a/docker/substra-backend/Dockerfile +++ b/docker/substra-backend/Dockerfile @@ -18,3 +18,4 @@ COPY ./backend/events /usr/src/app/events COPY ./backend/backend /usr/src/app/backend COPY ./backend/node /usr/src/app/node COPY ./backend/node-register /usr/src/app/node-register +COPY ./backend/user /usr/src/app/user diff --git a/docker/substrabac/Dockerfile b/docker/substrabac/Dockerfile new file mode 100644 index 000000000..6b3cd21a8 --- /dev/null +++ b/docker/substrabac/Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.6 + +RUN apt-get update +RUN apt-get install -y python3 python3-pip python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev g++ gcc gfortran musl-dev postgresql-contrib +RUN apt-get install -y git curl netcat + +RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +COPY ./substrabac/requirements.txt /usr/src/app/. + +RUN pip3 install -r requirements.txt + +COPY ./substrabac/manage.py /usr/src/app/manage.py +COPY ./substrabac/libs /usr/src/app/libs +COPY ./substrabac/substrapp /usr/src/app/substrapp +COPY ./substrabac/events /usr/src/app/events +COPY ./substrabac/substrabac /usr/src/app/substrabac +COPY ./substrabac/node /usr/src/app/node +COPY ./substrabac/node-register /usr/src/app/node-register +COPY ./substrabac/user /usr/src/app/user diff --git a/substrabac/libs/sessionAuthentication.py b/substrabac/libs/sessionAuthentication.py new file mode 100644 index 000000000..85f28544c --- /dev/null +++ b/substrabac/libs/sessionAuthentication.py @@ -0,0 +1,19 @@ +from rest_framework.authentication import SessionAuthentication + + +class CustomSessionAuthentication(SessionAuthentication): + """ + Use Django's session framework for authentication. + """ + + def authenticate(self, request): + """ + Returns a `User` if the request session currently has a logged in user. + Otherwise returns `None`. + """ + + # bypass for login with jwt + if request.resolver_match.url_name == 'user-login': + return None + + return super(CustomSessionAuthentication, self).authenticate(request) diff --git a/substrabac/node/generate_nodes.py b/substrabac/node/generate_nodes.py new file mode 100755 index 000000000..0750d3ff3 --- /dev/null +++ b/substrabac/node/generate_nodes.py @@ -0,0 +1,65 @@ +import json +import os +import secrets + + +def generate_secret(): + return secrets.token_hex(64) + + +def generate(orgs): + files = {} + + # TODO merge two loops + # init file content + for org in orgs: + data = { + 'incoming_nodes': [], + 'outgoing_nodes': [], + } + files[org] = data + + for org in orgs: + # create intern node (request from worker A to substrabac A) + secret = generate_secret() + files[org]['outgoing_nodes'].append({ + 'node_id': org, + 'secret': secret + }) + files[org]['incoming_nodes'].append({ + 'node_id': org, + 'secret': secret + }) + + for other_org in filter(lambda x: x != org, orgs): + # outgoing from server B to server A share same secret as incoming from server B in server A + secret = generate_secret() + files[other_org]['outgoing_nodes'].append({ # in server B + 'node_id': org, # to server A + 'secret': secret + }) + + files[org]['incoming_nodes'].append({ # in server A + 'node_id': other_org, # from server B + 'secret': secret + }) + + return files + + +def generate_for_orgs(orgs): + files = generate(orgs) + dir_path = os.path.dirname(os.path.realpath(__file__)) + nodes_path = os.path.join(dir_path, 'nodes') + os.makedirs(nodes_path, exist_ok=True) + for k, v in files.items(): + filepath = os.path.join(nodes_path, f'{k}.json') + with open(filepath, 'w') as f: + f.write(json.dumps(v, indent=4)) + + +if __name__ == '__main__': + orgs = ['owkinMSP', 'chu-nantesMSP', 'clbMSP'] # TODO should be discovered by discovery service + + generate_for_orgs(orgs) + diff --git a/substrabac/node/management/commands/init_nodes.py b/substrabac/node/management/commands/init_nodes.py new file mode 100644 index 000000000..297679194 --- /dev/null +++ b/substrabac/node/management/commands/init_nodes.py @@ -0,0 +1,26 @@ +import json + +from django.core.management.base import BaseCommand +from node.models import IncomingNode, OutgoingNode + + +class Command(BaseCommand): + help = 'Load nodes from file' + + def add_arguments(self, parser): + parser.add_argument('file') + + def handle(self, *args, **options): + + filepath = options['file'] + + print(filepath) + with open(filepath) as json_file: + data = json.load(json_file) + + for node in data['incoming_nodes']: + IncomingNode.objects.create(node_id=node['node_id'], secret=node['secret']) + self.stdout.write(self.style.SUCCESS('created incoming node')) + for node in data['outgoing_nodes']: + OutgoingNode.objects.create(node_id=node['node_id'], secret=node['secret']) + self.stdout.write(self.style.SUCCESS('created outgoing node')) diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py new file mode 100644 index 000000000..1ac8d8f2b --- /dev/null +++ b/substrabac/user/authentication.py @@ -0,0 +1,29 @@ +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class SecureJWTAuthentication(JWTAuthentication): + + def authenticate(self, request): + if request.resolver_match.url_name in ('user-login', 'api-root'): + return None + + header = self.get_header(request) + if header is None: + return None + + raw_token = self.get_raw_token(header) + if raw_token is None: + return None + + # reconstruct token from httpOnly cookie signature + try: + signature = request.COOKIES['signature'] + except: + return None + else: + raw_token = raw_token + f".{signature}".encode() + + validated_token = self.get_validated_token(raw_token) + + return self.get_user(validated_token), None + diff --git a/substrabac/user/views/user.py b/substrabac/user/views/user.py new file mode 100644 index 000000000..273637d84 --- /dev/null +++ b/substrabac/user/views/user.py @@ -0,0 +1,71 @@ +import datetime + +from django.conf import settings +from django.contrib.auth.models import User + +from rest_framework import status +from rest_framework.permissions import AllowAny +from rest_framework.viewsets import GenericViewSet +from rest_framework.decorators import list_route +from rest_framework.response import Response +from rest_framework_simplejwt.authentication import AUTH_HEADER_TYPES +from rest_framework_simplejwt.exceptions import TokenError, InvalidToken, AuthenticationFailed + +from user.serializers import CustomTokenObtainPairSerializer + + +class UserViewSet(GenericViewSet): + queryset = User.objects.all() + serializer_class = CustomTokenObtainPairSerializer + + www_authenticate_realm = 'api' + + permission_classes = [AllowAny] + + def get_authenticate_header(self, request): + return '{0} realm="{1}"'.format( + AUTH_HEADER_TYPES[0], + self.www_authenticate_realm, + ) + + @list_route(['post']) + def login(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + + try: + serializer.is_valid(raise_exception=True) + except AuthenticationFailed as e: + return Response({'message': 'wrong username password'}, status=status.HTTP_401_UNAUTHORIZED) + except TokenError as e: + raise InvalidToken(e.args[0]) + + token = serializer.validated_data + + expires = token.current_time + token.lifetime + + tokenString = str(token) + headerPayload = '.'.join(tokenString.split('.')[0:2]) + signature = tokenString.split('.')[2] + + response = Response(token.payload, status=status.HTTP_200_OK) + + host = request.get_host().split(':')[0] + + if settings.DEBUG: + response.set_cookie('header.payload', value=headerPayload, expires=expires, domain=host) + response.set_cookie('signature', value=signature, httponly=True, domain=host) + else: + response.set_cookie('header.payload', value=headerPayload, expires=expires, secure=True, domain=host) + response.set_cookie('signature', value=signature, httponly=True, secure=True, domain=host) + return response + + @list_route() + def logout(self, request, *args, **kwargs): + response = Response({}, status=status.HTTP_200_OK) + if settings.DEBUG: + response.set_cookie('header.payload', value='', domain='127.0.0.1') + response.set_cookie('signature', value='', httponly=True, domain='127.0.0.1') + else: + response.set_cookie('header.payload', value='', secure=True, domain=self.domain) + response.set_cookie('signature', value='', httponly=True, secure=True, domain=self.domain) + return response From dac2e13f2013fe36b4daa57b41541d4d342d960a Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:57:10 +0200 Subject: [PATCH 391/457] flake8 --- backend/substrapp/tests/common.py | 4 ++-- backend/substrapp/tests/tests_tasks.py | 5 +++-- .../substrapp/tests/views/test_views_authentication.py | 1 - populate.py | 10 ++++++++++ substrabac/node/generate_nodes.py | 1 - substrabac/user/authentication.py | 3 +-- substrabac/user/views/user.py | 4 +--- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 999685ef4..cf6a2d219 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -3,7 +3,6 @@ import os import base64 -from django.conf import settings from django.contrib.auth.models import User from django.core.files.uploadedfile import InMemoryUploadedFile from django.db import transaction @@ -18,6 +17,7 @@ def generate_basic_auth_header(username, password): return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() + def generate_jwt_auth_header(jwt): return 'JWT ' + jwt @@ -32,7 +32,7 @@ def request(self, **kwargs): try: with transaction.atomic(): User.objects.create_user(username=username, password=password) - except: + except Exception: pass # simulate login serializer = CustomTokenObtainPairSerializer(data={ diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 42590b28e..77536772d 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -53,7 +53,8 @@ def setUp(self): @classmethod def setUpTestData(cls): cls.outgoing_node = OutgoingNode.objects.create(node_id="external_node_id", secret="s3cr37") - cls.outgoing_node_traintuple = OutgoingNode.objects.create(node_id=assets.traintuple[1]['creator'], secret="s3cr37") + cls.outgoing_node_traintuple = OutgoingNode.objects.create(node_id=assets.traintuple[1]['creator'], + secret="s3cr37") if assets.traintuple[1]['creator'] != assets.algo[0]['owner']: cls.outgoing_node_algo = OutgoingNode.objects.create(node_id=assets.algo[0]['owner'], secret="s3cr37") @@ -442,7 +443,7 @@ def test_get_algo(self): subtuple = { 'algo': { 'storageAddress': assets.algo[0]['content']['storageAddress'], - 'owner': assets.algo[0]['owner'], + 'owner': assets.algo[0]['owner'], 'hash': algo_hash } } diff --git a/backend/substrapp/tests/views/test_views_authentication.py b/backend/substrapp/tests/views/test_views_authentication.py index ad0ed0307..ae6d475fc 100644 --- a/backend/substrapp/tests/views/test_views_authentication.py +++ b/backend/substrapp/tests/views/test_views_authentication.py @@ -8,7 +8,6 @@ from substrapp.models import Algo from ..common import generate_basic_auth_header, get_sample_algo_metadata, get_sample_algo, get_description_algo -from django.conf import settings from django.test import override_settings MEDIA_ROOT = "/tmp/unittests_views/" diff --git a/populate.py b/populate.py index b38c84db8..701076822 100644 --- a/populate.py +++ b/populate.py @@ -97,6 +97,16 @@ def update_datamanager(data_manager_key, data, profile): print(colored(json.dumps(r, indent=2), 'green')) +def login(*args): + for org in args: + print(f'Login with {org}') + client.set_profile(org) + try: + client.login() + except Exception as e: + raise Exception(f'login failed: {str(e)}') + + def do_populate(): parser = argparse.ArgumentParser() diff --git a/substrabac/node/generate_nodes.py b/substrabac/node/generate_nodes.py index 0750d3ff3..7f59b71ff 100755 --- a/substrabac/node/generate_nodes.py +++ b/substrabac/node/generate_nodes.py @@ -62,4 +62,3 @@ def generate_for_orgs(orgs): orgs = ['owkinMSP', 'chu-nantesMSP', 'clbMSP'] # TODO should be discovered by discovery service generate_for_orgs(orgs) - diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py index 1ac8d8f2b..16f363d29 100644 --- a/substrabac/user/authentication.py +++ b/substrabac/user/authentication.py @@ -18,7 +18,7 @@ def authenticate(self, request): # reconstruct token from httpOnly cookie signature try: signature = request.COOKIES['signature'] - except: + except Exception: return None else: raw_token = raw_token + f".{signature}".encode() @@ -26,4 +26,3 @@ def authenticate(self, request): validated_token = self.get_validated_token(raw_token) return self.get_user(validated_token), None - diff --git a/substrabac/user/views/user.py b/substrabac/user/views/user.py index 273637d84..9cd8a4e2a 100644 --- a/substrabac/user/views/user.py +++ b/substrabac/user/views/user.py @@ -1,5 +1,3 @@ -import datetime - from django.conf import settings from django.contrib.auth.models import User @@ -34,7 +32,7 @@ def login(self, request, *args, **kwargs): try: serializer.is_valid(raise_exception=True) - except AuthenticationFailed as e: + except AuthenticationFailed: return Response({'message': 'wrong username password'}, status=status.HTTP_401_UNAUTHORIZED) except TokenError as e: raise InvalidToken(e.args[0]) From de69a902f19ea285b96b617c856fd2709b401067 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 25 Sep 2019 12:28:36 +0200 Subject: [PATCH 392/457] clean README --- README.md | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 479873d78..6ba711f7a 100644 --- a/README.md +++ b/README.md @@ -151,23 +151,16 @@ DJANGO_SETTINGS_MODULE=backend.settings.common celery -A backend beat -l info Go in the `backend` folder and run the server locally: :warning:

        Be very careful, --settings is different here, `server` is needed.

        - ``` - BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=backend.settings.server.dev - BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=backend.settings.server.dev - ``` - - If you want to bypass the basic authentication when you browse the server on localhost:8000 or localhost:8001, you can use the `nobasicauth` settings. - Simply replace `server.dev` by `nobasicauth`, like: - ``` - BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python manage.py runserver 8000 --settings=backend.settings.server.nobasicauth - BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python manage.py runserver 8001 --settings=backend.settings.server.nobasicauth - ``` - It allows the substra-frontend project to work correctly too. + +```shell +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 ./manage.py runserver 8000 --settings=backend.settings.server.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 ./manage.py runserver 8001 --settings=backend.settings.server.dev +``` ## Generate nodes authentication For working with node to node authentication, you need to generate and then load some fixtures -``` +```shell python ./backend/node/generate_nodes.py BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 ./manage.py init_nodes ./backend/node/nodes/owkinMSP.json --settings=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 ./manage.py init_nodes ./backend/node/nodes/chu-nantesMSP.json --settings=backend.settings.dev From ec339e86f1676eb04f1b6a43053b0231b3483927 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 25 Sep 2019 15:43:40 +0200 Subject: [PATCH 393/457] Rename user app to users, adapt to last cli --- README.md | 8 ++--- backend/backend/settings/common.py | 3 +- .../backend/settings/deps/restframework.py | 2 +- backend/backend/urls.py | 2 ++ backend/substrapp/tests/common.py | 2 +- backend/substrapp/views/utils.py | 2 +- populate.py | 12 +++---- substrabac/users/__init__.py | 0 substrabac/users/apps.py | 5 +++ substrabac/{user => users}/authentication.py | 0 .../users/management/commands/__init__.py | 0 .../users/management/commands/add_user.py | 21 ++++++++++++ substrabac/users/serializers/__init__.py | 5 +++ substrabac/users/serializers/user.py | 32 +++++++++++++++++++ substrabac/users/urls.py | 16 ++++++++++ substrabac/users/views/__init__.py | 5 +++ substrabac/{user => users}/views/user.py | 2 +- 17 files changed, 102 insertions(+), 15 deletions(-) create mode 100644 substrabac/users/__init__.py create mode 100644 substrabac/users/apps.py rename substrabac/{user => users}/authentication.py (100%) create mode 100644 substrabac/users/management/commands/__init__.py create mode 100644 substrabac/users/management/commands/add_user.py create mode 100644 substrabac/users/serializers/__init__.py create mode 100644 substrabac/users/serializers/user.py create mode 100644 substrabac/users/urls.py create mode 100644 substrabac/users/views/__init__.py rename substrabac/{user => users}/views/user.py (97%) diff --git a/README.md b/README.md index 6ba711f7a..23985ef6f 100644 --- a/README.md +++ b/README.md @@ -140,10 +140,10 @@ Execute this command in the `backend/backend` folder. Note the use of the development settings. ```shell -DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 celery -E -A backend worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler -DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 celery -E -A backend worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker -DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler -DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 BACKEND_PEER_PORT_EXTERNAL=7051 celery -E -A backend worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 BACKEND_PEER_PORT_EXTERNAL=7051 celery -E -A backend worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 BACKEND_PEER_PORT_EXTERNAL=9051 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 BACKEND_PEER_PORT_EXTERNAL=9051 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker DJANGO_SETTINGS_MODULE=backend.settings.common celery -A backend beat -l info ``` diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index 7ff0f4533..29eb60afc 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -59,7 +59,8 @@ 'rest_framework_swagger', 'rest_framework', 'substrapp', - 'node' + 'node', + 'users' ] AUTHENTICATION_BACKENDS = [ diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index d44975644..21ed3988e 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -6,7 +6,7 @@ 'rest_framework.renderers.BrowsableAPIRenderer', ), 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'user.authentication.SecureJWTAuthentication', # for front/sdk/cli + 'users.authentication.SecureJWTAuthentication', # for front/sdk/cli 'libs.sessionAuthentication.CustomSessionAuthentication', # for web browsable api ], 'DEFAULT_PERMISSION_CLASSES': [ diff --git a/backend/backend/urls.py b/backend/backend/urls.py index e9661c764..af361b5cb 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -22,6 +22,7 @@ from backend.views import schema_view from substrapp.urls import router from node.urls import router as nodeRouter +from users.urls import router as userRouter urlpatterns = [ @@ -30,6 +31,7 @@ url(r'^doc/', schema_view), url(r'^', include((router.urls, 'substrapp'))), url(r'^', include((nodeRouter.urls, 'node'))), + url(r'^', include((userRouter.urls, 'user'))), url(r'^api-auth/', include('rest_framework.urls')), ])), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index cf6a2d219..9ff22546e 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -11,7 +11,7 @@ # This function helper generate a basic authenticaiton header with given credentials # Given username and password it returns "Basic GENERATED_TOKEN" -from user.serializers import CustomTokenObtainPairSerializer +from users.serializers import CustomTokenObtainPairSerializer def generate_basic_auth_header(username, password): diff --git a/backend/substrapp/views/utils.py b/backend/substrapp/views/utils.py index a98a78534..7a1d96fed 100644 --- a/backend/substrapp/views/utils.py +++ b/backend/substrapp/views/utils.py @@ -17,7 +17,7 @@ from wsgiref.util import is_hop_by_hop -from user.authentication import SecureJWTAuthentication +from users.authentication import SecureJWTAuthentication def authenticate_outgoing_request(outgoing_node_id): diff --git a/populate.py b/populate.py index 701076822..2e7a4a09d 100644 --- a/populate.py +++ b/populate.py @@ -30,19 +30,19 @@ def setup_config(network='docker'): print('Init config for owkin and chunantes') if network == 'docker': client.add_profile('owkin', 'http://owkin.substra-backend:8000', '0.0', - user=USER, password=PASSWORD) + username=USER, password=PASSWORD) client.add_profile('chunantes', 'http://chunantes.substra-backend:8001', '0.0', - user=USER, password=PASSWORD) + username=USER, password=PASSWORD) client.add_profile('clb', 'http://clb.substra-backend:8002', '0.0', - user=USER, password=PASSWORD) + username=USER, password=PASSWORD) if network == 'skaffold': # the usernames and passwords are defined in the skaffold.yaml file client.add_profile('owkin', 'http://substra-backend.node-1', '0.0', - user='node-1', password='node-1pwd') + username='node-1', password='node-1pwd') client.add_profile('chunantes', 'http://substra-backend.node-2', '0.0', - user='node-2', password='node-2pwd') + username='node-2', password='node-2pwd') client.add_profile('clb', 'http://substra-backend.node-3', '0.0', - user='node-3', password='node-3pwd') + username='node-3', password='node-3pwd') def zip_folder(path, destination): diff --git a/substrabac/users/__init__.py b/substrabac/users/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/users/apps.py b/substrabac/users/apps.py new file mode 100644 index 000000000..4ce1fabc0 --- /dev/null +++ b/substrabac/users/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class UsersConfig(AppConfig): + name = 'users' diff --git a/substrabac/user/authentication.py b/substrabac/users/authentication.py similarity index 100% rename from substrabac/user/authentication.py rename to substrabac/users/authentication.py diff --git a/substrabac/users/management/commands/__init__.py b/substrabac/users/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/substrabac/users/management/commands/add_user.py b/substrabac/users/management/commands/add_user.py new file mode 100644 index 000000000..952681209 --- /dev/null +++ b/substrabac/users/management/commands/add_user.py @@ -0,0 +1,21 @@ +import secrets + +from django.contrib.auth.models import User +from django.core.management.base import BaseCommand +from django.db import IntegrityError + + +class Command(BaseCommand): + help = 'Add user' + + def add_arguments(self, parser): + parser.add_argument('username') + parser.add_argument('password', nargs='?', default=secrets.token_hex(8)) + + def handle(self, *args, **options): + try: + User.objects.create_user(username=options['username'], password=options['password']) + except IntegrityError as e: + self.stderr.write(f'User already exists: {str(e)}') + else: + self.stdout.write(f"password: {options['password']}") diff --git a/substrabac/users/serializers/__init__.py b/substrabac/users/serializers/__init__.py new file mode 100644 index 000000000..87ae7d6c1 --- /dev/null +++ b/substrabac/users/serializers/__init__.py @@ -0,0 +1,5 @@ +# encoding: utf-8 + +from .user import CustomTokenObtainPairSerializer + +__all__ = ['CustomTokenObtainPairSerializer'] diff --git a/substrabac/users/serializers/user.py b/substrabac/users/serializers/user.py new file mode 100644 index 000000000..b08c8476d --- /dev/null +++ b/substrabac/users/serializers/user.py @@ -0,0 +1,32 @@ +from rest_framework_simplejwt.serializers import TokenObtainSerializer +from rest_framework_simplejwt.settings import api_settings +from rest_framework_simplejwt.token_blacklist.models import OutstandingToken +from rest_framework_simplejwt.tokens import AccessToken +from rest_framework_simplejwt.utils import datetime_from_epoch + + +class CustomTokenObtainPairSerializer(TokenObtainSerializer): + def get_token(self, user): + """ + Adds this token to the outstanding token list. + """ + token = AccessToken.for_user(user) + + jti = token[api_settings.JTI_CLAIM] + exp = token['exp'] + + OutstandingToken.objects.create( + user=user, + jti=jti, + token=str(token), + created_at=token.current_time, + expires_at=datetime_from_epoch(exp), + ) + + return token + + def validate(self, attrs): + super().validate(attrs) + token = self.get_token(self.user) + + return token diff --git a/substrabac/users/urls.py b/substrabac/users/urls.py new file mode 100644 index 000000000..557c4ef17 --- /dev/null +++ b/substrabac/users/urls.py @@ -0,0 +1,16 @@ +""" +substrapp URL +""" + +from django.conf.urls import url, include +from rest_framework.routers import DefaultRouter + +# Create a router and register our viewsets with it. +from users.views import UserViewSet + +router = DefaultRouter() +router.register(r'user', UserViewSet, base_name='user') + +urlpatterns = [ + url(r'^', include(router.urls)), +] diff --git a/substrabac/users/views/__init__.py b/substrabac/users/views/__init__.py new file mode 100644 index 000000000..f114283ed --- /dev/null +++ b/substrabac/users/views/__init__.py @@ -0,0 +1,5 @@ +# encoding: utf-8 + +from .user import UserViewSet + +__all__ = ['UserViewSet'] diff --git a/substrabac/user/views/user.py b/substrabac/users/views/user.py similarity index 97% rename from substrabac/user/views/user.py rename to substrabac/users/views/user.py index 9cd8a4e2a..9ad24a01e 100644 --- a/substrabac/user/views/user.py +++ b/substrabac/users/views/user.py @@ -9,7 +9,7 @@ from rest_framework_simplejwt.authentication import AUTH_HEADER_TYPES from rest_framework_simplejwt.exceptions import TokenError, InvalidToken, AuthenticationFailed -from user.serializers import CustomTokenObtainPairSerializer +from users.serializers import CustomTokenObtainPairSerializer class UserViewSet(GenericViewSet): From 9b34ac255488e466dcc502d39c6abbe59b612643 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 25 Sep 2019 15:52:56 +0200 Subject: [PATCH 394/457] fix docker --- README.md | 2 +- docker/celerybeat/Dockerfile | 2 +- docker/celeryworker/Dockerfile | 3 ++- docker/flower/Dockerfile | 2 +- docker/substrabac/Dockerfile | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 23985ef6f..cae331c15 100644 --- a/README.md +++ b/README.md @@ -240,7 +240,7 @@ $> sh build-docker-images.sh Then, go to the`docker` dir and run `start.py`: ```bash -$> python3 start.py -d --no-backup +$> python start.py -d --no-backup ``` Check your services are correctly started with `docker ps -a`. diff --git a/docker/celerybeat/Dockerfile b/docker/celerybeat/Dockerfile index 218b913a0..6e5768419 100644 --- a/docker/celerybeat/Dockerfile +++ b/docker/celerybeat/Dockerfile @@ -15,4 +15,4 @@ COPY ./backend/libs /usr/src/app/libs COPY ./backend/substrapp /usr/src/app/substrapp COPY ./backend/backend /usr/src/app/backend COPY ./backend/node /usr/src/app/node -COPY ./backend/user /usr/src/app/user +COPY ./backend/users /usr/src/app/users diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index c81309db2..c31a69058 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -14,4 +14,5 @@ RUN pip3 install -r requirements.txt COPY ./backend/libs /usr/src/app/libs COPY ./backend/substrapp /usr/src/app/substrapp COPY ./backend/backend /usr/src/app/bac -COPY ./backend/user /usr/src/app/user +COPY ./backend/node /usr/src/app/node +COPY ./backend/users /usr/src/app/users diff --git a/docker/flower/Dockerfile b/docker/flower/Dockerfile index 43b082012..c4020b7af 100644 --- a/docker/flower/Dockerfile +++ b/docker/flower/Dockerfile @@ -16,4 +16,4 @@ COPY ./backend/libs /usr/src/app/libs COPY ./backend/substrapp /usr/src/app/substrapp COPY ./backend/backend /usr/src/app/backend COPY ./backend/node /usr/src/app/node -COPY ./backend/user /usr/src/app/user +COPY ./backend/users /usr/src/app/users diff --git a/docker/substrabac/Dockerfile b/docker/substrabac/Dockerfile index 6b3cd21a8..f7dca881b 100644 --- a/docker/substrabac/Dockerfile +++ b/docker/substrabac/Dockerfile @@ -18,4 +18,4 @@ COPY ./substrabac/events /usr/src/app/events COPY ./substrabac/substrabac /usr/src/app/substrabac COPY ./substrabac/node /usr/src/app/node COPY ./substrabac/node-register /usr/src/app/node-register -COPY ./substrabac/user /usr/src/app/user +COPY ./substrabac/users /usr/src/app/users From 05cdbd2fbacd8fb303f25eae6e7e5a12c9e1dbe4 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 25 Sep 2019 17:02:26 +0200 Subject: [PATCH 395/457] Fix README --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index cae331c15..995addb28 100644 --- a/README.md +++ b/README.md @@ -109,14 +109,14 @@ It will clean the `medias` folders and create the `owkin` and `chu-nantes` folde 8. Optional: Create a superuser in your databases: -``` -BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 python backend/manage.py createsuperuser --settings=backend.settings.dev -BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 python backend/manage.py createsuperuser --settings=backend.settings.dev +```shell +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 ./backend/manage.py createsuperuser --settings=backend.settings.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 ./backend/manage.py createsuperuser --settings=backend.settings.dev ``` 9. Build the substra-model docker image: Clone the following git repo https://github.com/SubstraFoundation/substra-tools and build the docker image -``` +```shell docker build -t substra-model . ``` @@ -140,10 +140,10 @@ Execute this command in the `backend/backend` folder. Note the use of the development settings. ```shell -DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 BACKEND_PEER_PORT_EXTERNAL=7051 celery -E -A backend worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler -DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 BACKEND_PEER_PORT_EXTERNAL=7051 celery -E -A backend worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker -DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 BACKEND_PEER_PORT_EXTERNAL=9051 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler -DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 BACKEND_PEER_PORT_EXTERNAL=9051 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 BACKEND_PEER_PORT_EXTERNAL=9051 celery -E -A backend worker -l info -B -n owkin -Q owkin,scheduler,celery --hostname owkin.scheduler +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 BACKEND_PEER_PORT_EXTERNAL=9051 celery -E -A backend worker -l info -B -n owkin -Q owkin,owkin.worker,celery --hostname owkin.worker +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 BACKEND_PEER_PORT_EXTERNAL=7051 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,scheduler,celery --hostname chu-nantes.scheduler +DJANGO_SETTINGS_MODULE=backend.settings.dev BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 BACKEND_PEER_PORT_EXTERNAL=7051 celery -E -A backend worker -l info -B -n chunantes -Q chu-nantes,chu-nantes.worker,celery --hostname chu-nantes.worker DJANGO_SETTINGS_MODULE=backend.settings.common celery -A backend beat -l info ``` @@ -153,8 +153,8 @@ Go in the `backend` folder and run the server locally: :warning:

        Be very careful, --settings is different here, `server` is needed.

        ```shell -BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 ./manage.py runserver 8000 --settings=backend.settings.server.dev -BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 ./manage.py runserver 8001 --settings=backend.settings.server.dev +BACKEND_ORG=owkin BACKEND_DEFAULT_PORT=8000 BACKEND_PEER_PORT_EXTERNAL=9051 ./manage.py runserver 8000 --settings=backend.settings.server.dev +BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 BACKEND_PEER_PORT_EXTERNAL=7051 ./manage.py runserver 8001 --settings=backend.settings.server.dev ``` ## Generate nodes authentication @@ -169,14 +169,14 @@ BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 ./manage.py init_nodes ./backen ## Create a default user For working with node to node authentication, you need load some extra fixtures -``` -BACKEND_ORG=owkin ./backend/manage.py add_user substra p@$swr0d44 --settings=backend.settings.dev -BACKEND_ORG=chu-nantes ./backend/manage.py add_user substra p@$swr0d44 --settings=backend.settings.dev +```shell +BACKEND_ORG=owkin ./backend/manage.py add_user substra 'p@$swr0d44' --settings=backend.settings.dev +BACKEND_ORG=chu-nantes ./backend/manage.py add_user substra 'p@$swr0d44' --settings=backend.settings.dev ``` ## Test with unit and functional tests -``` +```shell DJANGO_SETTINGS_MODULE=backend.settings.test coverage run manage.py test coverage report # For shell report coverage html # For HTML report From 61288efaa84245d65cc3dfc9a64876c5610cd2a6 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 14:52:29 +0200 Subject: [PATCH 396/457] rebase --- substrabac/substrapp/tests/assets.py | 608 +++++++++++++++++++++++++++ 1 file changed, 608 insertions(+) create mode 100644 substrabac/substrapp/tests/assets.py diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py new file mode 100644 index 000000000..b25e6675b --- /dev/null +++ b/substrabac/substrapp/tests/assets.py @@ -0,0 +1,608 @@ +""" +WARNING +======= + +DO NOT MANUALLY EDIT THIS FILE! + +It is generated using substrapp/tests/generate_assets.py + +In order to update this file: +1. start a clean instance of substra +2. run populate.py +3. run substrapp/tests/generate_assets.py +""" + +objective = [ + { + "key": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", + "name": "Skin Lesion Classification Objective", + "description": { + "hash": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", + "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/description/" + }, + "metrics": { + "name": "macro-average recall", + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" + }, + "owner": "owkinMSP", + "testDataset": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + }, + { + "key": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "name": "Skin Lesion Classification Objective", + "description": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/description/" + }, + "metrics": { + "name": "macro-average recall", + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + }, + "owner": "owkinMSP", + "testDataset": { + "dataManagerKey": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "dataSampleKeys": [ + "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf", + "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a" + ], + "worker": "" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + } +] + +datamanager = [ + { + "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "description": { + "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" + }, + "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "name": "ISIC 2018", + "opener": { + "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" + }, + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "type": "Images" + }, + { + "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "description": { + "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" + }, + "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "name": "Simplified ISIC 2018", + "opener": { + "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" + }, + "owner": "owkinMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "type": "Images" + } +] + +algo = [ + { + "key": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "name": "Neural Network", + "content": { + "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" + }, + "description": { + "hash": "b9463411a01ea00869bdffce6e59a5c100a4e635c0a9386266cad3c77eb28e9e", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/description/" + }, + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + }, + { + "key": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "name": "Random Forest", + "content": { + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" + }, + "description": { + "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" + }, + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + }, + { + "key": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "name": "Logistic regression", + "content": { + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "description": { + "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" + }, + "owner": "owkinMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + } +] + +traintuple = [ + { + "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", + "algo": { + "name": "Neural Network", + "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 0 + }, + "computePlanID": "", + "inModels": None, + "log": "[01-01-0165-a860d73]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "failed", + "tag": "My super tag" + }, + { + "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "", + "inModels": None, + "log": "", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c", + "storageAddress": "http://testserver/model/4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "done", + "tag": "substra" + }, + { + "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "inModels": None, + "log": "", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "a06d1286549331a028af0878d7417ab12859d4796050a9bebb6f9ff64e8856e4", + "storageAddress": "http://testserver/model/a06d1286549331a028af0878d7417ab12859d4796050a9bebb6f9ff64e8856e4/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "done", + "tag": "" + }, + { + "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", + "algo": { + "name": "Random Forest", + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 0 + }, + "computePlanID": "", + "inModels": None, + "log": "[01-01-0165-9cc4851]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "failed", + "tag": "" + } +] + +testtuple = [ + { + "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "certified": True, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "owkinMSP", + "keys": [ + "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", + "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" + ], + "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "perf": 0 + }, + "log": "", + "model": { + "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "hash": "4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c", + "storageAddress": "http://testserver/model/4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c/file/" + }, + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "status": "done", + "tag": "substra" + } +] + +model = [ + { + "traintuple": { + "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", + "algo": { + "name": "Neural Network", + "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 0 + }, + "computePlanID": "", + "inModels": None, + "log": "[01-01-0165-a860d73]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "failed", + "tag": "My super tag" + }, + "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "status": "", + "tag": "" + } + }, + { + "traintuple": { + "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "", + "inModels": None, + "log": "", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c", + "storageAddress": "http://testserver/model/4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "done", + "tag": "substra" + }, + "testtuple": { + "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "certified": True, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "owkinMSP", + "keys": [ + "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", + "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" + ], + "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "perf": 0 + }, + "log": "", + "model": { + "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "hash": "4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c", + "storageAddress": "http://testserver/model/4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c/file/" + }, + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "status": "done", + "tag": "substra" + } + }, + { + "traintuple": { + "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "inModels": None, + "log": "", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "a06d1286549331a028af0878d7417ab12859d4796050a9bebb6f9ff64e8856e4", + "storageAddress": "http://testserver/model/a06d1286549331a028af0878d7417ab12859d4796050a9bebb6f9ff64e8856e4/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "done", + "tag": "" + }, + "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "status": "", + "tag": "" + } + }, + { + "traintuple": { + "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", + "algo": { + "name": "Random Forest", + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 0 + }, + "computePlanID": "", + "inModels": None, + "log": "[01-01-0165-9cc4851]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "failed", + "tag": "" + }, + "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "status": "", + "tag": "" + } + } +] + From 136cd5beae5b826e8e7635e07c575f34592c5ba9 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:34:36 +0200 Subject: [PATCH 397/457] Fix tests - docker - add session authent --- backend/backend/settings/common.py | 3 --- backend/substrapp/tests/common.py | 1 - backend/substrapp/tests/tests_tasks.py | 2 +- backend/substrapp/views/utils.py | 1 - substrabac/user/authentication.py | 29 ++++++++++++++++++++++++++ 5 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 substrabac/user/authentication.py diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index 29eb60afc..297309a31 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -162,9 +162,6 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 -BASIC_AUTHENTICATION_MODULE = 'rest_framework.authentication' - - TRUE_VALUES = { 't', 'T', 'y', 'Y', 'yes', 'YES', diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 9ff22546e..67ab3e095 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -17,7 +17,6 @@ def generate_basic_auth_header(username, password): return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() - def generate_jwt_auth_header(jwt): return 'JWT ' + jwt diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 77536772d..1a0f639b1 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -443,7 +443,7 @@ def test_get_algo(self): subtuple = { 'algo': { 'storageAddress': assets.algo[0]['content']['storageAddress'], - 'owner': assets.algo[0]['owner'], + 'owner': assets.algo[0]['owner'], 'hash': algo_hash } } diff --git a/backend/substrapp/views/utils.py b/backend/substrapp/views/utils.py index 7a1d96fed..e4e4a8eaa 100644 --- a/backend/substrapp/views/utils.py +++ b/backend/substrapp/views/utils.py @@ -16,7 +16,6 @@ from requests.auth import HTTPBasicAuth from wsgiref.util import is_hop_by_hop - from users.authentication import SecureJWTAuthentication diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py new file mode 100644 index 000000000..1ac8d8f2b --- /dev/null +++ b/substrabac/user/authentication.py @@ -0,0 +1,29 @@ +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class SecureJWTAuthentication(JWTAuthentication): + + def authenticate(self, request): + if request.resolver_match.url_name in ('user-login', 'api-root'): + return None + + header = self.get_header(request) + if header is None: + return None + + raw_token = self.get_raw_token(header) + if raw_token is None: + return None + + # reconstruct token from httpOnly cookie signature + try: + signature = request.COOKIES['signature'] + except: + return None + else: + raw_token = raw_token + f".{signature}".encode() + + validated_token = self.get_validated_token(raw_token) + + return self.get_user(validated_token), None + From cb4e7ae137516d3042fb544e3b556b511f8565b7 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:57:10 +0200 Subject: [PATCH 398/457] flake8 --- backend/substrapp/tests/common.py | 1 + backend/substrapp/tests/tests_tasks.py | 2 +- substrabac/user/authentication.py | 3 +-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 67ab3e095..9ff22546e 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -17,6 +17,7 @@ def generate_basic_auth_header(username, password): return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() + def generate_jwt_auth_header(jwt): return 'JWT ' + jwt diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 1a0f639b1..77536772d 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -443,7 +443,7 @@ def test_get_algo(self): subtuple = { 'algo': { 'storageAddress': assets.algo[0]['content']['storageAddress'], - 'owner': assets.algo[0]['owner'], + 'owner': assets.algo[0]['owner'], 'hash': algo_hash } } diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py index 1ac8d8f2b..16f363d29 100644 --- a/substrabac/user/authentication.py +++ b/substrabac/user/authentication.py @@ -18,7 +18,7 @@ def authenticate(self, request): # reconstruct token from httpOnly cookie signature try: signature = request.COOKIES['signature'] - except: + except Exception: return None else: raw_token = raw_token + f".{signature}".encode() @@ -26,4 +26,3 @@ def authenticate(self, request): validated_token = self.get_validated_token(raw_token) return self.get_user(validated_token), None - From 69bfdbc1638fcd7290aa8cc02d944eba1c7a432b Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 26 Sep 2019 10:57:06 +0200 Subject: [PATCH 399/457] Support new cli with keyring --- populate.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/populate.py b/populate.py index 2e7a4a09d..6d523d493 100644 --- a/populate.py +++ b/populate.py @@ -29,20 +29,16 @@ def setup_config(network='docker'): print('Init config for owkin and chunantes') if network == 'docker': - client.add_profile('owkin', 'http://owkin.substra-backend:8000', '0.0', - username=USER, password=PASSWORD) - client.add_profile('chunantes', 'http://chunantes.substra-backend:8001', '0.0', - username=USER, password=PASSWORD) - client.add_profile('clb', 'http://clb.substra-backend:8002', '0.0', - username=USER, password=PASSWORD) + USER, PASSWORD = ('foo', 'barbar10') + # get first available user + client.add_profile('owkin', USER, PASSWORD, 'http://substra-backend.owkin.xyz:8000', '0.0') + client.add_profile('chunantes', USER, PASSWORD, 'http://substra-backend.chunantes.xyz:8001', '0.0') + client.add_profile('clb', USER, PASSWORD, 'http://substra-backend.clb.xyz:8002', '0.0') if network == 'skaffold': # the usernames and passwords are defined in the skaffold.yaml file - client.add_profile('owkin', 'http://substra-backend.node-1', '0.0', - username='node-1', password='node-1pwd') - client.add_profile('chunantes', 'http://substra-backend.node-2', '0.0', - username='node-2', password='node-2pwd') - client.add_profile('clb', 'http://substra-backend.node-3', '0.0', - username='node-3', password='node-3pwd') + client.add_profile('owkin', 'node-1', 'node-1pwd', 'http://substra-backend.node-1.com', '0.0') + client.add_profile('chunantes', 'node-2', 'node-2pwd', 'http://substra-backend.node-2.com', '0.0') + client.add_profile('clb', 'node-3', 'node-3pwd', 'http://substra-backend.node-3.com', '0.0') def zip_folder(path, destination): From 2a22b50bf7b65cd92b3463d31f81e74f0ccb91e1 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 16:30:22 +0200 Subject: [PATCH 400/457] Rebase --- backend/substrapp/tests/generate_assets.py | 2 +- substrabac/substrapp/tests/assets.py | 32 +++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/backend/substrapp/tests/generate_assets.py b/backend/substrapp/tests/generate_assets.py index 89b7340f1..71ac54146 100644 --- a/backend/substrapp/tests/generate_assets.py +++ b/backend/substrapp/tests/generate_assets.py @@ -10,7 +10,7 @@ def main(): client = substra.Client() - client.add_profile('owkin', 'substra', 'p@$swr0d44', 'http://owkin.substrabac:8000', '0.0') + client.add_profile('owkin', 'substra', 'p@$swr0d44', 'http://substra-backend.owkin.xyz:8000', '0.0') client.login() client.set_profile('owkin') diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index b25e6675b..0c2bf6331 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -189,7 +189,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-a860d73]", + "log": "[01-01-0165-2cfe33a]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -236,8 +236,8 @@ } }, "outModel": { - "hash": "4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c", - "storageAddress": "http://testserver/model/4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c/file/" + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" }, "permissions": { "process": { @@ -277,8 +277,8 @@ } }, "outModel": { - "hash": "a06d1286549331a028af0878d7417ab12859d4796050a9bebb6f9ff64e8856e4", - "storageAddress": "http://testserver/model/a06d1286549331a028af0878d7417ab12859d4796050a9bebb6f9ff64e8856e4/file/" + "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", + "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" }, "permissions": { "process": { @@ -309,7 +309,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-9cc4851]", + "log": "[01-01-0165-b887bcc]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -352,8 +352,8 @@ "log": "", "model": { "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c", - "storageAddress": "http://testserver/model/4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c/file/" + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -388,7 +388,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-a860d73]", + "log": "[01-01-0165-2cfe33a]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -449,8 +449,8 @@ } }, "outModel": { - "hash": "4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c", - "storageAddress": "http://testserver/model/4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c/file/" + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" }, "permissions": { "process": { @@ -483,8 +483,8 @@ "log": "", "model": { "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c", - "storageAddress": "http://testserver/model/4cbf8b8d2f55f1ded0914eeee6625faa7529b7f30bc7c716df0fa1bb969f608c/file/" + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -526,8 +526,8 @@ } }, "outModel": { - "hash": "a06d1286549331a028af0878d7417ab12859d4796050a9bebb6f9ff64e8856e4", - "storageAddress": "http://testserver/model/a06d1286549331a028af0878d7417ab12859d4796050a9bebb6f9ff64e8856e4/file/" + "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", + "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" }, "permissions": { "process": { @@ -572,7 +572,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-9cc4851]", + "log": "[01-01-0165-b887bcc]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { From 5bf7d1592089cd93d1abe4575c7b61be1b9d8e8e Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:34:36 +0200 Subject: [PATCH 401/457] Fix tests - docker - add session authent --- backend/substrapp/tests/common.py | 1 - backend/substrapp/tests/tests_tasks.py | 2 +- substrabac/substrapp/tests/assets.py | 608 ------------------------- substrabac/user/authentication.py | 3 +- 4 files changed, 3 insertions(+), 611 deletions(-) diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 9ff22546e..67ab3e095 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -17,7 +17,6 @@ def generate_basic_auth_header(username, password): return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() - def generate_jwt_auth_header(jwt): return 'JWT ' + jwt diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 77536772d..1a0f639b1 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -443,7 +443,7 @@ def test_get_algo(self): subtuple = { 'algo': { 'storageAddress': assets.algo[0]['content']['storageAddress'], - 'owner': assets.algo[0]['owner'], + 'owner': assets.algo[0]['owner'], 'hash': algo_hash } } diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index 0c2bf6331..e69de29bb 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -1,608 +0,0 @@ -""" -WARNING -======= - -DO NOT MANUALLY EDIT THIS FILE! - -It is generated using substrapp/tests/generate_assets.py - -In order to update this file: -1. start a clean instance of substra -2. run populate.py -3. run substrapp/tests/generate_assets.py -""" - -objective = [ - { - "key": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", - "name": "Skin Lesion Classification Objective", - "description": { - "hash": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", - "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/description/" - }, - "metrics": { - "name": "macro-average recall", - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" - }, - "owner": "owkinMSP", - "testDataset": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - }, - { - "key": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "name": "Skin Lesion Classification Objective", - "description": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/description/" - }, - "metrics": { - "name": "macro-average recall", - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - }, - "owner": "owkinMSP", - "testDataset": { - "dataManagerKey": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "dataSampleKeys": [ - "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf", - "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a" - ], - "worker": "" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - } -] - -datamanager = [ - { - "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "description": { - "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", - "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" - }, - "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "name": "ISIC 2018", - "opener": { - "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" - }, - "owner": "chu-nantesMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "type": "Images" - }, - { - "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "description": { - "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", - "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" - }, - "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "name": "Simplified ISIC 2018", - "opener": { - "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" - }, - "owner": "owkinMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "type": "Images" - } -] - -algo = [ - { - "key": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", - "name": "Neural Network", - "content": { - "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", - "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" - }, - "description": { - "hash": "b9463411a01ea00869bdffce6e59a5c100a4e635c0a9386266cad3c77eb28e9e", - "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/description/" - }, - "owner": "chu-nantesMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - }, - { - "key": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "name": "Random Forest", - "content": { - "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" - }, - "description": { - "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" - }, - "owner": "chu-nantesMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - }, - { - "key": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "name": "Logistic regression", - "content": { - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "description": { - "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" - }, - "owner": "owkinMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - } -] - -traintuple = [ - { - "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", - "algo": { - "name": "Neural Network", - "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", - "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 0 - }, - "computePlanID": "", - "inModels": None, - "log": "[01-01-0165-2cfe33a]", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "failed", - "tag": "My super tag" - }, - { - "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 1 - }, - "computePlanID": "", - "inModels": None, - "log": "", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": { - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "done", - "tag": "substra" - }, - { - "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 1 - }, - "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", - "inModels": None, - "log": "", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": { - "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", - "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "done", - "tag": "" - }, - { - "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", - "algo": { - "name": "Random Forest", - "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 0 - }, - "computePlanID": "", - "inModels": None, - "log": "[01-01-0165-b887bcc]", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "failed", - "tag": "" - } -] - -testtuple = [ - { - "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "certified": True, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "owkinMSP", - "keys": [ - "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", - "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" - ], - "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "perf": 0 - }, - "log": "", - "model": { - "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" - }, - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "status": "done", - "tag": "substra" - } -] - -model = [ - { - "traintuple": { - "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", - "algo": { - "name": "Neural Network", - "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", - "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 0 - }, - "computePlanID": "", - "inModels": None, - "log": "[01-01-0165-2cfe33a]", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "failed", - "tag": "My super tag" - }, - "testtuple": { - "key": "", - "algo": None, - "certified": False, - "creator": "", - "dataset": None, - "log": "", - "model": None, - "objective": None, - "status": "", - "tag": "" - } - }, - { - "traintuple": { - "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 1 - }, - "computePlanID": "", - "inModels": None, - "log": "", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": { - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "done", - "tag": "substra" - }, - "testtuple": { - "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "certified": True, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "owkinMSP", - "keys": [ - "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", - "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" - ], - "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "perf": 0 - }, - "log": "", - "model": { - "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" - }, - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "status": "done", - "tag": "substra" - } - }, - { - "traintuple": { - "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 1 - }, - "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", - "inModels": None, - "log": "", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": { - "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", - "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "done", - "tag": "" - }, - "testtuple": { - "key": "", - "algo": None, - "certified": False, - "creator": "", - "dataset": None, - "log": "", - "model": None, - "objective": None, - "status": "", - "tag": "" - } - }, - { - "traintuple": { - "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", - "algo": { - "name": "Random Forest", - "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 0 - }, - "computePlanID": "", - "inModels": None, - "log": "[01-01-0165-b887bcc]", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "failed", - "tag": "" - }, - "testtuple": { - "key": "", - "algo": None, - "certified": False, - "creator": "", - "dataset": None, - "log": "", - "model": None, - "objective": None, - "status": "", - "tag": "" - } - } -] - diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py index 16f363d29..1ac8d8f2b 100644 --- a/substrabac/user/authentication.py +++ b/substrabac/user/authentication.py @@ -18,7 +18,7 @@ def authenticate(self, request): # reconstruct token from httpOnly cookie signature try: signature = request.COOKIES['signature'] - except Exception: + except: return None else: raw_token = raw_token + f".{signature}".encode() @@ -26,3 +26,4 @@ def authenticate(self, request): validated_token = self.get_validated_token(raw_token) return self.get_user(validated_token), None + From f185b62b6eea636aaf791a67567428e3736ff7e5 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 25 Sep 2019 15:43:40 +0200 Subject: [PATCH 402/457] Rename user app to users, adapt to last cli --- substrabac/user/authentication.py | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 substrabac/user/authentication.py diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py deleted file mode 100644 index 1ac8d8f2b..000000000 --- a/substrabac/user/authentication.py +++ /dev/null @@ -1,29 +0,0 @@ -from rest_framework_simplejwt.authentication import JWTAuthentication - - -class SecureJWTAuthentication(JWTAuthentication): - - def authenticate(self, request): - if request.resolver_match.url_name in ('user-login', 'api-root'): - return None - - header = self.get_header(request) - if header is None: - return None - - raw_token = self.get_raw_token(header) - if raw_token is None: - return None - - # reconstruct token from httpOnly cookie signature - try: - signature = request.COOKIES['signature'] - except: - return None - else: - raw_token = raw_token + f".{signature}".encode() - - validated_token = self.get_validated_token(raw_token) - - return self.get_user(validated_token), None - From 06df79f68c603386f1450de26a28ac84bbee1925 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:34:36 +0200 Subject: [PATCH 403/457] Fix tests - docker - add session authent --- substrabac/user/authentication.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 substrabac/user/authentication.py diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py new file mode 100644 index 000000000..1ac8d8f2b --- /dev/null +++ b/substrabac/user/authentication.py @@ -0,0 +1,29 @@ +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class SecureJWTAuthentication(JWTAuthentication): + + def authenticate(self, request): + if request.resolver_match.url_name in ('user-login', 'api-root'): + return None + + header = self.get_header(request) + if header is None: + return None + + raw_token = self.get_raw_token(header) + if raw_token is None: + return None + + # reconstruct token from httpOnly cookie signature + try: + signature = request.COOKIES['signature'] + except: + return None + else: + raw_token = raw_token + f".{signature}".encode() + + validated_token = self.get_validated_token(raw_token) + + return self.get_user(validated_token), None + From 4ee2094e404474370b1671740117be140fc83902 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:57:10 +0200 Subject: [PATCH 404/457] flake8 --- backend/substrapp/tests/tests_tasks.py | 2 +- substrabac/user/authentication.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 1a0f639b1..77536772d 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -443,7 +443,7 @@ def test_get_algo(self): subtuple = { 'algo': { 'storageAddress': assets.algo[0]['content']['storageAddress'], - 'owner': assets.algo[0]['owner'], + 'owner': assets.algo[0]['owner'], 'hash': algo_hash } } diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py index 1ac8d8f2b..16f363d29 100644 --- a/substrabac/user/authentication.py +++ b/substrabac/user/authentication.py @@ -18,7 +18,7 @@ def authenticate(self, request): # reconstruct token from httpOnly cookie signature try: signature = request.COOKIES['signature'] - except: + except Exception: return None else: raw_token = raw_token + f".{signature}".encode() @@ -26,4 +26,3 @@ def authenticate(self, request): validated_token = self.get_validated_token(raw_token) return self.get_user(validated_token), None - From b370178d42a6334988c8096ec41658a3d9e7dcda Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 26 Sep 2019 12:06:32 +0200 Subject: [PATCH 405/457] Add Simple token Auth --- backend/backend/settings/common.py | 2 + .../backend/settings/deps/restframework.py | 1 + backend/backend/urls.py | 5 +- backend/substrapp/views/utils.py | 3 +- backend/users/__init__.py | 0 backend/users/apps.py | 5 ++ backend/users/authentication.py | 28 ++++++++ backend/users/management/commands/__init__.py | 0 backend/users/management/commands/add_user.py | 21 ++++++ backend/users/serializers/__init__.py | 5 ++ backend/users/serializers/user.py | 32 +++++++++ backend/users/urls.py | 16 +++++ backend/users/views/__init__.py | 5 ++ backend/users/views/user.py | 69 +++++++++++++++++++ 14 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 backend/users/__init__.py create mode 100644 backend/users/apps.py create mode 100644 backend/users/authentication.py create mode 100644 backend/users/management/commands/__init__.py create mode 100644 backend/users/management/commands/add_user.py create mode 100644 backend/users/serializers/__init__.py create mode 100644 backend/users/serializers/user.py create mode 100644 backend/users/urls.py create mode 100644 backend/users/views/__init__.py create mode 100644 backend/users/views/user.py diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index 297309a31..a020da62e 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -58,6 +58,8 @@ 'django_celery_results', 'rest_framework_swagger', 'rest_framework', + 'rest_framework.authtoken', + 'rest_framework_simplejwt.token_blacklist', 'substrapp', 'node', 'users' diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index 21ed3988e..acf6a5a05 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -7,6 +7,7 @@ ), 'DEFAULT_AUTHENTICATION_CLASSES': [ 'users.authentication.SecureJWTAuthentication', # for front/sdk/cli + 'rest_framework.authentication.TokenAuthentication', # for front/sdk/cli 'libs.sessionAuthentication.CustomSessionAuthentication', # for web browsable api ], 'DEFAULT_PERMISSION_CLASSES': [ diff --git a/backend/backend/urls.py b/backend/backend/urls.py index af361b5cb..f691ef4a2 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -20,6 +20,8 @@ from django.urls import include from backend.views import schema_view +from rest_framework.authtoken import views + from substrapp.urls import router from node.urls import router as nodeRouter from users.urls import router as userRouter @@ -32,7 +34,8 @@ url(r'^', include((router.urls, 'substrapp'))), url(r'^', include((nodeRouter.urls, 'node'))), url(r'^', include((userRouter.urls, 'user'))), - url(r'^api-auth/', include('rest_framework.urls')), + url(r'^api-auth/', include('rest_framework.urls')), # for session authent + url(r'^api-token-auth/', views.obtain_auth_token) # for token authent ])), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/backend/substrapp/views/utils.py b/backend/substrapp/views/utils.py index e4e4a8eaa..3b568d7fb 100644 --- a/backend/substrapp/views/utils.py +++ b/backend/substrapp/views/utils.py @@ -2,7 +2,7 @@ from django.http import FileResponse -from rest_framework.authentication import BasicAuthentication +from rest_framework.authentication import BasicAuthentication, TokenAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -58,6 +58,7 @@ class PermissionMixin(object): authentication_classes = [ BasicAuthentication, # for node to node SecureJWTAuthentication, # for user from front/sdk/cli + TokenAuthentication, # for user from front/sdk/cli CustomSessionAuthentication, # for user on drf web browsable api ] permission_classes = [IsAuthenticated] diff --git a/backend/users/__init__.py b/backend/users/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/users/apps.py b/backend/users/apps.py new file mode 100644 index 000000000..4ce1fabc0 --- /dev/null +++ b/backend/users/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class UsersConfig(AppConfig): + name = 'users' diff --git a/backend/users/authentication.py b/backend/users/authentication.py new file mode 100644 index 000000000..16f363d29 --- /dev/null +++ b/backend/users/authentication.py @@ -0,0 +1,28 @@ +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class SecureJWTAuthentication(JWTAuthentication): + + def authenticate(self, request): + if request.resolver_match.url_name in ('user-login', 'api-root'): + return None + + header = self.get_header(request) + if header is None: + return None + + raw_token = self.get_raw_token(header) + if raw_token is None: + return None + + # reconstruct token from httpOnly cookie signature + try: + signature = request.COOKIES['signature'] + except Exception: + return None + else: + raw_token = raw_token + f".{signature}".encode() + + validated_token = self.get_validated_token(raw_token) + + return self.get_user(validated_token), None diff --git a/backend/users/management/commands/__init__.py b/backend/users/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/users/management/commands/add_user.py b/backend/users/management/commands/add_user.py new file mode 100644 index 000000000..952681209 --- /dev/null +++ b/backend/users/management/commands/add_user.py @@ -0,0 +1,21 @@ +import secrets + +from django.contrib.auth.models import User +from django.core.management.base import BaseCommand +from django.db import IntegrityError + + +class Command(BaseCommand): + help = 'Add user' + + def add_arguments(self, parser): + parser.add_argument('username') + parser.add_argument('password', nargs='?', default=secrets.token_hex(8)) + + def handle(self, *args, **options): + try: + User.objects.create_user(username=options['username'], password=options['password']) + except IntegrityError as e: + self.stderr.write(f'User already exists: {str(e)}') + else: + self.stdout.write(f"password: {options['password']}") diff --git a/backend/users/serializers/__init__.py b/backend/users/serializers/__init__.py new file mode 100644 index 000000000..87ae7d6c1 --- /dev/null +++ b/backend/users/serializers/__init__.py @@ -0,0 +1,5 @@ +# encoding: utf-8 + +from .user import CustomTokenObtainPairSerializer + +__all__ = ['CustomTokenObtainPairSerializer'] diff --git a/backend/users/serializers/user.py b/backend/users/serializers/user.py new file mode 100644 index 000000000..b08c8476d --- /dev/null +++ b/backend/users/serializers/user.py @@ -0,0 +1,32 @@ +from rest_framework_simplejwt.serializers import TokenObtainSerializer +from rest_framework_simplejwt.settings import api_settings +from rest_framework_simplejwt.token_blacklist.models import OutstandingToken +from rest_framework_simplejwt.tokens import AccessToken +from rest_framework_simplejwt.utils import datetime_from_epoch + + +class CustomTokenObtainPairSerializer(TokenObtainSerializer): + def get_token(self, user): + """ + Adds this token to the outstanding token list. + """ + token = AccessToken.for_user(user) + + jti = token[api_settings.JTI_CLAIM] + exp = token['exp'] + + OutstandingToken.objects.create( + user=user, + jti=jti, + token=str(token), + created_at=token.current_time, + expires_at=datetime_from_epoch(exp), + ) + + return token + + def validate(self, attrs): + super().validate(attrs) + token = self.get_token(self.user) + + return token diff --git a/backend/users/urls.py b/backend/users/urls.py new file mode 100644 index 000000000..557c4ef17 --- /dev/null +++ b/backend/users/urls.py @@ -0,0 +1,16 @@ +""" +substrapp URL +""" + +from django.conf.urls import url, include +from rest_framework.routers import DefaultRouter + +# Create a router and register our viewsets with it. +from users.views import UserViewSet + +router = DefaultRouter() +router.register(r'user', UserViewSet, base_name='user') + +urlpatterns = [ + url(r'^', include(router.urls)), +] diff --git a/backend/users/views/__init__.py b/backend/users/views/__init__.py new file mode 100644 index 000000000..f114283ed --- /dev/null +++ b/backend/users/views/__init__.py @@ -0,0 +1,5 @@ +# encoding: utf-8 + +from .user import UserViewSet + +__all__ = ['UserViewSet'] diff --git a/backend/users/views/user.py b/backend/users/views/user.py new file mode 100644 index 000000000..9ad24a01e --- /dev/null +++ b/backend/users/views/user.py @@ -0,0 +1,69 @@ +from django.conf import settings +from django.contrib.auth.models import User + +from rest_framework import status +from rest_framework.permissions import AllowAny +from rest_framework.viewsets import GenericViewSet +from rest_framework.decorators import list_route +from rest_framework.response import Response +from rest_framework_simplejwt.authentication import AUTH_HEADER_TYPES +from rest_framework_simplejwt.exceptions import TokenError, InvalidToken, AuthenticationFailed + +from users.serializers import CustomTokenObtainPairSerializer + + +class UserViewSet(GenericViewSet): + queryset = User.objects.all() + serializer_class = CustomTokenObtainPairSerializer + + www_authenticate_realm = 'api' + + permission_classes = [AllowAny] + + def get_authenticate_header(self, request): + return '{0} realm="{1}"'.format( + AUTH_HEADER_TYPES[0], + self.www_authenticate_realm, + ) + + @list_route(['post']) + def login(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + + try: + serializer.is_valid(raise_exception=True) + except AuthenticationFailed: + return Response({'message': 'wrong username password'}, status=status.HTTP_401_UNAUTHORIZED) + except TokenError as e: + raise InvalidToken(e.args[0]) + + token = serializer.validated_data + + expires = token.current_time + token.lifetime + + tokenString = str(token) + headerPayload = '.'.join(tokenString.split('.')[0:2]) + signature = tokenString.split('.')[2] + + response = Response(token.payload, status=status.HTTP_200_OK) + + host = request.get_host().split(':')[0] + + if settings.DEBUG: + response.set_cookie('header.payload', value=headerPayload, expires=expires, domain=host) + response.set_cookie('signature', value=signature, httponly=True, domain=host) + else: + response.set_cookie('header.payload', value=headerPayload, expires=expires, secure=True, domain=host) + response.set_cookie('signature', value=signature, httponly=True, secure=True, domain=host) + return response + + @list_route() + def logout(self, request, *args, **kwargs): + response = Response({}, status=status.HTTP_200_OK) + if settings.DEBUG: + response.set_cookie('header.payload', value='', domain='127.0.0.1') + response.set_cookie('signature', value='', httponly=True, domain='127.0.0.1') + else: + response.set_cookie('header.payload', value='', secure=True, domain=self.domain) + response.set_cookie('signature', value='', httponly=True, secure=True, domain=self.domain) + return response From c41a546cf0a462a35e0111da3ece3a2e431ef6cb Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 17:28:41 +0200 Subject: [PATCH 406/457] rebase --- substrabac/substrapp/tests/assets.py | 608 +++++++++++++++++++++++++++ 1 file changed, 608 insertions(+) diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index e69de29bb..0c2bf6331 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -0,0 +1,608 @@ +""" +WARNING +======= + +DO NOT MANUALLY EDIT THIS FILE! + +It is generated using substrapp/tests/generate_assets.py + +In order to update this file: +1. start a clean instance of substra +2. run populate.py +3. run substrapp/tests/generate_assets.py +""" + +objective = [ + { + "key": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", + "name": "Skin Lesion Classification Objective", + "description": { + "hash": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", + "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/description/" + }, + "metrics": { + "name": "macro-average recall", + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" + }, + "owner": "owkinMSP", + "testDataset": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + }, + { + "key": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "name": "Skin Lesion Classification Objective", + "description": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/description/" + }, + "metrics": { + "name": "macro-average recall", + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + }, + "owner": "owkinMSP", + "testDataset": { + "dataManagerKey": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "dataSampleKeys": [ + "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf", + "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a" + ], + "worker": "" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + } +] + +datamanager = [ + { + "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "description": { + "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" + }, + "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "name": "ISIC 2018", + "opener": { + "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" + }, + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "type": "Images" + }, + { + "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "description": { + "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" + }, + "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "name": "Simplified ISIC 2018", + "opener": { + "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" + }, + "owner": "owkinMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "type": "Images" + } +] + +algo = [ + { + "key": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "name": "Neural Network", + "content": { + "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" + }, + "description": { + "hash": "b9463411a01ea00869bdffce6e59a5c100a4e635c0a9386266cad3c77eb28e9e", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/description/" + }, + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + }, + { + "key": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "name": "Random Forest", + "content": { + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" + }, + "description": { + "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" + }, + "owner": "chu-nantesMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + }, + { + "key": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "name": "Logistic regression", + "content": { + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "description": { + "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" + }, + "owner": "owkinMSP", + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + } + } +] + +traintuple = [ + { + "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", + "algo": { + "name": "Neural Network", + "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 0 + }, + "computePlanID": "", + "inModels": None, + "log": "[01-01-0165-2cfe33a]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "failed", + "tag": "My super tag" + }, + { + "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "", + "inModels": None, + "log": "", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "done", + "tag": "substra" + }, + { + "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "inModels": None, + "log": "", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", + "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "done", + "tag": "" + }, + { + "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", + "algo": { + "name": "Random Forest", + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 0 + }, + "computePlanID": "", + "inModels": None, + "log": "[01-01-0165-b887bcc]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "failed", + "tag": "" + } +] + +testtuple = [ + { + "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "certified": True, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "owkinMSP", + "keys": [ + "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", + "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" + ], + "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "perf": 0 + }, + "log": "", + "model": { + "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + }, + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "status": "done", + "tag": "substra" + } +] + +model = [ + { + "traintuple": { + "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", + "algo": { + "name": "Neural Network", + "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", + "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 0 + }, + "computePlanID": "", + "inModels": None, + "log": "[01-01-0165-2cfe33a]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "failed", + "tag": "My super tag" + }, + "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "status": "", + "tag": "" + } + }, + { + "traintuple": { + "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "", + "inModels": None, + "log": "", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "done", + "tag": "substra" + }, + "testtuple": { + "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "certified": True, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "owkinMSP", + "keys": [ + "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", + "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" + ], + "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", + "perf": 0 + }, + "log": "", + "model": { + "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + }, + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "status": "done", + "tag": "substra" + } + }, + { + "traintuple": { + "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "algo": { + "name": "Logistic regression", + "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", + "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 1 + }, + "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", + "inModels": None, + "log": "", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": { + "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", + "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" + }, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "done", + "tag": "" + }, + "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "status": "", + "tag": "" + } + }, + { + "traintuple": { + "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", + "algo": { + "name": "Random Forest", + "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", + "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" + }, + "creator": "chu-nantesMSP", + "dataset": { + "worker": "chu-nantesMSP", + "keys": [ + "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", + "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" + ], + "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", + "perf": 0 + }, + "computePlanID": "", + "inModels": None, + "log": "[01-01-0165-b887bcc]", + "objective": { + "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", + "metrics": { + "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", + "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" + } + }, + "outModel": None, + "permissions": { + "process": { + "public": True, + "authorizedIDs": [] + } + }, + "rank": 0, + "status": "failed", + "tag": "" + }, + "testtuple": { + "key": "", + "algo": None, + "certified": False, + "creator": "", + "dataset": None, + "log": "", + "model": None, + "objective": None, + "status": "", + "tag": "" + } + } +] + From c3b164e0c674282326b92e78d8af922344bb9db4 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 17:31:34 +0200 Subject: [PATCH 407/457] remove unused files --- substrabac/user/authentication.py | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 substrabac/user/authentication.py diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py deleted file mode 100644 index 16f363d29..000000000 --- a/substrabac/user/authentication.py +++ /dev/null @@ -1,28 +0,0 @@ -from rest_framework_simplejwt.authentication import JWTAuthentication - - -class SecureJWTAuthentication(JWTAuthentication): - - def authenticate(self, request): - if request.resolver_match.url_name in ('user-login', 'api-root'): - return None - - header = self.get_header(request) - if header is None: - return None - - raw_token = self.get_raw_token(header) - if raw_token is None: - return None - - # reconstruct token from httpOnly cookie signature - try: - signature = request.COOKIES['signature'] - except Exception: - return None - else: - raw_token = raw_token + f".{signature}".encode() - - validated_token = self.get_validated_token(raw_token) - - return self.get_user(validated_token), None From 1c23c890a57b33b20332a441f4462628b2e23ec6 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 30 Sep 2019 15:33:28 +0200 Subject: [PATCH 408/457] update assets --- substrabac/substrapp/tests/assets.py | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index 0c2bf6331..da015933e 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -189,7 +189,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-2cfe33a]", + "log": "[01-01-0165-e17cc59]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -236,8 +236,8 @@ } }, "outModel": { - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", + "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" }, "permissions": { "process": { @@ -277,8 +277,8 @@ } }, "outModel": { - "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", - "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" + "hash": "77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193", + "storageAddress": "http://testserver/model/77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193/file/" }, "permissions": { "process": { @@ -309,7 +309,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-b887bcc]", + "log": "[01-01-0165-32eaa7e]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -352,8 +352,8 @@ "log": "", "model": { "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", + "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -388,7 +388,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-2cfe33a]", + "log": "[01-01-0165-e17cc59]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -449,8 +449,8 @@ } }, "outModel": { - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", + "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" }, "permissions": { "process": { @@ -483,8 +483,8 @@ "log": "", "model": { "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", + "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -526,8 +526,8 @@ } }, "outModel": { - "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", - "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" + "hash": "77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193", + "storageAddress": "http://testserver/model/77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193/file/" }, "permissions": { "process": { @@ -572,7 +572,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-b887bcc]", + "log": "[01-01-0165-32eaa7e]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { From fdf50ca6ed4e0182bdbb33059740bbb1d653d3ea Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 30 Sep 2019 15:34:03 +0200 Subject: [PATCH 409/457] clean --- backend/substrapp/tests/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 67ab3e095..9ff22546e 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -17,6 +17,7 @@ def generate_basic_auth_header(username, password): return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() + def generate_jwt_auth_header(jwt): return 'JWT ' + jwt From e7e9c62f666b6cb8606efa94d146044c9f8fd370 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:34:36 +0200 Subject: [PATCH 410/457] Fix tests - docker - add session authent --- backend/substrapp/tests/common.py | 1 + backend/substrapp/tests/tests_tasks.py | 2 +- substrabac/user/authentication.py | 29 ++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 substrabac/user/authentication.py diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 9ff22546e..9954479e9 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -3,6 +3,7 @@ import os import base64 + from django.contrib.auth.models import User from django.core.files.uploadedfile import InMemoryUploadedFile from django.db import transaction diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 77536772d..1a0f639b1 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -443,7 +443,7 @@ def test_get_algo(self): subtuple = { 'algo': { 'storageAddress': assets.algo[0]['content']['storageAddress'], - 'owner': assets.algo[0]['owner'], + 'owner': assets.algo[0]['owner'], 'hash': algo_hash } } diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py new file mode 100644 index 000000000..1ac8d8f2b --- /dev/null +++ b/substrabac/user/authentication.py @@ -0,0 +1,29 @@ +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class SecureJWTAuthentication(JWTAuthentication): + + def authenticate(self, request): + if request.resolver_match.url_name in ('user-login', 'api-root'): + return None + + header = self.get_header(request) + if header is None: + return None + + raw_token = self.get_raw_token(header) + if raw_token is None: + return None + + # reconstruct token from httpOnly cookie signature + try: + signature = request.COOKIES['signature'] + except: + return None + else: + raw_token = raw_token + f".{signature}".encode() + + validated_token = self.get_validated_token(raw_token) + + return self.get_user(validated_token), None + From f55808c01685d4c87fec8253d94a8ffd8605f109 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 25 Sep 2019 15:43:40 +0200 Subject: [PATCH 411/457] Rename user app to users, adapt to last cli --- .../backend/settings/deps/restframework.py | 3 ++ substrabac/user/authentication.py | 29 ------------------- 2 files changed, 3 insertions(+), 29 deletions(-) delete mode 100644 substrabac/user/authentication.py diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index acf6a5a05..0fade3057 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -7,7 +7,10 @@ ), 'DEFAULT_AUTHENTICATION_CLASSES': [ 'users.authentication.SecureJWTAuthentication', # for front/sdk/cli +<<<<<<< HEAD 'rest_framework.authentication.TokenAuthentication', # for front/sdk/cli +======= +>>>>>>> Rename user app to users, adapt to last cli 'libs.sessionAuthentication.CustomSessionAuthentication', # for web browsable api ], 'DEFAULT_PERMISSION_CLASSES': [ diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py deleted file mode 100644 index 1ac8d8f2b..000000000 --- a/substrabac/user/authentication.py +++ /dev/null @@ -1,29 +0,0 @@ -from rest_framework_simplejwt.authentication import JWTAuthentication - - -class SecureJWTAuthentication(JWTAuthentication): - - def authenticate(self, request): - if request.resolver_match.url_name in ('user-login', 'api-root'): - return None - - header = self.get_header(request) - if header is None: - return None - - raw_token = self.get_raw_token(header) - if raw_token is None: - return None - - # reconstruct token from httpOnly cookie signature - try: - signature = request.COOKIES['signature'] - except: - return None - else: - raw_token = raw_token + f".{signature}".encode() - - validated_token = self.get_validated_token(raw_token) - - return self.get_user(validated_token), None - From 27b4179e7f956c01ca220a989423d132cb39a87b Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:34:36 +0200 Subject: [PATCH 412/457] Fix tests - docker - add session authent --- substrabac/user/authentication.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 substrabac/user/authentication.py diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py new file mode 100644 index 000000000..1ac8d8f2b --- /dev/null +++ b/substrabac/user/authentication.py @@ -0,0 +1,29 @@ +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class SecureJWTAuthentication(JWTAuthentication): + + def authenticate(self, request): + if request.resolver_match.url_name in ('user-login', 'api-root'): + return None + + header = self.get_header(request) + if header is None: + return None + + raw_token = self.get_raw_token(header) + if raw_token is None: + return None + + # reconstruct token from httpOnly cookie signature + try: + signature = request.COOKIES['signature'] + except: + return None + else: + raw_token = raw_token + f".{signature}".encode() + + validated_token = self.get_validated_token(raw_token) + + return self.get_user(validated_token), None + From 8cd1df544e99af6dd47fd15f8e0a6605c9301cb4 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 26 Sep 2019 12:06:32 +0200 Subject: [PATCH 413/457] Add Simple token Auth --- .../backend/settings/deps/restframework.py | 3 - users tutorial.md | 112 ++++++++++++++++++ 2 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 users tutorial.md diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index 0fade3057..acf6a5a05 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -7,10 +7,7 @@ ), 'DEFAULT_AUTHENTICATION_CLASSES': [ 'users.authentication.SecureJWTAuthentication', # for front/sdk/cli -<<<<<<< HEAD 'rest_framework.authentication.TokenAuthentication', # for front/sdk/cli -======= ->>>>>>> Rename user app to users, adapt to last cli 'libs.sessionAuthentication.CustomSessionAuthentication', # for web browsable api ], 'DEFAULT_PERMISSION_CLASSES': [ diff --git a/users tutorial.md b/users tutorial.md new file mode 100644 index 000000000..3009fccb2 --- /dev/null +++ b/users tutorial.md @@ -0,0 +1,112 @@ +# Users by org + + +## Need +We have the will to manage users by organization. + +Node to node authentication i.e worker to backend instances communication are not impacted and use the current Basic Auth implementation. + +We want to be able to register them from an administration point of view. + +Each user can login himself. + +## Authentications + +There are two main authentication available running in parallel: +- Secure JWT Authentication +- Session Authentication + +Each authentication process owns its login view which run against the same database and one and only user management. + + +#### Secure JWT Authentication +The first one `Secure JWT Authentication` is mainly used for web single one page application as our susbtrafront project. +We use a Secure JWT Authentication and not a simple JWT Authentication for being sure we are free of XSS and/or CORS attacks. +More reading here: +- https://medium.com/@jcbaey/authentication-in-spa-reactjs-and-vuejs-the-right-way-e4a9ac5cd9a3 +- https://medium.com/lightrail/getting-token-authentication-right-in-a-stateless-single-page-application-57d0c6474e3 +It can also be used by SDK and CLI projects such as our substra-sdk and substra-cli. + +#### Session Authentication +The second one `Session Authentication` is a classic for server rendered pages, useful for our web browsable API available via django rest framework api. +It can also be used by SDK and CLI projects but is a little bit more difficult to implement, as two requests need to be done for logging in correctly. + +## Testing + +Three projects are impacted by this change: +- substrabac +- substrafront +- substra-cli + +Each has a branch entitled `users`. + +Launch a `substra-network` network with two organizations (classic). + +### substra-cli + +1. Go to the `users` branch. + +That's all :) + +#### Test + +1. Install new version `pip install .` +2. Create configuration: +```bash +$> substra config --profile user -k -v 0.0 -u foo -p barbar10 http://owkin.substrabac:8000 +``` +3. Login +```bash +$> substra login --profile user +``` +4. Request +``` +$> substra list objective --profile user +KEY NAME METRICS +1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3 Skin Lesion Classification Objective macro-average recall +3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71 Skin Lesion Classification Objective macro-average recall +``` + +### substrabac + +1. Go to the `users` branch. +2. Install new substra-cli with `pip install -e ../substra-cli` +3. Generate nodes username/password: +```bash +$> python ./substrabac/node/generate_nodes.py +``` +4. Build docker images: +```bash +$> sh build-docker-images.sh +``` +5. Run images: +```bash +$> python start.py -d --no-backup +``` +6. Run populate.py + +For each backend it will create by default an user with username `foo` and password `barbar10`. +The `populate.py` script uses these credentials for logging in. + + +#### Test: + +1. Go to `http://owkin.substrabac:8000`, be sure to have the `mod_header` running for not having the version error message. +2. Click on the login link on the top right of the page. +3. Login +4. Enjoy + + +### susbtrafront + +1. Go to the `users` branch. +2. Rebuild the images and run them: +```bash +$> docker-compose up -d --force-recreate --build +``` + +#### Test: + +1. Go to `http://owkin.substrabac:3000`, be sure to have deactivated the `mod_header` version control. +2. Login +4. Enjoy From 96e99d6a73185c9efa238e9599509744d830e9b2 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 18 Sep 2019 17:34:36 +0200 Subject: [PATCH 414/457] Fix tests - docker - add session authent --- backend/node/generate_nodes.py | 65 +++++++++++++++++++ .../node/management/commands/init_nodes.py | 26 ++++++++ backend/substrapp/tests/common.py | 1 - substrabac/node/generate_nodes.py | 1 + 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100755 backend/node/generate_nodes.py create mode 100644 backend/node/management/commands/init_nodes.py diff --git a/backend/node/generate_nodes.py b/backend/node/generate_nodes.py new file mode 100755 index 000000000..0750d3ff3 --- /dev/null +++ b/backend/node/generate_nodes.py @@ -0,0 +1,65 @@ +import json +import os +import secrets + + +def generate_secret(): + return secrets.token_hex(64) + + +def generate(orgs): + files = {} + + # TODO merge two loops + # init file content + for org in orgs: + data = { + 'incoming_nodes': [], + 'outgoing_nodes': [], + } + files[org] = data + + for org in orgs: + # create intern node (request from worker A to substrabac A) + secret = generate_secret() + files[org]['outgoing_nodes'].append({ + 'node_id': org, + 'secret': secret + }) + files[org]['incoming_nodes'].append({ + 'node_id': org, + 'secret': secret + }) + + for other_org in filter(lambda x: x != org, orgs): + # outgoing from server B to server A share same secret as incoming from server B in server A + secret = generate_secret() + files[other_org]['outgoing_nodes'].append({ # in server B + 'node_id': org, # to server A + 'secret': secret + }) + + files[org]['incoming_nodes'].append({ # in server A + 'node_id': other_org, # from server B + 'secret': secret + }) + + return files + + +def generate_for_orgs(orgs): + files = generate(orgs) + dir_path = os.path.dirname(os.path.realpath(__file__)) + nodes_path = os.path.join(dir_path, 'nodes') + os.makedirs(nodes_path, exist_ok=True) + for k, v in files.items(): + filepath = os.path.join(nodes_path, f'{k}.json') + with open(filepath, 'w') as f: + f.write(json.dumps(v, indent=4)) + + +if __name__ == '__main__': + orgs = ['owkinMSP', 'chu-nantesMSP', 'clbMSP'] # TODO should be discovered by discovery service + + generate_for_orgs(orgs) + diff --git a/backend/node/management/commands/init_nodes.py b/backend/node/management/commands/init_nodes.py new file mode 100644 index 000000000..297679194 --- /dev/null +++ b/backend/node/management/commands/init_nodes.py @@ -0,0 +1,26 @@ +import json + +from django.core.management.base import BaseCommand +from node.models import IncomingNode, OutgoingNode + + +class Command(BaseCommand): + help = 'Load nodes from file' + + def add_arguments(self, parser): + parser.add_argument('file') + + def handle(self, *args, **options): + + filepath = options['file'] + + print(filepath) + with open(filepath) as json_file: + data = json.load(json_file) + + for node in data['incoming_nodes']: + IncomingNode.objects.create(node_id=node['node_id'], secret=node['secret']) + self.stdout.write(self.style.SUCCESS('created incoming node')) + for node in data['outgoing_nodes']: + OutgoingNode.objects.create(node_id=node['node_id'], secret=node['secret']) + self.stdout.write(self.style.SUCCESS('created outgoing node')) diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 9954479e9..7f5ef92e4 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -18,7 +18,6 @@ def generate_basic_auth_header(username, password): return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() - def generate_jwt_auth_header(jwt): return 'JWT ' + jwt diff --git a/substrabac/node/generate_nodes.py b/substrabac/node/generate_nodes.py index 7f59b71ff..0750d3ff3 100755 --- a/substrabac/node/generate_nodes.py +++ b/substrabac/node/generate_nodes.py @@ -62,3 +62,4 @@ def generate_for_orgs(orgs): orgs = ['owkinMSP', 'chu-nantesMSP', 'clbMSP'] # TODO should be discovered by discovery service generate_for_orgs(orgs) + From 3c2706095dbc37e07588c07bbd87b63971f34d93 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Thu, 26 Sep 2019 15:15:46 +0200 Subject: [PATCH 415/457] Implement ExpiryTokenAuthentication --- .../backend/settings/deps/restframework.py | 2 +- backend/backend/urls.py | 7 ++- backend/backend/views.py | 29 ++++++++++- backend/libs/expiryTokenAuthentication.py | 51 +++++++++++++++++++ backend/libs/sessionAuthentication.py | 19 +++++++ substrabac/libs/expiryTokenAuthentication.py | 51 +++++++++++++++++++ 6 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 backend/libs/expiryTokenAuthentication.py create mode 100644 backend/libs/sessionAuthentication.py create mode 100644 substrabac/libs/expiryTokenAuthentication.py diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index acf6a5a05..aa2d49f12 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -7,7 +7,7 @@ ), 'DEFAULT_AUTHENTICATION_CLASSES': [ 'users.authentication.SecureJWTAuthentication', # for front/sdk/cli - 'rest_framework.authentication.TokenAuthentication', # for front/sdk/cli + 'libs.expiryTokenAuthentication.ExpiryTokenAuthentication', # for front/sdk/cli 'libs.sessionAuthentication.CustomSessionAuthentication', # for web browsable api ], 'DEFAULT_PERMISSION_CLASSES': [ diff --git a/backend/backend/urls.py b/backend/backend/urls.py index f691ef4a2..fecb890f7 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -19,8 +19,7 @@ from django.conf.urls.static import static from django.urls import include -from backend.views import schema_view -from rest_framework.authtoken import views +from backend.views import schema_view, obtain_auth_token from substrapp.urls import router from node.urls import router as nodeRouter @@ -33,9 +32,9 @@ url(r'^doc/', schema_view), url(r'^', include((router.urls, 'substrapp'))), url(r'^', include((nodeRouter.urls, 'node'))), - url(r'^', include((userRouter.urls, 'user'))), + url(r'^', include((userRouter.urls, 'user'))), # for secure jwt authent url(r'^api-auth/', include('rest_framework.urls')), # for session authent - url(r'^api-token-auth/', views.obtain_auth_token) # for token authent + url(r'^api-token-auth/', obtain_auth_token) # for expiry token authent ])), ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) \ + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/backend/backend/views.py b/backend/backend/views.py index aac766106..58f42ca37 100644 --- a/backend/backend/views.py +++ b/backend/backend/views.py @@ -1,11 +1,18 @@ import yaml + +from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.decorators import api_view, renderer_classes from rest_framework import response, schemas from rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer +from rest_framework.compat import coreapi + +from rest_framework.authtoken.models import Token +from rest_framework.response import Response from django.conf.urls import url, include + +from libs.expiryTokenAuthentication import token_expire_handler, expires_in from substrapp.urls import router -from rest_framework.compat import coreapi from requests.compat import urlparse @@ -105,3 +112,23 @@ def schema_view(request): title='Substra Backend API', patterns=[url(r'^/', include([url(r'^', include(router.urls))]))]) return response.Response(generator.get_schema(request=request)) + + +class ExpiryObtainAuthToken(ObtainAuthToken): + + def post(self, request, *args, **kwargs): + serializer = self.serializer_class(data=request.data, + context={'request': request}) + serializer.is_valid(raise_exception=True) + user = serializer.validated_data['user'] + token, created = Token.objects.get_or_create(user=user) + + # token_expire_handler will check, if the token is expired it will generate new one + is_expired, token = token_expire_handler(token) + + return Response({ + 'token': token.key, + 'expires_in': expires_in(token) + }) + +obtain_auth_token = ExpiryObtainAuthToken.as_view() diff --git a/backend/libs/expiryTokenAuthentication.py b/backend/libs/expiryTokenAuthentication.py new file mode 100644 index 000000000..157124a9b --- /dev/null +++ b/backend/libs/expiryTokenAuthentication.py @@ -0,0 +1,51 @@ +from rest_framework.authentication import TokenAuthentication +from rest_framework.authtoken.models import Token +from rest_framework.exceptions import AuthenticationFailed + +from datetime import timedelta +from django.utils import timezone +from django.conf import settings + +# this return left time +def expires_in(token): + time_elapsed = timezone.now() - token.created + left_time = timedelta(seconds=getattr(settings, 'TOKEN_EXPIRED_AFTER_SECONDS', 5*60)) - time_elapsed + return left_time + + +# token checker if token expired or not +def is_token_expired(token): + return expires_in(token) < timedelta(seconds=0) + + +# if token is expired new token will be established +# If token is expired then it will be removed +# and new one with different key will be created +def token_expire_handler(token): + is_expired = is_token_expired(token) + if is_expired: + token.delete() + token = Token.objects.create(user=token.user) + return is_expired, token + + +class ExpiryTokenAuthentication(TokenAuthentication): + """ + If token is expired then it will be removed + and new one with different key will be created + """ + + def authenticate_credentials(self, key): + try: + token = Token.objects.get(key=key) + except Token.DoesNotExist: + raise AuthenticationFailed("Invalid Token") + + if not token.user.is_active: + raise AuthenticationFailed("User is not active") + + is_expired, token = token_expire_handler(token) + if is_expired: + raise AuthenticationFailed("The Token is expired") + + return (token.user, token) diff --git a/backend/libs/sessionAuthentication.py b/backend/libs/sessionAuthentication.py new file mode 100644 index 000000000..85f28544c --- /dev/null +++ b/backend/libs/sessionAuthentication.py @@ -0,0 +1,19 @@ +from rest_framework.authentication import SessionAuthentication + + +class CustomSessionAuthentication(SessionAuthentication): + """ + Use Django's session framework for authentication. + """ + + def authenticate(self, request): + """ + Returns a `User` if the request session currently has a logged in user. + Otherwise returns `None`. + """ + + # bypass for login with jwt + if request.resolver_match.url_name == 'user-login': + return None + + return super(CustomSessionAuthentication, self).authenticate(request) diff --git a/substrabac/libs/expiryTokenAuthentication.py b/substrabac/libs/expiryTokenAuthentication.py new file mode 100644 index 000000000..157124a9b --- /dev/null +++ b/substrabac/libs/expiryTokenAuthentication.py @@ -0,0 +1,51 @@ +from rest_framework.authentication import TokenAuthentication +from rest_framework.authtoken.models import Token +from rest_framework.exceptions import AuthenticationFailed + +from datetime import timedelta +from django.utils import timezone +from django.conf import settings + +# this return left time +def expires_in(token): + time_elapsed = timezone.now() - token.created + left_time = timedelta(seconds=getattr(settings, 'TOKEN_EXPIRED_AFTER_SECONDS', 5*60)) - time_elapsed + return left_time + + +# token checker if token expired or not +def is_token_expired(token): + return expires_in(token) < timedelta(seconds=0) + + +# if token is expired new token will be established +# If token is expired then it will be removed +# and new one with different key will be created +def token_expire_handler(token): + is_expired = is_token_expired(token) + if is_expired: + token.delete() + token = Token.objects.create(user=token.user) + return is_expired, token + + +class ExpiryTokenAuthentication(TokenAuthentication): + """ + If token is expired then it will be removed + and new one with different key will be created + """ + + def authenticate_credentials(self, key): + try: + token = Token.objects.get(key=key) + except Token.DoesNotExist: + raise AuthenticationFailed("Invalid Token") + + if not token.user.is_active: + raise AuthenticationFailed("User is not active") + + is_expired, token = token_expire_handler(token) + if is_expired: + raise AuthenticationFailed("The Token is expired") + + return (token.user, token) From 3a461afbe15aa9f26f3ad196ab053df447d6bd10 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 17:47:14 +0200 Subject: [PATCH 416/457] rebase --- substrabac/substrapp/tests/assets.py | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index da015933e..d5e75b9b0 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -189,7 +189,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-e17cc59]", + "log": "[01-01-0165-2cfe33a]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -236,8 +236,8 @@ } }, "outModel": { - "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", - "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" }, "permissions": { "process": { @@ -277,8 +277,8 @@ } }, "outModel": { - "hash": "77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193", - "storageAddress": "http://testserver/model/77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193/file/" + "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", + "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" }, "permissions": { "process": { @@ -352,8 +352,8 @@ "log": "", "model": { "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", - "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -388,7 +388,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-e17cc59]", + "log": "[01-01-0165-2cfe33a]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -449,8 +449,8 @@ } }, "outModel": { - "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", - "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" }, "permissions": { "process": { @@ -483,8 +483,8 @@ "log": "", "model": { "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", - "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" + "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", + "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -526,8 +526,8 @@ } }, "outModel": { - "hash": "77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193", - "storageAddress": "http://testserver/model/77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193/file/" + "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", + "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" }, "permissions": { "process": { @@ -572,7 +572,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-32eaa7e]", + "log": "[01-01-0165-b887bcc]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { From 6bd71493f748a2dec77cb7537b9bfee7bdb83bdd Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 27 Sep 2019 17:49:14 +0200 Subject: [PATCH 417/457] flake8 --- backend/backend/views.py | 1 + backend/libs/expiryTokenAuthentication.py | 3 ++- substrabac/libs/expiryTokenAuthentication.py | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/backend/views.py b/backend/backend/views.py index 58f42ca37..2f96774c8 100644 --- a/backend/backend/views.py +++ b/backend/backend/views.py @@ -131,4 +131,5 @@ def post(self, request, *args, **kwargs): 'expires_in': expires_in(token) }) + obtain_auth_token = ExpiryObtainAuthToken.as_view() diff --git a/backend/libs/expiryTokenAuthentication.py b/backend/libs/expiryTokenAuthentication.py index 157124a9b..713fbc5d6 100644 --- a/backend/libs/expiryTokenAuthentication.py +++ b/backend/libs/expiryTokenAuthentication.py @@ -6,10 +6,11 @@ from django.utils import timezone from django.conf import settings + # this return left time def expires_in(token): time_elapsed = timezone.now() - token.created - left_time = timedelta(seconds=getattr(settings, 'TOKEN_EXPIRED_AFTER_SECONDS', 5*60)) - time_elapsed + left_time = timedelta(seconds=getattr(settings, 'TOKEN_EXPIRED_AFTER_SECONDS', 5 * 60)) - time_elapsed return left_time diff --git a/substrabac/libs/expiryTokenAuthentication.py b/substrabac/libs/expiryTokenAuthentication.py index 157124a9b..713fbc5d6 100644 --- a/substrabac/libs/expiryTokenAuthentication.py +++ b/substrabac/libs/expiryTokenAuthentication.py @@ -6,10 +6,11 @@ from django.utils import timezone from django.conf import settings + # this return left time def expires_in(token): time_elapsed = timezone.now() - token.created - left_time = timedelta(seconds=getattr(settings, 'TOKEN_EXPIRED_AFTER_SECONDS', 5*60)) - time_elapsed + left_time = timedelta(seconds=getattr(settings, 'TOKEN_EXPIRED_AFTER_SECONDS', 5 * 60)) - time_elapsed return left_time From 8b604d27db027bfdf3db07b73da8d4b37c60f525 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 30 Sep 2019 15:28:27 +0200 Subject: [PATCH 418/457] rebase --- backend/substrapp/tests/common.py | 3 ++- backend/substrapp/tests/tests_tasks.py | 2 +- substrabac/node/generate_nodes.py | 1 - substrabac/user/authentication.py | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 7f5ef92e4..9c76d6203 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -10,7 +10,7 @@ from rest_framework.test import APIClient -# This function helper generate a basic authenticaiton header with given credentials +# This function helper generate a basic authentication header with given credentials # Given username and password it returns "Basic GENERATED_TOKEN" from users.serializers import CustomTokenObtainPairSerializer @@ -18,6 +18,7 @@ def generate_basic_auth_header(username, password): return 'Basic ' + base64.b64encode(f'{username}:{password}'.encode()).decode() + def generate_jwt_auth_header(jwt): return 'JWT ' + jwt diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 1a0f639b1..77536772d 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -443,7 +443,7 @@ def test_get_algo(self): subtuple = { 'algo': { 'storageAddress': assets.algo[0]['content']['storageAddress'], - 'owner': assets.algo[0]['owner'], + 'owner': assets.algo[0]['owner'], 'hash': algo_hash } } diff --git a/substrabac/node/generate_nodes.py b/substrabac/node/generate_nodes.py index 0750d3ff3..7f59b71ff 100755 --- a/substrabac/node/generate_nodes.py +++ b/substrabac/node/generate_nodes.py @@ -62,4 +62,3 @@ def generate_for_orgs(orgs): orgs = ['owkinMSP', 'chu-nantesMSP', 'clbMSP'] # TODO should be discovered by discovery service generate_for_orgs(orgs) - diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py index 1ac8d8f2b..16f363d29 100644 --- a/substrabac/user/authentication.py +++ b/substrabac/user/authentication.py @@ -18,7 +18,7 @@ def authenticate(self, request): # reconstruct token from httpOnly cookie signature try: signature = request.COOKIES['signature'] - except: + except Exception: return None else: raw_token = raw_token + f".{signature}".encode() @@ -26,4 +26,3 @@ def authenticate(self, request): validated_token = self.get_validated_token(raw_token) return self.get_user(validated_token), None - From 52e7ceba6b5b7341903ed033f77a8e53e4e954fb Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 30 Sep 2019 15:32:24 +0200 Subject: [PATCH 419/457] clean --- substrabac/substrapp/tests/assets.py | 30 ++++++++++++++-------------- substrabac/user/authentication.py | 28 -------------------------- 2 files changed, 15 insertions(+), 43 deletions(-) delete mode 100644 substrabac/user/authentication.py diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py index d5e75b9b0..da015933e 100644 --- a/substrabac/substrapp/tests/assets.py +++ b/substrabac/substrapp/tests/assets.py @@ -189,7 +189,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-2cfe33a]", + "log": "[01-01-0165-e17cc59]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -236,8 +236,8 @@ } }, "outModel": { - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", + "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" }, "permissions": { "process": { @@ -277,8 +277,8 @@ } }, "outModel": { - "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", - "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" + "hash": "77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193", + "storageAddress": "http://testserver/model/77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193/file/" }, "permissions": { "process": { @@ -352,8 +352,8 @@ "log": "", "model": { "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", + "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -388,7 +388,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-2cfe33a]", + "log": "[01-01-0165-e17cc59]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { @@ -449,8 +449,8 @@ } }, "outModel": { - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", + "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" }, "permissions": { "process": { @@ -483,8 +483,8 @@ "log": "", "model": { "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0", - "storageAddress": "http://testserver/model/21fdf97348b49c55754dfb339b2dbae710dfc0373781c34d6d54dbae553391d0/file/" + "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", + "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" }, "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", @@ -526,8 +526,8 @@ } }, "outModel": { - "hash": "fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0", - "storageAddress": "http://testserver/model/fd1ae479a232c930f453a5b5d4f402b17ece18e15f95ede70f0a51b6b95009e0/file/" + "hash": "77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193", + "storageAddress": "http://testserver/model/77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193/file/" }, "permissions": { "process": { @@ -572,7 +572,7 @@ }, "computePlanID": "", "inModels": None, - "log": "[01-01-0165-b887bcc]", + "log": "[01-01-0165-32eaa7e]", "objective": { "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", "metrics": { diff --git a/substrabac/user/authentication.py b/substrabac/user/authentication.py deleted file mode 100644 index 16f363d29..000000000 --- a/substrabac/user/authentication.py +++ /dev/null @@ -1,28 +0,0 @@ -from rest_framework_simplejwt.authentication import JWTAuthentication - - -class SecureJWTAuthentication(JWTAuthentication): - - def authenticate(self, request): - if request.resolver_match.url_name in ('user-login', 'api-root'): - return None - - header = self.get_header(request) - if header is None: - return None - - raw_token = self.get_raw_token(header) - if raw_token is None: - return None - - # reconstruct token from httpOnly cookie signature - try: - signature = request.COOKIES['signature'] - except Exception: - return None - else: - raw_token = raw_token + f".{signature}".encode() - - validated_token = self.get_validated_token(raw_token) - - return self.get_user(validated_token), None From 702867c410173cd6909b085cc91ee3d01ecb7444 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 1 Oct 2019 10:14:07 +0200 Subject: [PATCH 420/457] Update charts to be compatible with k8s --- backend/backend/settings/common.py | 1 + backend/libs/HealthCheckMiddleware.py | 27 ++++ .../templates/deployment-backend.yaml | 23 +-- .../templates/deployment-scheduler.yaml | 11 -- .../templates/deployment-worker.yaml | 11 -- .../templates/job-add-users.yaml | 143 ++++++++++++++++++ charts/substra-backend/values.yaml | 4 + .../substrabac/templates/job-add-users.yaml | 143 ++++++++++++++++++ substrabac/libs/HealthCheckMiddleware.py | 27 ++++ 9 files changed, 347 insertions(+), 43 deletions(-) create mode 100644 backend/libs/HealthCheckMiddleware.py create mode 100644 charts/substra-backend/templates/job-add-users.yaml create mode 100644 charts/substrabac/templates/job-add-users.yaml create mode 100644 substrabac/libs/HealthCheckMiddleware.py diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index a020da62e..3e8b17490 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -81,6 +81,7 @@ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'libs.SQLPrintingMiddleware.SQLPrintingMiddleware', + 'libs.HealthCheckMiddleware.HealthCheckMiddleware', ] ROOT_URLCONF = 'backend.urls' diff --git a/backend/libs/HealthCheckMiddleware.py b/backend/libs/HealthCheckMiddleware.py new file mode 100644 index 000000000..cee4271bb --- /dev/null +++ b/backend/libs/HealthCheckMiddleware.py @@ -0,0 +1,27 @@ +from django.http import HttpResponse + + +class HealthCheckMiddleware(object): + def __init__(self, get_response): + self.get_response = get_response + # One-time configuration and initialization. + + def __call__(self, request): + if request.method == "GET": + if request.path == "/readiness": + return self.readiness(request) + elif request.path == "/liveness": + return self.liveness(request) + return self.get_response(request) + + def liveness(self, request): + """ + Returns that the server is alive. + """ + return HttpResponse("OK") + + def readiness(self, request): + """ + Returns that the server is alive. + """ + return HttpResponse("OK") diff --git a/charts/substra-backend/templates/deployment-backend.yaml b/charts/substra-backend/templates/deployment-backend.yaml index 5be64f8b5..eef09920d 100644 --- a/charts/substra-backend/templates/deployment-backend.yaml +++ b/charts/substra-backend/templates/deployment-backend.yaml @@ -66,17 +66,6 @@ spec: value: "{{ .Values.backend.defaultDomain }}" - name: CELERY_BROKER_URL value: "amqp://{{ .Values.rabbitmq.rabbitmq.username }}:{{ .Values.rabbitmq.rabbitmq.password }}@{{ .Release.Name }}-{{ .Values.rabbitmq.host }}:{{ .Values.rabbitmq.port }}//" - {{- with .Values.backend.auth }} - - name: BACK_AUTH_USER - value: {{ .user | quote }} - - name: BACK_AUTH_PASSWORD - value: {{ .password | quote }} - {{- else }} - - name: BACK_AUTH_USER - value: "" - - name: BACK_AUTH_PASSWORD - value: "" - {{- end }} - name: BACKEND_DEFAULT_PORT value: {{ .Values.backend.service.port | quote}} - name: BACKEND_PEER_PORT @@ -128,29 +117,21 @@ spec: name: admin-cert livenessProbe: httpGet: - path: / + path: /liveness port: http httpHeaders: - name: Accept value: "text/html;version=0.0, */*;version=0.0" - {{- with .Values.backend.auth }} - - name: Authorization - value: {{ .header | quote }} - {{- end }} initialDelaySeconds: 60 timeoutSeconds: 5 failureThreshold: 6 readinessProbe: httpGet: - path: / + path: /readiness port: http httpHeaders: - name: Accept value: "text/html;version=0.0, */*;version=0.0" - {{- with .Values.backend.auth }} - - name: Authorization - value: {{ .header | quote }} - {{- end }} initialDelaySeconds: 10 timeoutSeconds: 2 periodSeconds: 5 diff --git a/charts/substra-backend/templates/deployment-scheduler.yaml b/charts/substra-backend/templates/deployment-scheduler.yaml index 54e5c3128..bb521a160 100644 --- a/charts/substra-backend/templates/deployment-scheduler.yaml +++ b/charts/substra-backend/templates/deployment-scheduler.yaml @@ -50,17 +50,6 @@ spec: value: backend.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" - {{- with .Values.backend.auth }} - - name: BACK_AUTH_USER - value: {{ .user | quote }} - - name: BACK_AUTH_PASSWORD - value: {{ .password | quote }} - {{- else }} - - name: BACK_AUTH_USER - value: "" - - name: BACK_AUTH_PASSWORD - value: "" - {{- end }} - name: DATABASE_HOST value: {{ .Release.Name }}-postgresql - name: FABRIC_CFG_PATH_ENV diff --git a/charts/substra-backend/templates/deployment-worker.yaml b/charts/substra-backend/templates/deployment-worker.yaml index 62dddda88..3a920dded 100644 --- a/charts/substra-backend/templates/deployment-worker.yaml +++ b/charts/substra-backend/templates/deployment-worker.yaml @@ -50,17 +50,6 @@ spec: value: backend.settings.{{ .Values.backend.settings }} - name: PYTHONUNBUFFERED value: "1" - {{- with .Values.backend.auth }} - - name: BACK_AUTH_USER - value: {{ .user | quote }} - - name: BACK_AUTH_PASSWORD - value: {{ .password | quote }} - {{- else }} - - name: BACK_AUTH_USER - value: "" - - name: BACK_AUTH_PASSWORD - value: "" - {{- end }} - name: DEFAULT_DOMAIN value: "{{ .Values.backend.defaultDomain }}" - name: BACKEND_{{ .Values.organization.name | upper }}_DB_NAME diff --git a/charts/substra-backend/templates/job-add-users.yaml b/charts/substra-backend/templates/job-add-users.yaml new file mode 100644 index 000000000..ca8feef71 --- /dev/null +++ b/charts/substra-backend/templates/job-add-users.yaml @@ -0,0 +1,143 @@ +{{- range $index, $value := .Values.users }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "substra.fullname" $ }}-add-users-{{ $index }} + labels: + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" $ }}-add-users-{{ $index }} + app.kubernetes.io/part-of: {{ template "substra.name" $ }} +spec: + template: + spec: + restartPolicy: OnFailure + {{- with $.Values.backend.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - name: substrabac + image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" + imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" + command: ["python3"] + args: ["manage.py", "add_user", {{ .name }}, {{ .secret }}] + env: + - name: ORG + value: {{ $.Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ $.Values.organization.name }} + - name: SUBSTRABAC_{{ $.Values.organization.name | upper }}_DB_NAME + value: {{ $.Values.postgresql.postgresqlDatabase }} + - name: SUBSTRABAC_DB_USER + value: {{ $.Values.postgresql.postgresqlUsername }} + - name: SUBSTRABAC_DB_PWD + value: {{ $.Values.postgresql.postgresqlPassword }} + - name: DATABASE_HOST + value: {{ $.Release.Name }}-postgresql + - name: DJANGO_SETTINGS_MODULE + value: substrabac.settings.{{ $.Values.backend.settings }} + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric_cfg + - name: CORE_PEER_ADDRESS_ENV + value: "{{ $.Values.peer.host }}:{{ $.Values.peer.port }}" + - name: FABRIC_LOGGING_SPEC + value: debug + - name: DEFAULT_DOMAIN + value: "{{ $.Values.backend.defaultDomain }}" + - name: CELERY_BROKER_URL + value: "amqp://{{ $.Values.rabbitmq.rabbitmq.username }}:{{ $.Values.rabbitmq.rabbitmq.password }}@{{ $.Release.Name }}-{{ $.Values.rabbitmq.host }}:{{ $.Values.rabbitmq.port }}//" + - name: BACK_AUTH_USER + value: {{ $.user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ $.password | quote }} + - name: SUBSTRABAC_DEFAULT_PORT + value: {{ $.Values.backend.service.port | quote}} + - name: SUBSTRABAC_PEER_PORT + value: "internal" + - name: LEDGER_CONFIG_FILE + value: /conf/{{ $.Values.organization.name }}/substrabac/conf.json + - name: PYTHONUNBUFFERED + value: "1" + - name: MEDIA_ROOT + value: {{ $.Values.persistence.hostPath }}/medias/ + volumeMounts: + - mountPath: {{ $.Values.persistence.hostPath }} + name: data + - mountPath: /conf/{{ $.Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/fabric_cfg + name: fabric + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" $ }} + - name: config + configMap: + name: {{ include "substra.fullname" $ }}-backend + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ $.Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ $.Values.secrets.key }} + - name: cacert + secret: + secretName: {{ $.Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ $.Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ $.Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ $.Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ $.Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ $.Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} +{{- end }} diff --git a/charts/substra-backend/values.yaml b/charts/substra-backend/values.yaml index 61c70353f..421b1ce71 100644 --- a/charts/substra-backend/values.yaml +++ b/charts/substra-backend/values.yaml @@ -75,6 +75,10 @@ incomingNodes: [] # - name: nodeId # secret: nodeSecret +users: [] + # - name: username + # secret: userSecret + persistence: hostPath: "/substra" size: "10Gi" diff --git a/charts/substrabac/templates/job-add-users.yaml b/charts/substrabac/templates/job-add-users.yaml new file mode 100644 index 000000000..ca8feef71 --- /dev/null +++ b/charts/substrabac/templates/job-add-users.yaml @@ -0,0 +1,143 @@ +{{- range $index, $value := .Values.users }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "substra.fullname" $ }}-add-users-{{ $index }} + labels: + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} + app.kubernetes.io/name: {{ template "substra.name" $ }}-add-users-{{ $index }} + app.kubernetes.io/part-of: {{ template "substra.name" $ }} +spec: + template: + spec: + restartPolicy: OnFailure + {{- with $.Values.backend.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ . }} + {{- end }} + {{- end }} + containers: + - name: substrabac + image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" + imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" + command: ["python3"] + args: ["manage.py", "add_user", {{ .name }}, {{ .secret }}] + env: + - name: ORG + value: {{ $.Values.organization.name }} + - name: SUBSTRABAC_ORG + value: {{ $.Values.organization.name }} + - name: SUBSTRABAC_{{ $.Values.organization.name | upper }}_DB_NAME + value: {{ $.Values.postgresql.postgresqlDatabase }} + - name: SUBSTRABAC_DB_USER + value: {{ $.Values.postgresql.postgresqlUsername }} + - name: SUBSTRABAC_DB_PWD + value: {{ $.Values.postgresql.postgresqlPassword }} + - name: DATABASE_HOST + value: {{ $.Release.Name }}-postgresql + - name: DJANGO_SETTINGS_MODULE + value: substrabac.settings.{{ $.Values.backend.settings }} + - name: FABRIC_CFG_PATH + value: /var/hyperledger/fabric_cfg + - name: CORE_PEER_ADDRESS_ENV + value: "{{ $.Values.peer.host }}:{{ $.Values.peer.port }}" + - name: FABRIC_LOGGING_SPEC + value: debug + - name: DEFAULT_DOMAIN + value: "{{ $.Values.backend.defaultDomain }}" + - name: CELERY_BROKER_URL + value: "amqp://{{ $.Values.rabbitmq.rabbitmq.username }}:{{ $.Values.rabbitmq.rabbitmq.password }}@{{ $.Release.Name }}-{{ $.Values.rabbitmq.host }}:{{ $.Values.rabbitmq.port }}//" + - name: BACK_AUTH_USER + value: {{ $.user | quote }} + - name: BACK_AUTH_PASSWORD + value: {{ $.password | quote }} + - name: SUBSTRABAC_DEFAULT_PORT + value: {{ $.Values.backend.service.port | quote}} + - name: SUBSTRABAC_PEER_PORT + value: "internal" + - name: LEDGER_CONFIG_FILE + value: /conf/{{ $.Values.organization.name }}/substrabac/conf.json + - name: PYTHONUNBUFFERED + value: "1" + - name: MEDIA_ROOT + value: {{ $.Values.persistence.hostPath }}/medias/ + volumeMounts: + - mountPath: {{ $.Values.persistence.hostPath }} + name: data + - mountPath: /conf/{{ $.Values.organization.name }}/substrabac + name: config + readOnly: true + - mountPath: /var/hyperledger/fabric_cfg + name: fabric + readOnly: true + - mountPath: /var/hyperledger/msp/signcerts + name: id-cert + - mountPath: /var/hyperledger/msp/keystore + name: id-key + - mountPath: /var/hyperledger/msp/cacerts + name: cacert + - mountPath: /var/hyperledger/msp/admincerts + name: admin-cert + - mountPath: /var/hyperledger/tls/server/pair + name: tls + - mountPath: /var/hyperledger/tls/server/cert + name: tls-rootcert + - mountPath: /var/hyperledger/tls/client/pair + name: tls-client + - mountPath: /var/hyperledger/tls/client/cert + name: tls-clientrootcert + - mountPath: /var/hyperledger/tls/ord/cert + name: ord-tls-rootcert + - mountPath: /var/hyperledger/admin_msp/signcerts + name: admin-cert + - mountPath: /var/hyperledger/admin_msp/keystore + name: admin-key + - mountPath: /var/hyperledger/admin_msp/cacerts + name: cacert + - mountPath: /var/hyperledger/admin_msp/admincerts + name: admin-cert + volumes: + - name: data + persistentVolumeClaim: + claimName: {{ include "substra.fullname" $ }} + - name: config + configMap: + name: {{ include "substra.fullname" $ }}-backend + - name: fabric + configMap: + name: {{ $.Values.secrets.fabricConfigmap }} + - name: id-cert + secret: + secretName: {{ $.Values.secrets.cert }} + - name: id-key + secret: + secretName: {{ $.Values.secrets.key }} + - name: cacert + secret: + secretName: {{ $.Values.secrets.caCert }} + - name: tls + secret: + secretName: {{ $.Values.secrets.tls }} + - name: tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} + - name: tls-client + secret: + secretName: {{ $.Values.secrets.tlsClient }} + - name: tls-clientrootcert + secret: + secretName: {{ $.Values.secrets.tlsClientRootCerts }} + - name: admin-cert + secret: + secretName: {{ $.Values.secrets.adminCert }} + - name: admin-key + secret: + secretName: {{ $.Values.secrets.adminKey }} + - name: ord-tls-rootcert + secret: + secretName: {{ $.Values.secrets.tlsRootCert }} +{{- end }} diff --git a/substrabac/libs/HealthCheckMiddleware.py b/substrabac/libs/HealthCheckMiddleware.py new file mode 100644 index 000000000..cee4271bb --- /dev/null +++ b/substrabac/libs/HealthCheckMiddleware.py @@ -0,0 +1,27 @@ +from django.http import HttpResponse + + +class HealthCheckMiddleware(object): + def __init__(self, get_response): + self.get_response = get_response + # One-time configuration and initialization. + + def __call__(self, request): + if request.method == "GET": + if request.path == "/readiness": + return self.readiness(request) + elif request.path == "/liveness": + return self.liveness(request) + return self.get_response(request) + + def liveness(self, request): + """ + Returns that the server is alive. + """ + return HttpResponse("OK") + + def readiness(self, request): + """ + Returns that the server is alive. + """ + return HttpResponse("OK") From d5237bafe7af0d16b169bbd47981652cc56fc9c8 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 1 Oct 2019 11:46:48 +0200 Subject: [PATCH 421/457] Better domain extraction --- backend/requirements.txt | 1 + substrabac/users/views/user.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 57e5ca70d..fc9b1d6f6 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -29,3 +29,4 @@ sentry-sdk == 0.5.2 six >= 1.4.0 uwsgi == 2.0.18 git+git://github.com/hyperledger/fabric-sdk-py.git@36cc15021f74c11c7ae3196e380a5275c220145f # fabric-sdk-py==0.8.1 +tldextract == 2.2.1 diff --git a/substrabac/users/views/user.py b/substrabac/users/views/user.py index 9ad24a01e..0f45b4fe0 100644 --- a/substrabac/users/views/user.py +++ b/substrabac/users/views/user.py @@ -11,6 +11,8 @@ from users.serializers import CustomTokenObtainPairSerializer +import tldextract + class UserViewSet(GenericViewSet): queryset = User.objects.all() @@ -47,7 +49,10 @@ def login(self, request, *args, **kwargs): response = Response(token.payload, status=status.HTTP_200_OK) - host = request.get_host().split(':')[0] + ext = tldextract.extract(request.get_host()) + host = ext.domain + if ext.suffix: + host += '.' + ext.suffix if settings.DEBUG: response.set_cookie('header.payload', value=headerPayload, expires=expires, domain=host) From b9448dcc60bc9dbbaa95373d114e66bcfb5b5508 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 1 Oct 2019 15:36:40 +0200 Subject: [PATCH 422/457] update populate api url --- populate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/populate.py b/populate.py index 6d523d493..9c5698269 100644 --- a/populate.py +++ b/populate.py @@ -29,7 +29,7 @@ def setup_config(network='docker'): print('Init config for owkin and chunantes') if network == 'docker': - USER, PASSWORD = ('foo', 'barbar10') + USER, PASSWORD = ('substra', 'p@$swr0d44') # get first available user client.add_profile('owkin', USER, PASSWORD, 'http://substra-backend.owkin.xyz:8000', '0.0') client.add_profile('chunantes', USER, PASSWORD, 'http://substra-backend.chunantes.xyz:8001', '0.0') From 232f8f972af0a7ed28b7fe9af6f2913f7bfe9767 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 1 Oct 2019 16:14:59 +0200 Subject: [PATCH 423/457] Improve charts and bump version. --- charts/substra-backend/values.yaml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/charts/substra-backend/values.yaml b/charts/substra-backend/values.yaml index 421b1ce71..9db48db30 100644 --- a/charts/substra-backend/values.yaml +++ b/charts/substra-backend/values.yaml @@ -37,11 +37,6 @@ backend: loadBalancerSourceRanges: [] # nodePort: 30000 - auth: {} - # user: owkward - # password: H9YJh7znjhoje3 - # header: "Basic b3drd2FyZDpIOVlKaDd6bmpob2plMw==" - ingress: enabled: false annotations: {} From 2ab3e4b2b5429cceaeb9db1ff81b5445d404dda7 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 2 Oct 2019 14:33:19 +0200 Subject: [PATCH 424/457] Fix tests --- backend/substrapp/tests/tests_tasks.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/backend/substrapp/tests/tests_tasks.py b/backend/substrapp/tests/tests_tasks.py index 77536772d..bc4ed86ec 100644 --- a/backend/substrapp/tests/tests_tasks.py +++ b/backend/substrapp/tests/tests_tasks.py @@ -58,11 +58,6 @@ def setUpTestData(cls): if assets.traintuple[1]['creator'] != assets.algo[0]['owner']: cls.outgoing_node_algo = OutgoingNode.objects.create(node_id=assets.algo[0]['owner'], secret="s3cr37") - cls.outgoing_node_traintuple = OutgoingNode.objects.create(node_id=assets.traintuple[1]['creator'], - secret="s3cr37") - if assets.traintuple[1]['creator'] != assets.algo[0]['owner']: - cls.outgoing_node_algo = OutgoingNode.objects.create(node_id=assets.algo[0]['owner'], secret="s3cr37") - def tearDown(self): shutil.rmtree(MEDIA_ROOT, ignore_errors=True) From db61dd1df6376465c95e9894bf0b08b170c956d9 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 2 Oct 2019 16:52:25 +0200 Subject: [PATCH 425/457] Use cookie friendly domains --- backend/substrapp/tests/generate_assets.py | 4 +- backend/users/views/user.py | 22 +++- docker/start.py | 2 +- substrabac/users/views/user.py | 23 +++-- users tutorial.md | 112 --------------------- 5 files changed, 35 insertions(+), 128 deletions(-) delete mode 100644 users tutorial.md diff --git a/backend/substrapp/tests/generate_assets.py b/backend/substrapp/tests/generate_assets.py index 71ac54146..e7050fd19 100644 --- a/backend/substrapp/tests/generate_assets.py +++ b/backend/substrapp/tests/generate_assets.py @@ -33,8 +33,8 @@ def main(): '2. run populate.py\n' '3. run substrapp/tests/generate_assets.py\n"""\n\n') for k, v in assets.items(): - v = v.replace('owkin.substra-backend:8000', 'testserver') - v = v.replace('chunantes.substra-backend:8001', 'testserver') + v = v.replace('substra-backend.owkin.com:8000', 'testserver') + v = v.replace('substra-backend.chunantes.com:8001', 'testserver') v = v.replace('true', 'True') v = v.replace('false', 'False') v = v.replace('null', 'None') diff --git a/backend/users/views/user.py b/backend/users/views/user.py index 9ad24a01e..6bc6513bf 100644 --- a/backend/users/views/user.py +++ b/backend/users/views/user.py @@ -11,6 +11,8 @@ from users.serializers import CustomTokenObtainPairSerializer +import tldextract + class UserViewSet(GenericViewSet): queryset = User.objects.all() @@ -26,6 +28,14 @@ def get_authenticate_header(self, request): self.www_authenticate_realm, ) + def get_host(self, request): + ext = tldextract.extract(request.get_host()) + host = ext.domain + if ext.suffix: + host += '.' + ext.suffix + + return host + @list_route(['post']) def login(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) @@ -47,7 +57,7 @@ def login(self, request, *args, **kwargs): response = Response(token.payload, status=status.HTTP_200_OK) - host = request.get_host().split(':')[0] + host = self.get_host(request) if settings.DEBUG: response.set_cookie('header.payload', value=headerPayload, expires=expires, domain=host) @@ -60,10 +70,12 @@ def login(self, request, *args, **kwargs): @list_route() def logout(self, request, *args, **kwargs): response = Response({}, status=status.HTTP_200_OK) + + host = self.get_host(request) if settings.DEBUG: - response.set_cookie('header.payload', value='', domain='127.0.0.1') - response.set_cookie('signature', value='', httponly=True, domain='127.0.0.1') + response.set_cookie('header.payload', value='', domain=host) + response.set_cookie('signature', value='', httponly=True, domain=host) else: - response.set_cookie('header.payload', value='', secure=True, domain=self.domain) - response.set_cookie('signature', value='', httponly=True, secure=True, domain=self.domain) + response.set_cookie('header.payload', value='', secure=True, domain=host) + response.set_cookie('signature', value='', httponly=True, secure=True, domain=host) return response diff --git a/docker/start.py b/docker/start.py index 03ff5474f..5b0bc1586 100644 --- a/docker/start.py +++ b/docker/start.py @@ -175,7 +175,7 @@ def generate_docker_compose_file(conf, launch_settings): user_command = f"python manage.py add_user foo barbar10" backend = { - 'container_name': f'{org_name_stripped}.substra-backend', + 'container_name': f'substra-backend.{org_name_stripped}.xyz', 'labels': ['substra'], 'image': 'substra/substra-backend', 'restart': 'unless-stopped', diff --git a/substrabac/users/views/user.py b/substrabac/users/views/user.py index 0f45b4fe0..6bc6513bf 100644 --- a/substrabac/users/views/user.py +++ b/substrabac/users/views/user.py @@ -28,6 +28,14 @@ def get_authenticate_header(self, request): self.www_authenticate_realm, ) + def get_host(self, request): + ext = tldextract.extract(request.get_host()) + host = ext.domain + if ext.suffix: + host += '.' + ext.suffix + + return host + @list_route(['post']) def login(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) @@ -49,10 +57,7 @@ def login(self, request, *args, **kwargs): response = Response(token.payload, status=status.HTTP_200_OK) - ext = tldextract.extract(request.get_host()) - host = ext.domain - if ext.suffix: - host += '.' + ext.suffix + host = self.get_host(request) if settings.DEBUG: response.set_cookie('header.payload', value=headerPayload, expires=expires, domain=host) @@ -65,10 +70,12 @@ def login(self, request, *args, **kwargs): @list_route() def logout(self, request, *args, **kwargs): response = Response({}, status=status.HTTP_200_OK) + + host = self.get_host(request) if settings.DEBUG: - response.set_cookie('header.payload', value='', domain='127.0.0.1') - response.set_cookie('signature', value='', httponly=True, domain='127.0.0.1') + response.set_cookie('header.payload', value='', domain=host) + response.set_cookie('signature', value='', httponly=True, domain=host) else: - response.set_cookie('header.payload', value='', secure=True, domain=self.domain) - response.set_cookie('signature', value='', httponly=True, secure=True, domain=self.domain) + response.set_cookie('header.payload', value='', secure=True, domain=host) + response.set_cookie('signature', value='', httponly=True, secure=True, domain=host) return response diff --git a/users tutorial.md b/users tutorial.md deleted file mode 100644 index 3009fccb2..000000000 --- a/users tutorial.md +++ /dev/null @@ -1,112 +0,0 @@ -# Users by org - - -## Need -We have the will to manage users by organization. - -Node to node authentication i.e worker to backend instances communication are not impacted and use the current Basic Auth implementation. - -We want to be able to register them from an administration point of view. - -Each user can login himself. - -## Authentications - -There are two main authentication available running in parallel: -- Secure JWT Authentication -- Session Authentication - -Each authentication process owns its login view which run against the same database and one and only user management. - - -#### Secure JWT Authentication -The first one `Secure JWT Authentication` is mainly used for web single one page application as our susbtrafront project. -We use a Secure JWT Authentication and not a simple JWT Authentication for being sure we are free of XSS and/or CORS attacks. -More reading here: -- https://medium.com/@jcbaey/authentication-in-spa-reactjs-and-vuejs-the-right-way-e4a9ac5cd9a3 -- https://medium.com/lightrail/getting-token-authentication-right-in-a-stateless-single-page-application-57d0c6474e3 -It can also be used by SDK and CLI projects such as our substra-sdk and substra-cli. - -#### Session Authentication -The second one `Session Authentication` is a classic for server rendered pages, useful for our web browsable API available via django rest framework api. -It can also be used by SDK and CLI projects but is a little bit more difficult to implement, as two requests need to be done for logging in correctly. - -## Testing - -Three projects are impacted by this change: -- substrabac -- substrafront -- substra-cli - -Each has a branch entitled `users`. - -Launch a `substra-network` network with two organizations (classic). - -### substra-cli - -1. Go to the `users` branch. - -That's all :) - -#### Test - -1. Install new version `pip install .` -2. Create configuration: -```bash -$> substra config --profile user -k -v 0.0 -u foo -p barbar10 http://owkin.substrabac:8000 -``` -3. Login -```bash -$> substra login --profile user -``` -4. Request -``` -$> substra list objective --profile user -KEY NAME METRICS -1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3 Skin Lesion Classification Objective macro-average recall -3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71 Skin Lesion Classification Objective macro-average recall -``` - -### substrabac - -1. Go to the `users` branch. -2. Install new substra-cli with `pip install -e ../substra-cli` -3. Generate nodes username/password: -```bash -$> python ./substrabac/node/generate_nodes.py -``` -4. Build docker images: -```bash -$> sh build-docker-images.sh -``` -5. Run images: -```bash -$> python start.py -d --no-backup -``` -6. Run populate.py - -For each backend it will create by default an user with username `foo` and password `barbar10`. -The `populate.py` script uses these credentials for logging in. - - -#### Test: - -1. Go to `http://owkin.substrabac:8000`, be sure to have the `mod_header` running for not having the version error message. -2. Click on the login link on the top right of the page. -3. Login -4. Enjoy - - -### susbtrafront - -1. Go to the `users` branch. -2. Rebuild the images and run them: -```bash -$> docker-compose up -d --force-recreate --build -``` - -#### Test: - -1. Go to `http://owkin.substrabac:3000`, be sure to have deactivated the `mod_header` version control. -2. Login -4. Enjoy From c431274f35fde4bdd5d3294abbf50f41924005b6 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 3 Oct 2019 10:57:29 +0200 Subject: [PATCH 426/457] Fix domain to save model and remove SITE_* useless variables. --- backend/backend/settings/dev.py | 4 ++++ backend/backend/settings/prod.py | 4 ++++ .../substrapp/management/tests/tests_bulkcreatedatasample.py | 1 - backend/substrapp/management/tests/tests_createdatamanager.py | 1 - backend/substrapp/management/tests/tests_createobjective.py | 1 - backend/substrapp/management/utils/localRequest.py | 3 ++- backend/substrapp/tests/views/tests_views_algo.py | 1 - backend/substrapp/tests/views/tests_views_datasample.py | 1 - backend/substrapp/tests/views/tests_views_objective.py | 1 - docker/start.py | 4 ---- 10 files changed, 10 insertions(+), 11 deletions(-) diff --git a/backend/backend/settings/dev.py b/backend/backend/settings/dev.py index d776c3cf3..0fe416476 100644 --- a/backend/backend/settings/dev.py +++ b/backend/backend/settings/dev.py @@ -36,10 +36,14 @@ MEDIA_ROOT = os.environ.get('MEDIA_ROOT', os.path.join(PROJECT_ROOT, f'medias/{ORG_NAME}')) +<<<<<<< HEAD:backend/backend/settings/dev.py SITE_HOST = f'{ORG_NAME}.substra-backend' SITE_PORT = DEFAULT_PORT DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') +======= +DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://substrabac.{ORG_NAME}.com:{DEFAULT_PORT}') +>>>>>>> Fix domain to save model and remove SITE_* useless variables.:substrabac/substrabac/settings/dev.py LOGGING = { 'version': 1, diff --git a/backend/backend/settings/prod.py b/backend/backend/settings/prod.py index 755097d88..186ea3a5e 100644 --- a/backend/backend/settings/prod.py +++ b/backend/backend/settings/prod.py @@ -42,9 +42,13 @@ } MEDIA_ROOT = os.environ.get('MEDIA_ROOT', f'/substra/medias/{ORG_NAME}') +<<<<<<< HEAD:backend/backend/settings/prod.py SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substra-backend') SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') +======= +DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://substrabac.{ORG_NAME}.com:{DEFAULT_PORT}') +>>>>>>> Fix domain to save model and remove SITE_* useless variables.:substrabac/substrabac/settings/prod.py LOGGING = { 'version': 1, diff --git a/backend/substrapp/management/tests/tests_bulkcreatedatasample.py b/backend/substrapp/management/tests/tests_bulkcreatedatasample.py index c2895097c..6048bbddc 100644 --- a/backend/substrapp/management/tests/tests_bulkcreatedatasample.py +++ b/backend/substrapp/management/tests/tests_bulkcreatedatasample.py @@ -25,7 +25,6 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) class BulkCreateDataSampleTestCase(TestCase): diff --git a/backend/substrapp/management/tests/tests_createdatamanager.py b/backend/substrapp/management/tests/tests_createdatamanager.py index 0a49e99f3..d3575ad0c 100644 --- a/backend/substrapp/management/tests/tests_createdatamanager.py +++ b/backend/substrapp/management/tests/tests_createdatamanager.py @@ -17,7 +17,6 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) class CreateDataManagerTestCase(TestCase): diff --git a/backend/substrapp/management/tests/tests_createobjective.py b/backend/substrapp/management/tests/tests_createobjective.py index f3b3c72a6..4e1bf8b62 100644 --- a/backend/substrapp/management/tests/tests_createobjective.py +++ b/backend/substrapp/management/tests/tests_createobjective.py @@ -16,7 +16,6 @@ @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) class CreateObjectiveTestCase(TestCase): diff --git a/backend/substrapp/management/utils/localRequest.py b/backend/substrapp/management/utils/localRequest.py index 91ec423f4..80d0d21c7 100644 --- a/backend/substrapp/management/utils/localRequest.py +++ b/backend/substrapp/management/utils/localRequest.py @@ -7,4 +7,5 @@ def is_secure(self): return not getattr(settings, 'DEBUG') def get_host(self): - return getattr(settings, 'SITE_HOST') + # remove protocol (http/https) from default domain + return getattr(settings, 'DEFAULT_DOMAIN').split('//')[-1] diff --git a/backend/substrapp/tests/views/tests_views_algo.py b/backend/substrapp/tests/views/tests_views_algo.py index c40d0c794..9fd6ade20 100644 --- a/backend/substrapp/tests/views/tests_views_algo.py +++ b/backend/substrapp/tests/views/tests_views_algo.py @@ -27,7 +27,6 @@ # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(LEDGER_SYNC_ENABLED=True) class AlgoViewTests(APITestCase): diff --git a/backend/substrapp/tests/views/tests_views_datasample.py b/backend/substrapp/tests/views/tests_views_datasample.py index 1fa01223a..487412448 100644 --- a/backend/substrapp/tests/views/tests_views_datasample.py +++ b/backend/substrapp/tests/views/tests_views_datasample.py @@ -25,7 +25,6 @@ # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(DEFAULT_DOMAIN='https://localhost') @override_settings(LEDGER_SYNC_ENABLED=True) diff --git a/backend/substrapp/tests/views/tests_views_objective.py b/backend/substrapp/tests/views/tests_views_objective.py index 78fdd5c11..000451d9a 100644 --- a/backend/substrapp/tests/views/tests_views_objective.py +++ b/backend/substrapp/tests/views/tests_views_objective.py @@ -36,7 +36,6 @@ def zip_folder(path, destination): # APITestCase @override_settings(MEDIA_ROOT=MEDIA_ROOT) -@override_settings(SITE_HOST='localhost') @override_settings(LEDGER={'name': 'test-org', 'peer': 'test-peer'}) @override_settings(DEFAULT_DOMAIN='https://localhost') @override_settings(LEDGER_SYNC_ENABLED=True) diff --git a/docker/start.py b/docker/start.py index 5b0bc1586..5587040b0 100644 --- a/docker/start.py +++ b/docker/start.py @@ -149,10 +149,6 @@ def generate_docker_compose_file(conf, launch_settings): f'CELERY_BROKER_URL={CELERY_BROKER_URL}', f'DJANGO_SETTINGS_MODULE=backend.settings.{launch_settings}', - - # Basic auth - f"SITE_HOST={os.environ.get('SITE_HOST', 'localhost')}", - f"SITE_PORT={os.environ.get('BACK_PORT', 9000)}", ] hlf_volumes = [ From d233e8f72d808a3ff125d4214b257d086a66df35 Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Thu, 3 Oct 2019 11:12:53 +0200 Subject: [PATCH 427/457] Use urlparse for local request --- backend/substrapp/management/utils/localRequest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/substrapp/management/utils/localRequest.py b/backend/substrapp/management/utils/localRequest.py index 80d0d21c7..eabc23df4 100644 --- a/backend/substrapp/management/utils/localRequest.py +++ b/backend/substrapp/management/utils/localRequest.py @@ -1,4 +1,5 @@ from django.conf import settings +from urllib.parse import urlparse class LocalRequest(object): @@ -8,4 +9,4 @@ def is_secure(self): def get_host(self): # remove protocol (http/https) from default domain - return getattr(settings, 'DEFAULT_DOMAIN').split('//')[-1] + return urlparse(getattr(settings, 'DEFAULT_DOMAIN')).netloc From 39cb7bfab2f3967904930925305a7fab9f6d3d71 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 7 Oct 2019 18:30:53 +0200 Subject: [PATCH 428/457] Fix tests after rebase --- backend/backend/settings/common.py | 1 - .../backend/settings/deps/restframework.py | 7 +++++++ backend/libs/authentication.py | 21 ------------------- backend/substrapp/views/utils.py | 7 ------- 4 files changed, 7 insertions(+), 29 deletions(-) delete mode 100644 backend/libs/authentication.py diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index 3e8b17490..459100cc7 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -67,7 +67,6 @@ AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', - 'libs.authentication.SettingsBackend', 'node.authentication.NodeBackend', ] diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index aa2d49f12..f3e0449f2 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -1,3 +1,5 @@ +from datetime import timedelta + REST_FRAMEWORK = { 'TEST_REQUEST_DEFAULT_FORMAT': 'json', 'DEFAULT_RENDERER_CLASSES': ( @@ -18,3 +20,8 @@ 'ALLOWED_VERSIONS': ('0.0',), 'DEFAULT_VERSION': '0.0', } + +SIMPLE_JWT = { + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), + 'AUTH_HEADER_TYPES': ('JWT',), +} diff --git a/backend/libs/authentication.py b/backend/libs/authentication.py deleted file mode 100644 index 44b80694c..000000000 --- a/backend/libs/authentication.py +++ /dev/null @@ -1,21 +0,0 @@ -from django.conf import settings -from django.contrib.auth.models import User - - -# TODO should be removed when local users are handled with registering/logging and session -class SettingsBackend: - """Authenticate against user and password defined in settings.""" - - def authenticate(self, request, username=None, password=None): - """Check the username/password and return a user.""" - if not username or not password: - return None - - if username == settings.BASICAUTH_USERNAME and password == settings.BASICAUTH_PASSWORD: - return User(username=username) - - return None - - def get_user(self, user_id): - # required for session - return None diff --git a/backend/substrapp/views/utils.py b/backend/substrapp/views/utils.py index 3b568d7fb..e4c7f95ac 100644 --- a/backend/substrapp/views/utils.py +++ b/backend/substrapp/views/utils.py @@ -44,10 +44,6 @@ def set_headers(self, filelike): self['Access-Control-Expose-Headers'] = 'Content-Disposition' -def is_local_user(user): - return user.username == settings.BASICAUTH_USERNAME - - def node_has_process_permission(asset): """Check if current node can process input asset.""" permission = asset['permissions']['process'] @@ -68,9 +64,6 @@ def _has_access(self, user, asset): if user.is_anonymous: # safeguard, should never happened return False - if is_local_user(user): - return True - permission = asset['permissions']['process'] if permission['public']: return True From 28aac2bc8ba1efad52e9a49b418fec1ad6587f9d Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 8 Oct 2019 09:57:29 +0200 Subject: [PATCH 429/457] clean --- README.md | 9 ++++++++- backend/node/management/commands/init_nodes.py | 1 - substrabac/node/management/commands/init_nodes.py | 1 - 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 995addb28..87e770f79 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,14 @@ BACKEND_ORG=chu-nantes BACKEND_DEFAULT_PORT=8001 ./manage.py init_nodes ./backen ## Create a default user -For working with node to node authentication, you need load some extra fixtures +A django admin command is available for registering a user: +```shell +./manage.py add_user $USERNAME $PASSWORD +``` + +The populate.py file will use for each organization credentials `substra/p@$swr0d44` for connection. +Create these users with: + ```shell BACKEND_ORG=owkin ./backend/manage.py add_user substra 'p@$swr0d44' --settings=backend.settings.dev BACKEND_ORG=chu-nantes ./backend/manage.py add_user substra 'p@$swr0d44' --settings=backend.settings.dev diff --git a/backend/node/management/commands/init_nodes.py b/backend/node/management/commands/init_nodes.py index 297679194..78875b155 100644 --- a/backend/node/management/commands/init_nodes.py +++ b/backend/node/management/commands/init_nodes.py @@ -14,7 +14,6 @@ def handle(self, *args, **options): filepath = options['file'] - print(filepath) with open(filepath) as json_file: data = json.load(json_file) diff --git a/substrabac/node/management/commands/init_nodes.py b/substrabac/node/management/commands/init_nodes.py index 297679194..78875b155 100644 --- a/substrabac/node/management/commands/init_nodes.py +++ b/substrabac/node/management/commands/init_nodes.py @@ -14,7 +14,6 @@ def handle(self, *args, **options): filepath = options['file'] - print(filepath) with open(filepath) as json_file: data = json.load(json_file) From 63401b0dc9a670cac81d4143ac126bf16404b9e3 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 8 Oct 2019 11:14:57 +0200 Subject: [PATCH 430/457] Add mising login call in populate after rebase --- populate.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/populate.py b/populate.py index 9c5698269..d151de142 100644 --- a/populate.py +++ b/populate.py @@ -135,6 +135,8 @@ def do_populate(): else: raise Exception(f"Number of orgs {args['nb_org']} not in [1, 2, 3]") + login(org_0, org_1, org_2) + print(f'will create datamanager with {org_1}') # create datamanager with org1 data = { From 6298afa18dbc91641be89837513d5821616a2c2f Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 14 Oct 2019 12:02:00 +0200 Subject: [PATCH 431/457] Use xyz instead of com --- backend/backend/settings/dev.py | 7 +------ backend/backend/settings/prod.py | 7 ++----- backend/substrapp/tests/generate_assets.py | 4 ++-- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/backend/backend/settings/dev.py b/backend/backend/settings/dev.py index 0fe416476..efd31d313 100644 --- a/backend/backend/settings/dev.py +++ b/backend/backend/settings/dev.py @@ -36,14 +36,9 @@ MEDIA_ROOT = os.environ.get('MEDIA_ROOT', os.path.join(PROJECT_ROOT, f'medias/{ORG_NAME}')) -<<<<<<< HEAD:backend/backend/settings/dev.py - -SITE_HOST = f'{ORG_NAME}.substra-backend' +SITE_HOST = f'substra-backend.{ORG_NAME}.xyz' SITE_PORT = DEFAULT_PORT DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') -======= -DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://substrabac.{ORG_NAME}.com:{DEFAULT_PORT}') ->>>>>>> Fix domain to save model and remove SITE_* useless variables.:substrabac/substrabac/settings/dev.py LOGGING = { 'version': 1, diff --git a/backend/backend/settings/prod.py b/backend/backend/settings/prod.py index 186ea3a5e..7b0371157 100644 --- a/backend/backend/settings/prod.py +++ b/backend/backend/settings/prod.py @@ -42,13 +42,10 @@ } MEDIA_ROOT = os.environ.get('MEDIA_ROOT', f'/substra/medias/{ORG_NAME}') -<<<<<<< HEAD:backend/backend/settings/prod.py -SITE_HOST = os.environ.get('SITE_HOST', f'{ORG_NAME}.substra-backend') + +SITE_HOST = os.environ.get('SITE_HOST', f'substra-backend.{ORG_NAME}.xyz') SITE_PORT = os.environ.get('SITE_PORT', DEFAULT_PORT) DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://{SITE_HOST}:{SITE_PORT}') -======= -DEFAULT_DOMAIN = os.environ.get('DEFAULT_DOMAIN', f'http://substrabac.{ORG_NAME}.com:{DEFAULT_PORT}') ->>>>>>> Fix domain to save model and remove SITE_* useless variables.:substrabac/substrabac/settings/prod.py LOGGING = { 'version': 1, diff --git a/backend/substrapp/tests/generate_assets.py b/backend/substrapp/tests/generate_assets.py index e7050fd19..16304e001 100644 --- a/backend/substrapp/tests/generate_assets.py +++ b/backend/substrapp/tests/generate_assets.py @@ -33,8 +33,8 @@ def main(): '2. run populate.py\n' '3. run substrapp/tests/generate_assets.py\n"""\n\n') for k, v in assets.items(): - v = v.replace('substra-backend.owkin.com:8000', 'testserver') - v = v.replace('substra-backend.chunantes.com:8001', 'testserver') + v = v.replace('substra-backend.owkin.xyz:8000', 'testserver') + v = v.replace('substra-backend.chunantes.xyz:8001', 'testserver') v = v.replace('true', 'True') v = v.replace('false', 'False') v = v.replace('null', 'None') From fa466d12700dacd68e102310fce990d81e2e2693 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 16 Oct 2019 11:54:18 +0200 Subject: [PATCH 432/457] cleaning --- README.md | 7 ++++++- backend/backend/settings/deps/restframework.py | 3 ++- substrabac/libs/expiryTokenAuthentication.py | 5 +++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 87e770f79..4680a1c1e 100644 --- a/README.md +++ b/README.md @@ -245,13 +245,18 @@ Then, build the images: $> sh build-docker-images.sh ``` -Then, go to the`docker` dir and run `start.py`: +Then, go to the`docker` dir and run `start.py` (`-d` means `dev` settings): ```bash $> python start.py -d --no-backup ``` Check your services are correctly started with `docker ps -a`. +## Expiry token period + +An global environment variable `ACCESS_TOKEN_LIFETIME` can be set for dealing with expiry token period. +By default, set to 24h. + ## Testing fabric-sdk-py A directory named `fabric-sdk-py_tests` is available to the root of this project. diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index f3e0449f2..fb6ebec5e 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -1,3 +1,4 @@ +import os from datetime import timedelta REST_FRAMEWORK = { @@ -22,6 +23,6 @@ } SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), + 'ACCESS_TOKEN_LIFETIME': os.environ.get('ACCESS_TOKEN_LIFETIME', timedelta(hours=24)), 'AUTH_HEADER_TYPES': ('JWT',), } diff --git a/substrabac/libs/expiryTokenAuthentication.py b/substrabac/libs/expiryTokenAuthentication.py index 713fbc5d6..192d96916 100644 --- a/substrabac/libs/expiryTokenAuthentication.py +++ b/substrabac/libs/expiryTokenAuthentication.py @@ -1,16 +1,17 @@ +import os + from rest_framework.authentication import TokenAuthentication from rest_framework.authtoken.models import Token from rest_framework.exceptions import AuthenticationFailed from datetime import timedelta from django.utils import timezone -from django.conf import settings # this return left time def expires_in(token): time_elapsed = timezone.now() - token.created - left_time = timedelta(seconds=getattr(settings, 'TOKEN_EXPIRED_AFTER_SECONDS', 5 * 60)) - time_elapsed + left_time = os.environ.get('ACCESS_TOKEN_LIFETIME', timedelta(hours=24)) - time_elapsed return left_time From abb7cbc2a59c90851ef2502e4db229fe04f4954d Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Fri, 18 Oct 2019 10:55:48 +0200 Subject: [PATCH 433/457] remove unneeded fixtures --- README.md | 4 ++-- .../backend/settings/deps/restframework.py | 2 +- backend/node/fixtures/nodes-chunantes.yaml | 24 ------------------- backend/node/fixtures/nodes-clb.yaml | 24 ------------------- backend/node/fixtures/nodes-owkin.yaml | 24 ------------------- 5 files changed, 3 insertions(+), 75 deletions(-) delete mode 100644 backend/node/fixtures/nodes-chunantes.yaml delete mode 100644 backend/node/fixtures/nodes-clb.yaml delete mode 100644 backend/node/fixtures/nodes-owkin.yaml diff --git a/README.md b/README.md index 4680a1c1e..1d851b77e 100644 --- a/README.md +++ b/README.md @@ -254,8 +254,8 @@ Check your services are correctly started with `docker ps -a`. ## Expiry token period -An global environment variable `ACCESS_TOKEN_LIFETIME` can be set for dealing with expiry token period. -By default, set to 24h. +An global environment variable `ACCESS_TOKEN_LIFETIME` expressed in minutes can be set for dealing with expiry token period. +By default, set to 24*60 min i.e 24h. ## Testing fabric-sdk-py diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index fb6ebec5e..57c52b240 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -23,6 +23,6 @@ } SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': os.environ.get('ACCESS_TOKEN_LIFETIME', timedelta(hours=24)), + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=os.environ.get('ACCESS_TOKEN_LIFETIME', 1)), 'AUTH_HEADER_TYPES': ('JWT',), } diff --git a/backend/node/fixtures/nodes-chunantes.yaml b/backend/node/fixtures/nodes-chunantes.yaml deleted file mode 100644 index cbc6a9ff4..000000000 --- a/backend/node/fixtures/nodes-chunantes.yaml +++ /dev/null @@ -1,24 +0,0 @@ -- fields: - secret: 5136ebe4f3ef6cc7fa1dd87d8eceb761e4a0a9ba0724f2a71455a926c2953ba37124b1636c6591cf92aa416672431d991141139d98f337d45767cfc908275488 - model: node.outgoingnode - pk: chu-nantesMSP -- fields: - secret: 7ba4b3e3cb54d977978fd577ac5a97349d0b4b88a5d16fb9f2e9d9c0183d28905878e3233b55da2807e33b59eb7c8032748b2c621f1ef9151cdc689af232c7dc - model: node.outgoingnode - pk: owkinMSP -- fields: - secret: 6978256d3ed5e458ce74c33e1362d5acb43160a20ca8f7b0dbf19324816d9de3a3bd798382244fd5125d82d030982b4adc9a189987c5bd165c5143f68827683d - model: node.outgoingnode - pk: clbMSP -- fields: - secret: 5136ebe4f3ef6cc7fa1dd87d8eceb761e4a0a9ba0724f2a71455a926c2953ba37124b1636c6591cf92aa416672431d991141139d98f337d45767cfc908275488 - model: node.incomingnode - pk: chu-nantesMSP -- fields: - secret: 8af85ad336b9be224449c6e8d194898fbc23f7cd4f77b742ee03af4c3fb1f5999494504e8edde5e74ee8740ce76c542402f75b68a9d49f32b83d9e3910556a46 - model: node.incomingnode - pk: owkinMSP -- fields: - secret: ef34f894f4c6d709d81af8e2b57886e92381f4019c2df77b49a54834dc5c53be865d773ed0106ae8bccc039d2b1514e9c0445ba4d3872db1958a2e0d8630329b - model: node.incomingnode - pk: clbMSP diff --git a/backend/node/fixtures/nodes-clb.yaml b/backend/node/fixtures/nodes-clb.yaml deleted file mode 100644 index 0baa5b3c8..000000000 --- a/backend/node/fixtures/nodes-clb.yaml +++ /dev/null @@ -1,24 +0,0 @@ -- fields: - secret: ef34f894f4c6d709d81af8e2b57886e92381f4019c2df77b49a54834dc5c53be865d773ed0106ae8bccc039d2b1514e9c0445ba4d3872db1958a2e0d8630329b - model: node.outgoingnode - pk: chu-nantesMSP -- fields: - secret: 640a45ade3a35b767c890b2bff0d5b5b2ce41bb86f12c2826e4a325aca30e9cc11090dadc49874d9bd60faf6dffe4a994e2bb0c0a8ff051165f6ecf52c6797f7 - model: node.outgoingnode - pk: owkinMSP -- fields: - secret: 43b6422d9332e476ebabe1586bb98f71ffd00dcbfa6cb23ce7faaf13f5c8c5312f44faea409d09b29d1c5cdf066b5048ccf302de20a955c78774eb2b88b6fde5 - model: node.outgoingnode - pk: clbMSP -- fields: - secret: 6978256d3ed5e458ce74c33e1362d5acb43160a20ca8f7b0dbf19324816d9de3a3bd798382244fd5125d82d030982b4adc9a189987c5bd165c5143f68827683d - model: node.incomingnode - pk: chu-nantesMSP -- fields: - secret: 7a4c73e3fc43ec6a64768d31e8493c2aac9c214117457a7d1b08dbe54d8ab08e3b32dda657c77b2d2ca10cc5014bc4d4233bbe732c8e7c1cc37491cd6e17efbc - model: node.incomingnode - pk: owkinMSP -- fields: - secret: 43b6422d9332e476ebabe1586bb98f71ffd00dcbfa6cb23ce7faaf13f5c8c5312f44faea409d09b29d1c5cdf066b5048ccf302de20a955c78774eb2b88b6fde5 - model: node.incomingnode - pk: clbMSP diff --git a/backend/node/fixtures/nodes-owkin.yaml b/backend/node/fixtures/nodes-owkin.yaml deleted file mode 100644 index 9c4324d53..000000000 --- a/backend/node/fixtures/nodes-owkin.yaml +++ /dev/null @@ -1,24 +0,0 @@ -- fields: - secret: 8af85ad336b9be224449c6e8d194898fbc23f7cd4f77b742ee03af4c3fb1f5999494504e8edde5e74ee8740ce76c542402f75b68a9d49f32b83d9e3910556a46 - model: node.outgoingnode - pk: chu-nantesMSP -- fields: - secret: c420b2dd0552241b21932a81001f9ef6682c22b8d427649f3e15e8ace817c06ed069bac647a3f62a6d81c6ace4c469d549d7f76c9f6adc8c2646d5af7ca4dfa3 - model: node.outgoingnode - pk: owkinMSP -- fields: - secret: 7a4c73e3fc43ec6a64768d31e8493c2aac9c214117457a7d1b08dbe54d8ab08e3b32dda657c77b2d2ca10cc5014bc4d4233bbe732c8e7c1cc37491cd6e17efbc - model: node.outgoingnode - pk: clbMSP -- fields: - secret: 7ba4b3e3cb54d977978fd577ac5a97349d0b4b88a5d16fb9f2e9d9c0183d28905878e3233b55da2807e33b59eb7c8032748b2c621f1ef9151cdc689af232c7dc - model: node.incomingnode - pk: chu-nantesMSP -- fields: - secret: c420b2dd0552241b21932a81001f9ef6682c22b8d427649f3e15e8ace817c06ed069bac647a3f62a6d81c6ace4c469d549d7f76c9f6adc8c2646d5af7ca4dfa3 - model: node.incomingnode - pk: owkinMSP -- fields: - secret: 640a45ade3a35b767c890b2bff0d5b5b2ce41bb86f12c2826e4a325aca30e9cc11090dadc49874d9bd60faf6dffe4a994e2bb0c0a8ff051165f6ecf52c6797f7 - model: node.incomingnode - pk: clbMSP From 99618d5db1c167bd859cdeb19477c82192824137 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 21 Oct 2019 10:37:08 +0200 Subject: [PATCH 434/457] Update validation password --- backend/backend/settings/common.py | 12 ++++++++ backend/libs/maximumLengthValidator.py | 29 +++++++++++++++++++ backend/libs/zxcvbnValidator.py | 17 +++++++++++ backend/requirements.txt | 3 +- backend/substrapp/tests/common.py | 2 +- backend/users/management/commands/add_user.py | 25 ++++++++++++---- docker/start.py | 2 +- substrabac/libs/maximumLengthValidator.py | 29 +++++++++++++++++++ substrabac/libs/zxcvbnValidator.py | 17 +++++++++++ .../users/management/commands/add_user.py | 25 ++++++++++++---- 10 files changed, 148 insertions(+), 13 deletions(-) create mode 100644 backend/libs/maximumLengthValidator.py create mode 100644 backend/libs/zxcvbnValidator.py create mode 100644 substrabac/libs/maximumLengthValidator.py create mode 100644 substrabac/libs/zxcvbnValidator.py diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index 459100cc7..95b286109 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -117,11 +117,23 @@ # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'libs.zxcvbnValidator.ZxcvbnValidator', + }, { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + 'OPTIONS': { + 'min_length': 9, + } + }, + { + 'NAME': 'libs.maximumLengthValidator.MaximumLengthValidator', + 'OPTIONS': { + 'max_length': 64 + } }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', diff --git a/backend/libs/maximumLengthValidator.py b/backend/libs/maximumLengthValidator.py new file mode 100644 index 000000000..0e3226376 --- /dev/null +++ b/backend/libs/maximumLengthValidator.py @@ -0,0 +1,29 @@ +from django.core.exceptions import ValidationError +from django.utils.translation import ngettext + + +class MaximumLengthValidator: + """ + Validate whether the password is of a maximum length. + """ + def __init__(self, max_length=64): + self.max_length = max_length + + def validate(self, password, user=None): + if len(password) > self.max_length: + raise ValidationError( + ngettext( + "This password is too long. It must contain a maximum of %(max_length)d character.", + "This password is too long. It must contain a maximum of %(max_length)d characters.", + self.max_length + ), + code='password_too_long', + params={'max_length': self.max_length}, + ) + + def get_help_text(self): + return ngettext( + "Your password must contain a maximum of %(max_length)d character.", + "Your password must contain a maximum of %(max_length)d characters.", + self.max_length + ) % {'min_length': self.max_length} diff --git a/backend/libs/zxcvbnValidator.py b/backend/libs/zxcvbnValidator.py new file mode 100644 index 000000000..63bf5cb37 --- /dev/null +++ b/backend/libs/zxcvbnValidator.py @@ -0,0 +1,17 @@ +from django.core.exceptions import ValidationError +from django.utils.translation import gettext as _ +from zxcvbn import zxcvbn + + +class ZxcvbnValidator: + + def validate(self, password, user=None): + results = zxcvbn(password, user_inputs=[user]) + + # score to the password, from 0 (terrible) to 4 (great) + if results['score'] < 3: + raise ValidationError(_(f"This password is not enough complex.\nwarning: {results['feedback']['warning']}"), + code='password_not_complex') + + def get_help_text(self): + return _("Your password must be complex one") diff --git a/backend/requirements.txt b/backend/requirements.txt index fc9b1d6f6..3a620bb36 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -27,6 +27,7 @@ requests == 2.20.0 rx >= 1.5.3 sentry-sdk == 0.5.2 six >= 1.4.0 +tldextract == 2.2.1 uwsgi == 2.0.18 +zxcvbn==4.4.28 git+git://github.com/hyperledger/fabric-sdk-py.git@36cc15021f74c11c7ae3196e380a5275c220145f # fabric-sdk-py==0.8.1 -tldextract == 2.2.1 diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 9c76d6203..1261dca16 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -29,7 +29,7 @@ def request(self, **kwargs): # create user username = 'foo' - password = 'barbar10' + password = 'p@$swr0d44' try: with transaction.atomic(): User.objects.create_user(username=username, password=password) diff --git a/backend/users/management/commands/add_user.py b/backend/users/management/commands/add_user.py index 952681209..987d267f2 100644 --- a/backend/users/management/commands/add_user.py +++ b/backend/users/management/commands/add_user.py @@ -1,6 +1,8 @@ import secrets -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model +from django.contrib.auth.password_validation import validate_password +from django.core.exceptions import ValidationError from django.core.management.base import BaseCommand from django.db import IntegrityError @@ -8,14 +10,27 @@ class Command(BaseCommand): help = 'Add user' + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.UserModel = get_user_model() + def add_arguments(self, parser): parser.add_argument('username') parser.add_argument('password', nargs='?', default=secrets.token_hex(8)) def handle(self, *args, **options): + + username = options['username'] + password = options['password'] + try: - User.objects.create_user(username=options['username'], password=options['password']) - except IntegrityError as e: - self.stderr.write(f'User already exists: {str(e)}') + validate_password(password, self.UserModel(username=username)) + except ValidationError as err: + self.stderr.write('\n'.join(err.messages)) else: - self.stdout.write(f"password: {options['password']}") + try: + self.UserModel.objects.create_user(username=username, password=password) + except IntegrityError as e: + self.stderr.write(f'User already exists: {str(e)}') + else: + self.stdout.write(f"password: {password}") diff --git a/docker/start.py b/docker/start.py index 5587040b0..ec71c9580 100644 --- a/docker/start.py +++ b/docker/start.py @@ -168,7 +168,7 @@ def generate_docker_compose_file(conf, launch_settings): user_command = '' if launch_settings == 'dev': fixtures_command = f"python manage.py init_nodes ./node/nodes/{org_name}MSP.json" - user_command = f"python manage.py add_user foo barbar10" + user_command = f"python manage.py add_user foo p@$swr0d44" backend = { 'container_name': f'substra-backend.{org_name_stripped}.xyz', diff --git a/substrabac/libs/maximumLengthValidator.py b/substrabac/libs/maximumLengthValidator.py new file mode 100644 index 000000000..0e3226376 --- /dev/null +++ b/substrabac/libs/maximumLengthValidator.py @@ -0,0 +1,29 @@ +from django.core.exceptions import ValidationError +from django.utils.translation import ngettext + + +class MaximumLengthValidator: + """ + Validate whether the password is of a maximum length. + """ + def __init__(self, max_length=64): + self.max_length = max_length + + def validate(self, password, user=None): + if len(password) > self.max_length: + raise ValidationError( + ngettext( + "This password is too long. It must contain a maximum of %(max_length)d character.", + "This password is too long. It must contain a maximum of %(max_length)d characters.", + self.max_length + ), + code='password_too_long', + params={'max_length': self.max_length}, + ) + + def get_help_text(self): + return ngettext( + "Your password must contain a maximum of %(max_length)d character.", + "Your password must contain a maximum of %(max_length)d characters.", + self.max_length + ) % {'min_length': self.max_length} diff --git a/substrabac/libs/zxcvbnValidator.py b/substrabac/libs/zxcvbnValidator.py new file mode 100644 index 000000000..63bf5cb37 --- /dev/null +++ b/substrabac/libs/zxcvbnValidator.py @@ -0,0 +1,17 @@ +from django.core.exceptions import ValidationError +from django.utils.translation import gettext as _ +from zxcvbn import zxcvbn + + +class ZxcvbnValidator: + + def validate(self, password, user=None): + results = zxcvbn(password, user_inputs=[user]) + + # score to the password, from 0 (terrible) to 4 (great) + if results['score'] < 3: + raise ValidationError(_(f"This password is not enough complex.\nwarning: {results['feedback']['warning']}"), + code='password_not_complex') + + def get_help_text(self): + return _("Your password must be complex one") diff --git a/substrabac/users/management/commands/add_user.py b/substrabac/users/management/commands/add_user.py index 952681209..987d267f2 100644 --- a/substrabac/users/management/commands/add_user.py +++ b/substrabac/users/management/commands/add_user.py @@ -1,6 +1,8 @@ import secrets -from django.contrib.auth.models import User +from django.contrib.auth import get_user_model +from django.contrib.auth.password_validation import validate_password +from django.core.exceptions import ValidationError from django.core.management.base import BaseCommand from django.db import IntegrityError @@ -8,14 +10,27 @@ class Command(BaseCommand): help = 'Add user' + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.UserModel = get_user_model() + def add_arguments(self, parser): parser.add_argument('username') parser.add_argument('password', nargs='?', default=secrets.token_hex(8)) def handle(self, *args, **options): + + username = options['username'] + password = options['password'] + try: - User.objects.create_user(username=options['username'], password=options['password']) - except IntegrityError as e: - self.stderr.write(f'User already exists: {str(e)}') + validate_password(password, self.UserModel(username=username)) + except ValidationError as err: + self.stderr.write('\n'.join(err.messages)) else: - self.stdout.write(f"password: {options['password']}") + try: + self.UserModel.objects.create_user(username=username, password=password) + except IntegrityError as e: + self.stderr.write(f'User already exists: {str(e)}') + else: + self.stdout.write(f"password: {password}") From 5fb1adc5817aa64a5f62f0bab05cf39a92984ca8 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 21 Oct 2019 10:43:37 +0200 Subject: [PATCH 435/457] Use username substra --- backend/substrapp/tests/common.py | 2 +- docker/start.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 1261dca16..76ce9d074 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -28,7 +28,7 @@ class AuthenticatedClient(APIClient): def request(self, **kwargs): # create user - username = 'foo' + username = 'substra' password = 'p@$swr0d44' try: with transaction.atomic(): diff --git a/docker/start.py b/docker/start.py index ec71c9580..a331259e2 100644 --- a/docker/start.py +++ b/docker/start.py @@ -168,7 +168,7 @@ def generate_docker_compose_file(conf, launch_settings): user_command = '' if launch_settings == 'dev': fixtures_command = f"python manage.py init_nodes ./node/nodes/{org_name}MSP.json" - user_command = f"python manage.py add_user foo p@$swr0d44" + user_command = f"python manage.py add_user substra p@$swr0d44" backend = { 'container_name': f'substra-backend.{org_name_stripped}.xyz', From 6495ea608d03a829310735d1d28759ce899844b9 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 21 Oct 2019 11:42:05 +0200 Subject: [PATCH 436/457] Update complex password handling --- backend/libs/zxcvbnValidator.py | 8 +++++--- docker/start.py | 2 +- substrabac/libs/zxcvbnValidator.py | 8 +++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/backend/libs/zxcvbnValidator.py b/backend/libs/zxcvbnValidator.py index 63bf5cb37..82077ebc8 100644 --- a/backend/libs/zxcvbnValidator.py +++ b/backend/libs/zxcvbnValidator.py @@ -10,8 +10,10 @@ def validate(self, password, user=None): # score to the password, from 0 (terrible) to 4 (great) if results['score'] < 3: - raise ValidationError(_(f"This password is not enough complex.\nwarning: {results['feedback']['warning']}"), - code='password_not_complex') + str = 'This password is not complex enough.' + if results['feedback']['warning']: + str += f"\nnwarning: {results['feedback']['warning']}" + raise ValidationError(_(str), code='password_not_complex') def get_help_text(self): - return _("Your password must be complex one") + return _("Your password must be a complex one") diff --git a/docker/start.py b/docker/start.py index a331259e2..f03f0bf65 100644 --- a/docker/start.py +++ b/docker/start.py @@ -168,7 +168,7 @@ def generate_docker_compose_file(conf, launch_settings): user_command = '' if launch_settings == 'dev': fixtures_command = f"python manage.py init_nodes ./node/nodes/{org_name}MSP.json" - user_command = f"python manage.py add_user substra p@$swr0d44" + user_command = f"python manage.py add_user substra 'p@$swr0d44'" backend = { 'container_name': f'substra-backend.{org_name_stripped}.xyz', diff --git a/substrabac/libs/zxcvbnValidator.py b/substrabac/libs/zxcvbnValidator.py index 63bf5cb37..82077ebc8 100644 --- a/substrabac/libs/zxcvbnValidator.py +++ b/substrabac/libs/zxcvbnValidator.py @@ -10,8 +10,10 @@ def validate(self, password, user=None): # score to the password, from 0 (terrible) to 4 (great) if results['score'] < 3: - raise ValidationError(_(f"This password is not enough complex.\nwarning: {results['feedback']['warning']}"), - code='password_not_complex') + str = 'This password is not complex enough.' + if results['feedback']['warning']: + str += f"\nnwarning: {results['feedback']['warning']}" + raise ValidationError(_(str), code='password_not_complex') def get_help_text(self): - return _("Your password must be complex one") + return _("Your password must be a complex one") From 93d0eedc7a655fb83426dbb4bc4c690080d4b227 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 21 Oct 2019 12:06:55 +0200 Subject: [PATCH 437/457] Fix $ with docker-compose $ special env --- docker/start.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker/start.py b/docker/start.py index f03f0bf65..ae6a66dbf 100644 --- a/docker/start.py +++ b/docker/start.py @@ -1,4 +1,5 @@ import os +import re import json import glob import argparse @@ -168,7 +169,7 @@ def generate_docker_compose_file(conf, launch_settings): user_command = '' if launch_settings == 'dev': fixtures_command = f"python manage.py init_nodes ./node/nodes/{org_name}MSP.json" - user_command = f"python manage.py add_user substra 'p@$swr0d44'" + user_command = f"python manage.py add_user substra '{'p@$swr0d44'.replace('$', '$$')}'" # needed for docker-compose special variable backend = { 'container_name': f'substra-backend.{org_name_stripped}.xyz', From 551bf564b73e2bf616b246ef0b8c17139d6c6651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Gasser?= Date: Mon, 21 Oct 2019 08:35:29 -0400 Subject: [PATCH 438/457] use SUBSTRA_PATH in ledger.py --- backend/backend/settings/deps/ledger.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/backend/settings/deps/ledger.py b/backend/backend/settings/deps/ledger.py index a5e7a2b90..66eda4120 100644 --- a/backend/backend/settings/deps/ledger.py +++ b/backend/backend/settings/deps/ledger.py @@ -1,4 +1,3 @@ - import os import base64 import asyncio @@ -15,8 +14,8 @@ from hfc.util.keyvaluestore import FileKeyValueStore from hfc.fabric.block_decoder import decode_fabric_MSP_config, decode_fabric_peers_info, decode_fabric_endpoints - -LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'/substra/conf/{ORG}/substra-backend/conf.json') +SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') +LEDGER_CONFIG_FILE = os.environ.get('LEDGER_CONFIG_FILE', f'{SUBSTRA_FOLDER}/conf/{ORG}/substra-backend/conf.json') LEDGER = json.load(open(LEDGER_CONFIG_FILE, 'r')) LEDGER_SYNC_ENABLED = True From ecf97700e110617c22cd7b5cecc966c8a0990411 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 21 Oct 2019 16:35:23 +0200 Subject: [PATCH 439/457] Fix min_length error --- substrabac/libs/maximumLengthValidator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/libs/maximumLengthValidator.py b/substrabac/libs/maximumLengthValidator.py index 0e3226376..61679d8a4 100644 --- a/substrabac/libs/maximumLengthValidator.py +++ b/substrabac/libs/maximumLengthValidator.py @@ -26,4 +26,4 @@ def get_help_text(self): "Your password must contain a maximum of %(max_length)d character.", "Your password must contain a maximum of %(max_length)d characters.", self.max_length - ) % {'min_length': self.max_length} + ) % {'max_length': self.max_length} From 8c0f5b0b62d7611496f4d1912a3dec385df72f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Gasser?= Date: Mon, 21 Oct 2019 10:56:05 -0400 Subject: [PATCH 440/457] password validation: add tests (#389) --- .../tests/tests_password_validation.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 substrabac/substrapp/tests/tests_password_validation.py diff --git a/substrabac/substrapp/tests/tests_password_validation.py b/substrabac/substrapp/tests/tests_password_validation.py new file mode 100644 index 000000000..330a2d87a --- /dev/null +++ b/substrabac/substrapp/tests/tests_password_validation.py @@ -0,0 +1,43 @@ +from django.test import TestCase +from django.core.exceptions import ValidationError +from libs.maximumLengthValidator import MaximumLengthValidator +from libs.zxcvbnValidator import ZxcvbnValidator + + +class PasswordValidationTests(TestCase): + + def setUp(self): + self.max_len_validator = MaximumLengthValidator() + self.complexity_validator = ZxcvbnValidator() + + def test_password_invalid_length(self): + password_short = "aaa" + password_too_long = ''.join(["a" * 65]) + + # short password OK + try: + self.max_len_validator.validate(password_short) + except Exception: + self.fail(f"Password validation should succeed when the password is not too long.") + + # too long password NOT OK + self.assertRaisesRegexp(ValidationError, + "This password is too long. It must contain a maximum of 64 characters.", + self.max_len_validator.validate, + password_too_long) + + def test_password_complexity(self): + password_not_complex = "abc" + password_complex = "p@$swr0d44" + + # complex password OK + try: + self.complexity_validator.validate(password_complex) + except Exception: + self.fail(f"Password validation should succeed when the password is complex enough.") + + # easy-to-guess password NOT OK + self.assertRaisesRegexp(ValidationError, + "This password is not complex enough.*", + self.complexity_validator.validate, + password_not_complex) From 1648c14e53b5fbbb386c51e1fc2b06e4a8cdab55 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 22 Oct 2019 14:09:27 +0200 Subject: [PATCH 441/457] fix ACCESS_TOKEN_LIFETIME settings override handling --- backend/backend/settings/deps/restframework.py | 2 +- substrabac/libs/expiryTokenAuthentication.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/backend/settings/deps/restframework.py b/backend/backend/settings/deps/restframework.py index 57c52b240..a0e4dbe77 100644 --- a/backend/backend/settings/deps/restframework.py +++ b/backend/backend/settings/deps/restframework.py @@ -23,6 +23,6 @@ } SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=os.environ.get('ACCESS_TOKEN_LIFETIME', 1)), + 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=int(os.environ.get('ACCESS_TOKEN_LIFETIME', 24*60))), 'AUTH_HEADER_TYPES': ('JWT',), } diff --git a/substrabac/libs/expiryTokenAuthentication.py b/substrabac/libs/expiryTokenAuthentication.py index 192d96916..a5b262186 100644 --- a/substrabac/libs/expiryTokenAuthentication.py +++ b/substrabac/libs/expiryTokenAuthentication.py @@ -1,8 +1,7 @@ -import os - from rest_framework.authentication import TokenAuthentication from rest_framework.authtoken.models import Token from rest_framework.exceptions import AuthenticationFailed +from rest_framework_simplejwt.settings import api_settings from datetime import timedelta from django.utils import timezone @@ -11,7 +10,7 @@ # this return left time def expires_in(token): time_elapsed = timezone.now() - token.created - left_time = os.environ.get('ACCESS_TOKEN_LIFETIME', timedelta(hours=24)) - time_elapsed + left_time = api_settings.ACCESS_TOKEN_LIFETIME - time_elapsed return left_time From 978d0a882fc7cbfdf0090d225ebf7e779733d1bc Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 22 Oct 2019 15:02:24 +0200 Subject: [PATCH 442/457] fix flake8 --- docker/start.py | 4 ++-- substrabac/libs/expiryTokenAuthentication.py | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/docker/start.py b/docker/start.py index ae6a66dbf..186e02d84 100644 --- a/docker/start.py +++ b/docker/start.py @@ -1,5 +1,4 @@ import os -import re import json import glob import argparse @@ -169,7 +168,8 @@ def generate_docker_compose_file(conf, launch_settings): user_command = '' if launch_settings == 'dev': fixtures_command = f"python manage.py init_nodes ./node/nodes/{org_name}MSP.json" - user_command = f"python manage.py add_user substra '{'p@$swr0d44'.replace('$', '$$')}'" # needed for docker-compose special variable + # replace needed for docker-compose special variable + user_command = f"python manage.py add_user substra '{'p@$swr0d44'.replace('$', '$$')}'" backend = { 'container_name': f'substra-backend.{org_name_stripped}.xyz', diff --git a/substrabac/libs/expiryTokenAuthentication.py b/substrabac/libs/expiryTokenAuthentication.py index a5b262186..59c0e54c1 100644 --- a/substrabac/libs/expiryTokenAuthentication.py +++ b/substrabac/libs/expiryTokenAuthentication.py @@ -37,16 +37,12 @@ class ExpiryTokenAuthentication(TokenAuthentication): """ def authenticate_credentials(self, key): - try: - token = Token.objects.get(key=key) - except Token.DoesNotExist: - raise AuthenticationFailed("Invalid Token") - if not token.user.is_active: - raise AuthenticationFailed("User is not active") + _, token = super(ExpiryTokenAuthentication, self).authenticate_credentials(key) - is_expired, token = token_expire_handler(token) + is_expired = is_token_expired(token) if is_expired: - raise AuthenticationFailed("The Token is expired") + token.delete() + raise AuthenticationFailed('The Token is expired') return (token.user, token) From d61b1782b017b2d84b8adc0b03ccbadb9fb2a6b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Gasser?= Date: Wed, 23 Oct 2019 13:39:11 -0400 Subject: [PATCH 443/457] typo --- substrabac/libs/zxcvbnValidator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrabac/libs/zxcvbnValidator.py b/substrabac/libs/zxcvbnValidator.py index 82077ebc8..aadc1a474 100644 --- a/substrabac/libs/zxcvbnValidator.py +++ b/substrabac/libs/zxcvbnValidator.py @@ -12,7 +12,7 @@ def validate(self, password, user=None): if results['score'] < 3: str = 'This password is not complex enough.' if results['feedback']['warning']: - str += f"\nnwarning: {results['feedback']['warning']}" + str += f"\nwarning: {results['feedback']['warning']}" raise ValidationError(_(str), code='password_not_complex') def get_help_text(self): From d021f05eb3d10dc5bb0d128d5f2f5974800382d6 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 28 Oct 2019 11:08:37 +0100 Subject: [PATCH 444/457] fix file after rebase --- backend/libs/expiryTokenAuthentication.py | 16 +++---- backend/libs/maximumLengthValidator.py | 2 +- backend/libs/zxcvbnValidator.py | 2 +- .../tests/tests_password_validation.py | 43 +++++++++++++++++++ 4 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 backend/substrapp/tests/tests_password_validation.py diff --git a/backend/libs/expiryTokenAuthentication.py b/backend/libs/expiryTokenAuthentication.py index 713fbc5d6..59c0e54c1 100644 --- a/backend/libs/expiryTokenAuthentication.py +++ b/backend/libs/expiryTokenAuthentication.py @@ -1,16 +1,16 @@ from rest_framework.authentication import TokenAuthentication from rest_framework.authtoken.models import Token from rest_framework.exceptions import AuthenticationFailed +from rest_framework_simplejwt.settings import api_settings from datetime import timedelta from django.utils import timezone -from django.conf import settings # this return left time def expires_in(token): time_elapsed = timezone.now() - token.created - left_time = timedelta(seconds=getattr(settings, 'TOKEN_EXPIRED_AFTER_SECONDS', 5 * 60)) - time_elapsed + left_time = api_settings.ACCESS_TOKEN_LIFETIME - time_elapsed return left_time @@ -37,16 +37,12 @@ class ExpiryTokenAuthentication(TokenAuthentication): """ def authenticate_credentials(self, key): - try: - token = Token.objects.get(key=key) - except Token.DoesNotExist: - raise AuthenticationFailed("Invalid Token") - if not token.user.is_active: - raise AuthenticationFailed("User is not active") + _, token = super(ExpiryTokenAuthentication, self).authenticate_credentials(key) - is_expired, token = token_expire_handler(token) + is_expired = is_token_expired(token) if is_expired: - raise AuthenticationFailed("The Token is expired") + token.delete() + raise AuthenticationFailed('The Token is expired') return (token.user, token) diff --git a/backend/libs/maximumLengthValidator.py b/backend/libs/maximumLengthValidator.py index 0e3226376..61679d8a4 100644 --- a/backend/libs/maximumLengthValidator.py +++ b/backend/libs/maximumLengthValidator.py @@ -26,4 +26,4 @@ def get_help_text(self): "Your password must contain a maximum of %(max_length)d character.", "Your password must contain a maximum of %(max_length)d characters.", self.max_length - ) % {'min_length': self.max_length} + ) % {'max_length': self.max_length} diff --git a/backend/libs/zxcvbnValidator.py b/backend/libs/zxcvbnValidator.py index 82077ebc8..aadc1a474 100644 --- a/backend/libs/zxcvbnValidator.py +++ b/backend/libs/zxcvbnValidator.py @@ -12,7 +12,7 @@ def validate(self, password, user=None): if results['score'] < 3: str = 'This password is not complex enough.' if results['feedback']['warning']: - str += f"\nnwarning: {results['feedback']['warning']}" + str += f"\nwarning: {results['feedback']['warning']}" raise ValidationError(_(str), code='password_not_complex') def get_help_text(self): diff --git a/backend/substrapp/tests/tests_password_validation.py b/backend/substrapp/tests/tests_password_validation.py new file mode 100644 index 000000000..330a2d87a --- /dev/null +++ b/backend/substrapp/tests/tests_password_validation.py @@ -0,0 +1,43 @@ +from django.test import TestCase +from django.core.exceptions import ValidationError +from libs.maximumLengthValidator import MaximumLengthValidator +from libs.zxcvbnValidator import ZxcvbnValidator + + +class PasswordValidationTests(TestCase): + + def setUp(self): + self.max_len_validator = MaximumLengthValidator() + self.complexity_validator = ZxcvbnValidator() + + def test_password_invalid_length(self): + password_short = "aaa" + password_too_long = ''.join(["a" * 65]) + + # short password OK + try: + self.max_len_validator.validate(password_short) + except Exception: + self.fail(f"Password validation should succeed when the password is not too long.") + + # too long password NOT OK + self.assertRaisesRegexp(ValidationError, + "This password is too long. It must contain a maximum of 64 characters.", + self.max_len_validator.validate, + password_too_long) + + def test_password_complexity(self): + password_not_complex = "abc" + password_complex = "p@$swr0d44" + + # complex password OK + try: + self.complexity_validator.validate(password_complex) + except Exception: + self.fail(f"Password validation should succeed when the password is complex enough.") + + # easy-to-guess password NOT OK + self.assertRaisesRegexp(ValidationError, + "This password is not complex enough.*", + self.complexity_validator.validate, + password_not_complex) From b9c572b5983f10d77011444aecba3f0c4bb48833 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 28 Oct 2019 15:26:26 +0100 Subject: [PATCH 445/457] mini fix after review --- backend/backend/settings/common.py | 4 + backend/backend/views.py | 4 +- backend/libs/expiryTokenAuthentication.py | 8 +- backend/users/views/user.py | 6 +- docker/start.py | 44 +- substrabac/libs/HealthCheckMiddleware.py | 27 - substrabac/libs/expiryTokenAuthentication.py | 48 -- substrabac/libs/maximumLengthValidator.py | 29 - substrabac/libs/sessionAuthentication.py | 19 - substrabac/libs/zxcvbnValidator.py | 19 - substrabac/node/generate_nodes.py | 64 -- .../node/management/commands/init_nodes.py | 25 - substrabac/substrapp/tests/assets.py | 608 ------------------ .../tests/tests_password_validation.py | 43 -- substrabac/users/__init__.py | 0 substrabac/users/apps.py | 5 - substrabac/users/authentication.py | 28 - .../users/management/commands/__init__.py | 0 .../users/management/commands/add_user.py | 36 -- substrabac/users/serializers/__init__.py | 5 - substrabac/users/serializers/user.py | 32 - substrabac/users/urls.py | 16 - substrabac/users/views/__init__.py | 5 - substrabac/users/views/user.py | 81 --- 24 files changed, 36 insertions(+), 1120 deletions(-) delete mode 100644 substrabac/libs/HealthCheckMiddleware.py delete mode 100644 substrabac/libs/expiryTokenAuthentication.py delete mode 100644 substrabac/libs/maximumLengthValidator.py delete mode 100644 substrabac/libs/sessionAuthentication.py delete mode 100644 substrabac/libs/zxcvbnValidator.py delete mode 100755 substrabac/node/generate_nodes.py delete mode 100644 substrabac/node/management/commands/init_nodes.py delete mode 100644 substrabac/substrapp/tests/assets.py delete mode 100644 substrabac/substrapp/tests/tests_password_validation.py delete mode 100644 substrabac/users/__init__.py delete mode 100644 substrabac/users/apps.py delete mode 100644 substrabac/users/authentication.py delete mode 100644 substrabac/users/management/commands/__init__.py delete mode 100644 substrabac/users/management/commands/add_user.py delete mode 100644 substrabac/users/serializers/__init__.py delete mode 100644 substrabac/users/serializers/user.py delete mode 100644 substrabac/users/urls.py delete mode 100644 substrabac/users/views/__init__.py delete mode 100644 substrabac/users/views/user.py diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index 95b286109..b08f9b21d 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -12,6 +12,8 @@ import os import sys +from datetime import timedelta + from libs.gen_secret_key import write_secret_key # Build paths inside the project like this: os.path.join(BASE_DIR, ...) @@ -176,6 +178,8 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 +EXPIRY_TOKEN_LIFETIME = timedelta(minutes=int(os.environ.get('EXPIRY_TOKEN_LIFETIME', 24*60))), + TRUE_VALUES = { 't', 'T', 'y', 'Y', 'yes', 'YES', diff --git a/backend/backend/views.py b/backend/backend/views.py index 2f96774c8..abb1450c9 100644 --- a/backend/backend/views.py +++ b/backend/backend/views.py @@ -11,7 +11,7 @@ from django.conf.urls import url, include -from libs.expiryTokenAuthentication import token_expire_handler, expires_in +from libs.expiryTokenAuthentication import token_expire_handler, expires_at from substrapp.urls import router from requests.compat import urlparse @@ -128,7 +128,7 @@ def post(self, request, *args, **kwargs): return Response({ 'token': token.key, - 'expires_in': expires_in(token) + 'expires_at': expires_at(token) }) diff --git a/backend/libs/expiryTokenAuthentication.py b/backend/libs/expiryTokenAuthentication.py index 59c0e54c1..1e470eb3a 100644 --- a/backend/libs/expiryTokenAuthentication.py +++ b/backend/libs/expiryTokenAuthentication.py @@ -1,22 +1,22 @@ +from django.conf import settings from rest_framework.authentication import TokenAuthentication from rest_framework.authtoken.models import Token from rest_framework.exceptions import AuthenticationFailed -from rest_framework_simplejwt.settings import api_settings from datetime import timedelta from django.utils import timezone # this return left time -def expires_in(token): +def expires_at(token): time_elapsed = timezone.now() - token.created - left_time = api_settings.ACCESS_TOKEN_LIFETIME - time_elapsed + left_time = getattr(settings, 'EXPIRY_TOKEN_LIFETIME') - time_elapsed return left_time # token checker if token expired or not def is_token_expired(token): - return expires_in(token) < timedelta(seconds=0) + return expires_at(token) < timedelta(seconds=0) # if token is expired new token will be established diff --git a/backend/users/views/user.py b/backend/users/views/user.py index 6bc6513bf..a0faf7517 100644 --- a/backend/users/views/user.py +++ b/backend/users/views/user.py @@ -4,7 +4,7 @@ from rest_framework import status from rest_framework.permissions import AllowAny from rest_framework.viewsets import GenericViewSet -from rest_framework.decorators import list_route +from rest_framework.decorators import action from rest_framework.response import Response from rest_framework_simplejwt.authentication import AUTH_HEADER_TYPES from rest_framework_simplejwt.exceptions import TokenError, InvalidToken, AuthenticationFailed @@ -36,7 +36,7 @@ def get_host(self, request): return host - @list_route(['post']) + @action(methods=['post'], detail=False) def login(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) @@ -67,7 +67,7 @@ def login(self, request, *args, **kwargs): response.set_cookie('signature', value=signature, httponly=True, secure=True, domain=host) return response - @list_route() + @action(detail=False) def logout(self, request, *args, **kwargs): response = Response({}, status=status.HTTP_200_OK) diff --git a/docker/start.py b/docker/start.py index 186e02d84..af1f0b7b8 100644 --- a/docker/start.py +++ b/docker/start.py @@ -111,9 +111,6 @@ def generate_docker_compose_file(conf, launch_settings): }, 'path': os.path.join(dir_path, './docker-compose-dynamic.yaml')} - # generate nodes - # TODO make sure nodes folder exists else warn - for org in conf: org_name = org['name'] org_name_stripped = org_name.replace('-', '') @@ -264,24 +261,29 @@ def stop(docker_compose=None): def start(conf, launch_settings, no_backup): - print('Generate docker-compose file\n') - docker_compose = generate_docker_compose_file(conf, launch_settings) - - stop(docker_compose) - - if no_backup: - print('Clean medias directory\n') - call(['sh', os.path.join(dir_path, '../scripts/clean_media.sh')]) - print('Remove postgresql database\n') - call(['rm', '-rf', f'{SUBSTRA_FOLDER}/backup/postgres-data']) - print('Remove rabbit database\n') - call(['rm', '-rf', f'{SUBSTRA_FOLDER}/backup/rabbit-data']) - - print('start docker-compose', flush=True) - call(['docker-compose', '-f', docker_compose['path'], '--project-directory', - os.path.join(dir_path, '../'), 'up', '-d', '--remove-orphans', '--build']) - call(['docker', 'ps', '-a', '--format', 'table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}', - '--filter', 'label=substra']) + nodes_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'backend/node/nodes') + if not os.path.exists(nodes_path): + print('ERROR: nodes folder does not exist, please run `python ./backend/node/generate_nodes.py`' + ' (you maybe will have to regenerate your docker images)\n') + else: + print('Generate docker-compose file\n') + docker_compose = generate_docker_compose_file(conf, launch_settings) + + stop(docker_compose) + + if no_backup: + print('Clean medias directory\n') + call(['sh', os.path.join(dir_path, '../scripts/clean_media.sh')]) + print('Remove postgresql database\n') + call(['rm', '-rf', f'{SUBSTRA_FOLDER}/backup/postgres-data']) + print('Remove rabbit database\n') + call(['rm', '-rf', f'{SUBSTRA_FOLDER}/backup/rabbit-data']) + + print('start docker-compose', flush=True) + call(['docker-compose', '-f', docker_compose['path'], '--project-directory', + os.path.join(dir_path, '../'), 'up', '-d', '--remove-orphans', '--build']) + call(['docker', 'ps', '-a', '--format', 'table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Ports}}', + '--filter', 'label=substra']) if __name__ == "__main__": diff --git a/substrabac/libs/HealthCheckMiddleware.py b/substrabac/libs/HealthCheckMiddleware.py deleted file mode 100644 index cee4271bb..000000000 --- a/substrabac/libs/HealthCheckMiddleware.py +++ /dev/null @@ -1,27 +0,0 @@ -from django.http import HttpResponse - - -class HealthCheckMiddleware(object): - def __init__(self, get_response): - self.get_response = get_response - # One-time configuration and initialization. - - def __call__(self, request): - if request.method == "GET": - if request.path == "/readiness": - return self.readiness(request) - elif request.path == "/liveness": - return self.liveness(request) - return self.get_response(request) - - def liveness(self, request): - """ - Returns that the server is alive. - """ - return HttpResponse("OK") - - def readiness(self, request): - """ - Returns that the server is alive. - """ - return HttpResponse("OK") diff --git a/substrabac/libs/expiryTokenAuthentication.py b/substrabac/libs/expiryTokenAuthentication.py deleted file mode 100644 index 59c0e54c1..000000000 --- a/substrabac/libs/expiryTokenAuthentication.py +++ /dev/null @@ -1,48 +0,0 @@ -from rest_framework.authentication import TokenAuthentication -from rest_framework.authtoken.models import Token -from rest_framework.exceptions import AuthenticationFailed -from rest_framework_simplejwt.settings import api_settings - -from datetime import timedelta -from django.utils import timezone - - -# this return left time -def expires_in(token): - time_elapsed = timezone.now() - token.created - left_time = api_settings.ACCESS_TOKEN_LIFETIME - time_elapsed - return left_time - - -# token checker if token expired or not -def is_token_expired(token): - return expires_in(token) < timedelta(seconds=0) - - -# if token is expired new token will be established -# If token is expired then it will be removed -# and new one with different key will be created -def token_expire_handler(token): - is_expired = is_token_expired(token) - if is_expired: - token.delete() - token = Token.objects.create(user=token.user) - return is_expired, token - - -class ExpiryTokenAuthentication(TokenAuthentication): - """ - If token is expired then it will be removed - and new one with different key will be created - """ - - def authenticate_credentials(self, key): - - _, token = super(ExpiryTokenAuthentication, self).authenticate_credentials(key) - - is_expired = is_token_expired(token) - if is_expired: - token.delete() - raise AuthenticationFailed('The Token is expired') - - return (token.user, token) diff --git a/substrabac/libs/maximumLengthValidator.py b/substrabac/libs/maximumLengthValidator.py deleted file mode 100644 index 61679d8a4..000000000 --- a/substrabac/libs/maximumLengthValidator.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.core.exceptions import ValidationError -from django.utils.translation import ngettext - - -class MaximumLengthValidator: - """ - Validate whether the password is of a maximum length. - """ - def __init__(self, max_length=64): - self.max_length = max_length - - def validate(self, password, user=None): - if len(password) > self.max_length: - raise ValidationError( - ngettext( - "This password is too long. It must contain a maximum of %(max_length)d character.", - "This password is too long. It must contain a maximum of %(max_length)d characters.", - self.max_length - ), - code='password_too_long', - params={'max_length': self.max_length}, - ) - - def get_help_text(self): - return ngettext( - "Your password must contain a maximum of %(max_length)d character.", - "Your password must contain a maximum of %(max_length)d characters.", - self.max_length - ) % {'max_length': self.max_length} diff --git a/substrabac/libs/sessionAuthentication.py b/substrabac/libs/sessionAuthentication.py deleted file mode 100644 index 85f28544c..000000000 --- a/substrabac/libs/sessionAuthentication.py +++ /dev/null @@ -1,19 +0,0 @@ -from rest_framework.authentication import SessionAuthentication - - -class CustomSessionAuthentication(SessionAuthentication): - """ - Use Django's session framework for authentication. - """ - - def authenticate(self, request): - """ - Returns a `User` if the request session currently has a logged in user. - Otherwise returns `None`. - """ - - # bypass for login with jwt - if request.resolver_match.url_name == 'user-login': - return None - - return super(CustomSessionAuthentication, self).authenticate(request) diff --git a/substrabac/libs/zxcvbnValidator.py b/substrabac/libs/zxcvbnValidator.py deleted file mode 100644 index aadc1a474..000000000 --- a/substrabac/libs/zxcvbnValidator.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.core.exceptions import ValidationError -from django.utils.translation import gettext as _ -from zxcvbn import zxcvbn - - -class ZxcvbnValidator: - - def validate(self, password, user=None): - results = zxcvbn(password, user_inputs=[user]) - - # score to the password, from 0 (terrible) to 4 (great) - if results['score'] < 3: - str = 'This password is not complex enough.' - if results['feedback']['warning']: - str += f"\nwarning: {results['feedback']['warning']}" - raise ValidationError(_(str), code='password_not_complex') - - def get_help_text(self): - return _("Your password must be a complex one") diff --git a/substrabac/node/generate_nodes.py b/substrabac/node/generate_nodes.py deleted file mode 100755 index 7f59b71ff..000000000 --- a/substrabac/node/generate_nodes.py +++ /dev/null @@ -1,64 +0,0 @@ -import json -import os -import secrets - - -def generate_secret(): - return secrets.token_hex(64) - - -def generate(orgs): - files = {} - - # TODO merge two loops - # init file content - for org in orgs: - data = { - 'incoming_nodes': [], - 'outgoing_nodes': [], - } - files[org] = data - - for org in orgs: - # create intern node (request from worker A to substrabac A) - secret = generate_secret() - files[org]['outgoing_nodes'].append({ - 'node_id': org, - 'secret': secret - }) - files[org]['incoming_nodes'].append({ - 'node_id': org, - 'secret': secret - }) - - for other_org in filter(lambda x: x != org, orgs): - # outgoing from server B to server A share same secret as incoming from server B in server A - secret = generate_secret() - files[other_org]['outgoing_nodes'].append({ # in server B - 'node_id': org, # to server A - 'secret': secret - }) - - files[org]['incoming_nodes'].append({ # in server A - 'node_id': other_org, # from server B - 'secret': secret - }) - - return files - - -def generate_for_orgs(orgs): - files = generate(orgs) - dir_path = os.path.dirname(os.path.realpath(__file__)) - nodes_path = os.path.join(dir_path, 'nodes') - os.makedirs(nodes_path, exist_ok=True) - for k, v in files.items(): - filepath = os.path.join(nodes_path, f'{k}.json') - with open(filepath, 'w') as f: - f.write(json.dumps(v, indent=4)) - - -if __name__ == '__main__': - orgs = ['owkinMSP', 'chu-nantesMSP', 'clbMSP'] # TODO should be discovered by discovery service - - generate_for_orgs(orgs) diff --git a/substrabac/node/management/commands/init_nodes.py b/substrabac/node/management/commands/init_nodes.py deleted file mode 100644 index 78875b155..000000000 --- a/substrabac/node/management/commands/init_nodes.py +++ /dev/null @@ -1,25 +0,0 @@ -import json - -from django.core.management.base import BaseCommand -from node.models import IncomingNode, OutgoingNode - - -class Command(BaseCommand): - help = 'Load nodes from file' - - def add_arguments(self, parser): - parser.add_argument('file') - - def handle(self, *args, **options): - - filepath = options['file'] - - with open(filepath) as json_file: - data = json.load(json_file) - - for node in data['incoming_nodes']: - IncomingNode.objects.create(node_id=node['node_id'], secret=node['secret']) - self.stdout.write(self.style.SUCCESS('created incoming node')) - for node in data['outgoing_nodes']: - OutgoingNode.objects.create(node_id=node['node_id'], secret=node['secret']) - self.stdout.write(self.style.SUCCESS('created outgoing node')) diff --git a/substrabac/substrapp/tests/assets.py b/substrabac/substrapp/tests/assets.py deleted file mode 100644 index da015933e..000000000 --- a/substrabac/substrapp/tests/assets.py +++ /dev/null @@ -1,608 +0,0 @@ -""" -WARNING -======= - -DO NOT MANUALLY EDIT THIS FILE! - -It is generated using substrapp/tests/generate_assets.py - -In order to update this file: -1. start a clean instance of substra -2. run populate.py -3. run substrapp/tests/generate_assets.py -""" - -objective = [ - { - "key": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", - "name": "Skin Lesion Classification Objective", - "description": { - "hash": "1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3", - "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/description/" - }, - "metrics": { - "name": "macro-average recall", - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/1cdafbb018dd195690111d74916b76c96892d897ec3587c814f287946db446c3/metrics/" - }, - "owner": "owkinMSP", - "testDataset": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - }, - { - "key": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "name": "Skin Lesion Classification Objective", - "description": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/description/" - }, - "metrics": { - "name": "macro-average recall", - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - }, - "owner": "owkinMSP", - "testDataset": { - "dataManagerKey": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "dataSampleKeys": [ - "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf", - "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a" - ], - "worker": "" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - } -] - -datamanager = [ - { - "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "description": { - "hash": "15863c2af1fcfee9ca6f61f04be8a0eaaf6a45e4d50c421788d450d198e580f1", - "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/description/" - }, - "key": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "name": "ISIC 2018", - "opener": { - "hash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "storageAddress": "http://testserver/data_manager/8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca/opener/" - }, - "owner": "chu-nantesMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "type": "Images" - }, - { - "objectiveKey": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "description": { - "hash": "258bef187a166b3fef5cb86e68c8f7e154c283a148cd5bc344fec7e698821ad3", - "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/description/" - }, - "key": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "name": "Simplified ISIC 2018", - "opener": { - "hash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "storageAddress": "http://testserver/data_manager/ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932/opener/" - }, - "owner": "owkinMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "type": "Images" - } -] - -algo = [ - { - "key": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", - "name": "Neural Network", - "content": { - "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", - "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" - }, - "description": { - "hash": "b9463411a01ea00869bdffce6e59a5c100a4e635c0a9386266cad3c77eb28e9e", - "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/description/" - }, - "owner": "chu-nantesMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - }, - { - "key": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "name": "Random Forest", - "content": { - "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" - }, - "description": { - "hash": "4acea40c4b51996c88ef279c5c9aa41ab77b97d38c5ca167e978a98b2e402675", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/description/" - }, - "owner": "chu-nantesMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - }, - { - "key": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "name": "Logistic regression", - "content": { - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "description": { - "hash": "124a0425b746d7072282d167b53cb6aab3a31bf1946dae89135c15b0126ebec3", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/description/" - }, - "owner": "owkinMSP", - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - } - } -] - -traintuple = [ - { - "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", - "algo": { - "name": "Neural Network", - "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", - "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 0 - }, - "computePlanID": "", - "inModels": None, - "log": "[01-01-0165-e17cc59]", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "failed", - "tag": "My super tag" - }, - { - "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 1 - }, - "computePlanID": "", - "inModels": None, - "log": "", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": { - "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", - "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "done", - "tag": "substra" - }, - { - "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 1 - }, - "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", - "inModels": None, - "log": "", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": { - "hash": "77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193", - "storageAddress": "http://testserver/model/77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193/file/" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "done", - "tag": "" - }, - { - "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", - "algo": { - "name": "Random Forest", - "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 0 - }, - "computePlanID": "", - "inModels": None, - "log": "[01-01-0165-32eaa7e]", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "failed", - "tag": "" - } -] - -testtuple = [ - { - "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "certified": True, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "owkinMSP", - "keys": [ - "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", - "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" - ], - "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "perf": 0 - }, - "log": "", - "model": { - "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", - "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" - }, - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "status": "done", - "tag": "substra" - } -] - -model = [ - { - "traintuple": { - "key": "0cdf5520e2b5d4242bd503791a2da3afaeaf7f45b84b388667367b7e4df7c3d3", - "algo": { - "name": "Neural Network", - "hash": "0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f", - "storageAddress": "http://testserver/algo/0acc5180e09b6a6ac250f4e3c172e2893f617aa1c22ef1f379019d20fe44142f/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 0 - }, - "computePlanID": "", - "inModels": None, - "log": "[01-01-0165-e17cc59]", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "failed", - "tag": "My super tag" - }, - "testtuple": { - "key": "", - "algo": None, - "certified": False, - "creator": "", - "dataset": None, - "log": "", - "model": None, - "objective": None, - "status": "", - "tag": "" - } - }, - { - "traintuple": { - "key": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 1 - }, - "computePlanID": "", - "inModels": None, - "log": "", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": { - "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", - "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "done", - "tag": "substra" - }, - "testtuple": { - "key": "2672e448f9944748664a0b5dceb335de8db7f2646e9da2a836d8ebbec2c3fd4c", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "certified": True, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "owkinMSP", - "keys": [ - "17d58b67ae2028018108c9bf555fa58b2ddcfe560e0117294196e79d26140b2a", - "8bf3bf4f753a32f27d18c86405e7a406a83a55610d91abcca9acc525061b8ecf" - ], - "openerHash": "ce9f292c72e9b82697445117f9c2d1d18ce0f8ed07ff91dadb17d668bddf8932", - "perf": 0 - }, - "log": "", - "model": { - "traintupleKey": "0bd1a982d5d26699a2c32fe8ec72d9debb0af017a91a45c98fe1f8bf784b0b87", - "hash": "4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b", - "storageAddress": "http://testserver/model/4d79c29495e1d6bb7bbe920c633eae328ab25e79a8e77e37a2e0315839fc6d8b/file/" - }, - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "status": "done", - "tag": "substra" - } - }, - { - "traintuple": { - "key": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", - "algo": { - "name": "Logistic regression", - "hash": "7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5", - "storageAddress": "http://testserver/algo/7c9f9799bf64c10002381583a9ffc535bc3f4bf14d6f0c614d3f6f868f72a9d5/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "e3644123451975be20909fcfd9c664a0573d9bfe04c5021625412d78c3536f1c" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 1 - }, - "computePlanID": "94be807e307b3c14e3bee15478ac466ac1fbc373cd207a0c4db9456c971e518a", - "inModels": None, - "log": "", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": { - "hash": "77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193", - "storageAddress": "http://testserver/model/77f61ca2a815e04487f6c212f7e9342437c3c30e3c2dad56e994f4d802607193/file/" - }, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "done", - "tag": "" - }, - "testtuple": { - "key": "", - "algo": None, - "certified": False, - "creator": "", - "dataset": None, - "log": "", - "model": None, - "objective": None, - "status": "", - "tag": "" - } - }, - { - "traintuple": { - "key": "dd80853c84f752b69fb0738f368d32a56a16e072e81f1c9fd6e781cc27ca80b3", - "algo": { - "name": "Random Forest", - "hash": "9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9", - "storageAddress": "http://testserver/algo/9c3d8777e11fd72cbc0fd672bec3a0848f8518b4d56706008cc05f8a1cee44f9/file/" - }, - "creator": "chu-nantesMSP", - "dataset": { - "worker": "chu-nantesMSP", - "keys": [ - "31510dc1d8be788f7c5d28d05714f7efb9edb667762966b9adc02eadeaacebe9", - "03a1f878768ea8624942d46a3b438c37992e626c2cf655023bcc3bed69d485d1" - ], - "openerHash": "8dd01465003a9b1e01c99c904d86aa518b3a5dd9dc8d40fe7d075c726ac073ca", - "perf": 0 - }, - "computePlanID": "", - "inModels": None, - "log": "[01-01-0165-32eaa7e]", - "objective": { - "hash": "3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71", - "metrics": { - "hash": "501b94306d9c65650273629d0f5e8177043dc3cc93ea309263fcc52f1eb010e0", - "storageAddress": "http://testserver/objective/3d70ab46d710dacb0f48cb42db4874fac14e048a0d415e266aad38c09591ee71/metrics/" - } - }, - "outModel": None, - "permissions": { - "process": { - "public": True, - "authorizedIDs": [] - } - }, - "rank": 0, - "status": "failed", - "tag": "" - }, - "testtuple": { - "key": "", - "algo": None, - "certified": False, - "creator": "", - "dataset": None, - "log": "", - "model": None, - "objective": None, - "status": "", - "tag": "" - } - } -] - diff --git a/substrabac/substrapp/tests/tests_password_validation.py b/substrabac/substrapp/tests/tests_password_validation.py deleted file mode 100644 index 330a2d87a..000000000 --- a/substrabac/substrapp/tests/tests_password_validation.py +++ /dev/null @@ -1,43 +0,0 @@ -from django.test import TestCase -from django.core.exceptions import ValidationError -from libs.maximumLengthValidator import MaximumLengthValidator -from libs.zxcvbnValidator import ZxcvbnValidator - - -class PasswordValidationTests(TestCase): - - def setUp(self): - self.max_len_validator = MaximumLengthValidator() - self.complexity_validator = ZxcvbnValidator() - - def test_password_invalid_length(self): - password_short = "aaa" - password_too_long = ''.join(["a" * 65]) - - # short password OK - try: - self.max_len_validator.validate(password_short) - except Exception: - self.fail(f"Password validation should succeed when the password is not too long.") - - # too long password NOT OK - self.assertRaisesRegexp(ValidationError, - "This password is too long. It must contain a maximum of 64 characters.", - self.max_len_validator.validate, - password_too_long) - - def test_password_complexity(self): - password_not_complex = "abc" - password_complex = "p@$swr0d44" - - # complex password OK - try: - self.complexity_validator.validate(password_complex) - except Exception: - self.fail(f"Password validation should succeed when the password is complex enough.") - - # easy-to-guess password NOT OK - self.assertRaisesRegexp(ValidationError, - "This password is not complex enough.*", - self.complexity_validator.validate, - password_not_complex) diff --git a/substrabac/users/__init__.py b/substrabac/users/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/substrabac/users/apps.py b/substrabac/users/apps.py deleted file mode 100644 index 4ce1fabc0..000000000 --- a/substrabac/users/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class UsersConfig(AppConfig): - name = 'users' diff --git a/substrabac/users/authentication.py b/substrabac/users/authentication.py deleted file mode 100644 index 16f363d29..000000000 --- a/substrabac/users/authentication.py +++ /dev/null @@ -1,28 +0,0 @@ -from rest_framework_simplejwt.authentication import JWTAuthentication - - -class SecureJWTAuthentication(JWTAuthentication): - - def authenticate(self, request): - if request.resolver_match.url_name in ('user-login', 'api-root'): - return None - - header = self.get_header(request) - if header is None: - return None - - raw_token = self.get_raw_token(header) - if raw_token is None: - return None - - # reconstruct token from httpOnly cookie signature - try: - signature = request.COOKIES['signature'] - except Exception: - return None - else: - raw_token = raw_token + f".{signature}".encode() - - validated_token = self.get_validated_token(raw_token) - - return self.get_user(validated_token), None diff --git a/substrabac/users/management/commands/__init__.py b/substrabac/users/management/commands/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/substrabac/users/management/commands/add_user.py b/substrabac/users/management/commands/add_user.py deleted file mode 100644 index 987d267f2..000000000 --- a/substrabac/users/management/commands/add_user.py +++ /dev/null @@ -1,36 +0,0 @@ -import secrets - -from django.contrib.auth import get_user_model -from django.contrib.auth.password_validation import validate_password -from django.core.exceptions import ValidationError -from django.core.management.base import BaseCommand -from django.db import IntegrityError - - -class Command(BaseCommand): - help = 'Add user' - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.UserModel = get_user_model() - - def add_arguments(self, parser): - parser.add_argument('username') - parser.add_argument('password', nargs='?', default=secrets.token_hex(8)) - - def handle(self, *args, **options): - - username = options['username'] - password = options['password'] - - try: - validate_password(password, self.UserModel(username=username)) - except ValidationError as err: - self.stderr.write('\n'.join(err.messages)) - else: - try: - self.UserModel.objects.create_user(username=username, password=password) - except IntegrityError as e: - self.stderr.write(f'User already exists: {str(e)}') - else: - self.stdout.write(f"password: {password}") diff --git a/substrabac/users/serializers/__init__.py b/substrabac/users/serializers/__init__.py deleted file mode 100644 index 87ae7d6c1..000000000 --- a/substrabac/users/serializers/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# encoding: utf-8 - -from .user import CustomTokenObtainPairSerializer - -__all__ = ['CustomTokenObtainPairSerializer'] diff --git a/substrabac/users/serializers/user.py b/substrabac/users/serializers/user.py deleted file mode 100644 index b08c8476d..000000000 --- a/substrabac/users/serializers/user.py +++ /dev/null @@ -1,32 +0,0 @@ -from rest_framework_simplejwt.serializers import TokenObtainSerializer -from rest_framework_simplejwt.settings import api_settings -from rest_framework_simplejwt.token_blacklist.models import OutstandingToken -from rest_framework_simplejwt.tokens import AccessToken -from rest_framework_simplejwt.utils import datetime_from_epoch - - -class CustomTokenObtainPairSerializer(TokenObtainSerializer): - def get_token(self, user): - """ - Adds this token to the outstanding token list. - """ - token = AccessToken.for_user(user) - - jti = token[api_settings.JTI_CLAIM] - exp = token['exp'] - - OutstandingToken.objects.create( - user=user, - jti=jti, - token=str(token), - created_at=token.current_time, - expires_at=datetime_from_epoch(exp), - ) - - return token - - def validate(self, attrs): - super().validate(attrs) - token = self.get_token(self.user) - - return token diff --git a/substrabac/users/urls.py b/substrabac/users/urls.py deleted file mode 100644 index 557c4ef17..000000000 --- a/substrabac/users/urls.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -substrapp URL -""" - -from django.conf.urls import url, include -from rest_framework.routers import DefaultRouter - -# Create a router and register our viewsets with it. -from users.views import UserViewSet - -router = DefaultRouter() -router.register(r'user', UserViewSet, base_name='user') - -urlpatterns = [ - url(r'^', include(router.urls)), -] diff --git a/substrabac/users/views/__init__.py b/substrabac/users/views/__init__.py deleted file mode 100644 index f114283ed..000000000 --- a/substrabac/users/views/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# encoding: utf-8 - -from .user import UserViewSet - -__all__ = ['UserViewSet'] diff --git a/substrabac/users/views/user.py b/substrabac/users/views/user.py deleted file mode 100644 index 6bc6513bf..000000000 --- a/substrabac/users/views/user.py +++ /dev/null @@ -1,81 +0,0 @@ -from django.conf import settings -from django.contrib.auth.models import User - -from rest_framework import status -from rest_framework.permissions import AllowAny -from rest_framework.viewsets import GenericViewSet -from rest_framework.decorators import list_route -from rest_framework.response import Response -from rest_framework_simplejwt.authentication import AUTH_HEADER_TYPES -from rest_framework_simplejwt.exceptions import TokenError, InvalidToken, AuthenticationFailed - -from users.serializers import CustomTokenObtainPairSerializer - -import tldextract - - -class UserViewSet(GenericViewSet): - queryset = User.objects.all() - serializer_class = CustomTokenObtainPairSerializer - - www_authenticate_realm = 'api' - - permission_classes = [AllowAny] - - def get_authenticate_header(self, request): - return '{0} realm="{1}"'.format( - AUTH_HEADER_TYPES[0], - self.www_authenticate_realm, - ) - - def get_host(self, request): - ext = tldextract.extract(request.get_host()) - host = ext.domain - if ext.suffix: - host += '.' + ext.suffix - - return host - - @list_route(['post']) - def login(self, request, *args, **kwargs): - serializer = self.get_serializer(data=request.data) - - try: - serializer.is_valid(raise_exception=True) - except AuthenticationFailed: - return Response({'message': 'wrong username password'}, status=status.HTTP_401_UNAUTHORIZED) - except TokenError as e: - raise InvalidToken(e.args[0]) - - token = serializer.validated_data - - expires = token.current_time + token.lifetime - - tokenString = str(token) - headerPayload = '.'.join(tokenString.split('.')[0:2]) - signature = tokenString.split('.')[2] - - response = Response(token.payload, status=status.HTTP_200_OK) - - host = self.get_host(request) - - if settings.DEBUG: - response.set_cookie('header.payload', value=headerPayload, expires=expires, domain=host) - response.set_cookie('signature', value=signature, httponly=True, domain=host) - else: - response.set_cookie('header.payload', value=headerPayload, expires=expires, secure=True, domain=host) - response.set_cookie('signature', value=signature, httponly=True, secure=True, domain=host) - return response - - @list_route() - def logout(self, request, *args, **kwargs): - response = Response({}, status=status.HTTP_200_OK) - - host = self.get_host(request) - if settings.DEBUG: - response.set_cookie('header.payload', value='', domain=host) - response.set_cookie('signature', value='', httponly=True, domain=host) - else: - response.set_cookie('header.payload', value='', secure=True, domain=host) - response.set_cookie('signature', value='', httponly=True, secure=True, domain=host) - return response From d306808078a5dd23d8da7c4c9787aa55a85a0271 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 28 Oct 2019 16:06:56 +0100 Subject: [PATCH 446/457] fix job add users after renaming --- backend/node/generate_nodes.py | 2 +- .../templates/job-add-users.yaml | 20 +-- .../substrabac/templates/job-add-users.yaml | 143 ------------------ docker/substrabac/Dockerfile | 21 --- 4 files changed, 11 insertions(+), 175 deletions(-) delete mode 100644 charts/substrabac/templates/job-add-users.yaml delete mode 100644 docker/substrabac/Dockerfile diff --git a/backend/node/generate_nodes.py b/backend/node/generate_nodes.py index 0750d3ff3..f46cb44d9 100755 --- a/backend/node/generate_nodes.py +++ b/backend/node/generate_nodes.py @@ -20,7 +20,7 @@ def generate(orgs): files[org] = data for org in orgs: - # create intern node (request from worker A to substrabac A) + # create intern node (request from worker A to backend A) secret = generate_secret() files[org]['outgoing_nodes'].append({ 'node_id': org, diff --git a/charts/substra-backend/templates/job-add-users.yaml b/charts/substra-backend/templates/job-add-users.yaml index ca8feef71..319d1b2b2 100644 --- a/charts/substra-backend/templates/job-add-users.yaml +++ b/charts/substra-backend/templates/job-add-users.yaml @@ -21,7 +21,7 @@ spec: {{- end }} {{- end }} containers: - - name: substrabac + - name: backend image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" command: ["python3"] @@ -29,18 +29,18 @@ spec: env: - name: ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABAC_ORG + - name: BACKEND_ORG value: {{ $.Values.organization.name }} - - name: SUBSTRABAC_{{ $.Values.organization.name | upper }}_DB_NAME + - name: BACKEND_{{ $.Values.organization.name | upper }}_DB_NAME value: {{ $.Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABAC_DB_USER + - name: BACKEND_DB_USER value: {{ $.Values.postgresql.postgresqlUsername }} - - name: SUBSTRABAC_DB_PWD + - name: BACKEND_DB_PWD value: {{ $.Values.postgresql.postgresqlPassword }} - name: DATABASE_HOST value: {{ $.Release.Name }}-postgresql - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.{{ $.Values.backend.settings }} + value: backend.settings.{{ $.Values.backend.settings }} - name: FABRIC_CFG_PATH value: /var/hyperledger/fabric_cfg - name: CORE_PEER_ADDRESS_ENV @@ -55,12 +55,12 @@ spec: value: {{ $.user | quote }} - name: BACK_AUTH_PASSWORD value: {{ $.password | quote }} - - name: SUBSTRABAC_DEFAULT_PORT + - name: BACKEND_DEFAULT_PORT value: {{ $.Values.backend.service.port | quote}} - - name: SUBSTRABAC_PEER_PORT + - name: BACKEND_PEER_PORT value: "internal" - name: LEDGER_CONFIG_FILE - value: /conf/{{ $.Values.organization.name }}/substrabac/conf.json + value: /conf/{{ $.Values.organization.name }}/backend/conf.json - name: PYTHONUNBUFFERED value: "1" - name: MEDIA_ROOT @@ -68,7 +68,7 @@ spec: volumeMounts: - mountPath: {{ $.Values.persistence.hostPath }} name: data - - mountPath: /conf/{{ $.Values.organization.name }}/substrabac + - mountPath: /conf/{{ $.Values.organization.name }}/backend name: config readOnly: true - mountPath: /var/hyperledger/fabric_cfg diff --git a/charts/substrabac/templates/job-add-users.yaml b/charts/substrabac/templates/job-add-users.yaml deleted file mode 100644 index ca8feef71..000000000 --- a/charts/substrabac/templates/job-add-users.yaml +++ /dev/null @@ -1,143 +0,0 @@ -{{- range $index, $value := .Values.users }} ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ template "substra.fullname" $ }}-add-users-{{ $index }} - labels: - app.kubernetes.io/managed-by: {{ $.Release.Service }} - app.kubernetes.io/instance: {{ $.Release.Name }} - helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} - app.kubernetes.io/name: {{ template "substra.name" $ }}-add-users-{{ $index }} - app.kubernetes.io/part-of: {{ template "substra.name" $ }} -spec: - template: - spec: - restartPolicy: OnFailure - {{- with $.Values.backend.image.pullSecrets }} - imagePullSecrets: - {{- range . }} - - name: {{ . }} - {{- end }} - {{- end }} - containers: - - name: substrabac - image: "{{ $.Values.backend.image.repository }}:{{ $.Values.backend.image.tag }}" - imagePullPolicy: "{{ $.Values.backend.image.pullPolicy }}" - command: ["python3"] - args: ["manage.py", "add_user", {{ .name }}, {{ .secret }}] - env: - - name: ORG - value: {{ $.Values.organization.name }} - - name: SUBSTRABAC_ORG - value: {{ $.Values.organization.name }} - - name: SUBSTRABAC_{{ $.Values.organization.name | upper }}_DB_NAME - value: {{ $.Values.postgresql.postgresqlDatabase }} - - name: SUBSTRABAC_DB_USER - value: {{ $.Values.postgresql.postgresqlUsername }} - - name: SUBSTRABAC_DB_PWD - value: {{ $.Values.postgresql.postgresqlPassword }} - - name: DATABASE_HOST - value: {{ $.Release.Name }}-postgresql - - name: DJANGO_SETTINGS_MODULE - value: substrabac.settings.{{ $.Values.backend.settings }} - - name: FABRIC_CFG_PATH - value: /var/hyperledger/fabric_cfg - - name: CORE_PEER_ADDRESS_ENV - value: "{{ $.Values.peer.host }}:{{ $.Values.peer.port }}" - - name: FABRIC_LOGGING_SPEC - value: debug - - name: DEFAULT_DOMAIN - value: "{{ $.Values.backend.defaultDomain }}" - - name: CELERY_BROKER_URL - value: "amqp://{{ $.Values.rabbitmq.rabbitmq.username }}:{{ $.Values.rabbitmq.rabbitmq.password }}@{{ $.Release.Name }}-{{ $.Values.rabbitmq.host }}:{{ $.Values.rabbitmq.port }}//" - - name: BACK_AUTH_USER - value: {{ $.user | quote }} - - name: BACK_AUTH_PASSWORD - value: {{ $.password | quote }} - - name: SUBSTRABAC_DEFAULT_PORT - value: {{ $.Values.backend.service.port | quote}} - - name: SUBSTRABAC_PEER_PORT - value: "internal" - - name: LEDGER_CONFIG_FILE - value: /conf/{{ $.Values.organization.name }}/substrabac/conf.json - - name: PYTHONUNBUFFERED - value: "1" - - name: MEDIA_ROOT - value: {{ $.Values.persistence.hostPath }}/medias/ - volumeMounts: - - mountPath: {{ $.Values.persistence.hostPath }} - name: data - - mountPath: /conf/{{ $.Values.organization.name }}/substrabac - name: config - readOnly: true - - mountPath: /var/hyperledger/fabric_cfg - name: fabric - readOnly: true - - mountPath: /var/hyperledger/msp/signcerts - name: id-cert - - mountPath: /var/hyperledger/msp/keystore - name: id-key - - mountPath: /var/hyperledger/msp/cacerts - name: cacert - - mountPath: /var/hyperledger/msp/admincerts - name: admin-cert - - mountPath: /var/hyperledger/tls/server/pair - name: tls - - mountPath: /var/hyperledger/tls/server/cert - name: tls-rootcert - - mountPath: /var/hyperledger/tls/client/pair - name: tls-client - - mountPath: /var/hyperledger/tls/client/cert - name: tls-clientrootcert - - mountPath: /var/hyperledger/tls/ord/cert - name: ord-tls-rootcert - - mountPath: /var/hyperledger/admin_msp/signcerts - name: admin-cert - - mountPath: /var/hyperledger/admin_msp/keystore - name: admin-key - - mountPath: /var/hyperledger/admin_msp/cacerts - name: cacert - - mountPath: /var/hyperledger/admin_msp/admincerts - name: admin-cert - volumes: - - name: data - persistentVolumeClaim: - claimName: {{ include "substra.fullname" $ }} - - name: config - configMap: - name: {{ include "substra.fullname" $ }}-backend - - name: fabric - configMap: - name: {{ $.Values.secrets.fabricConfigmap }} - - name: id-cert - secret: - secretName: {{ $.Values.secrets.cert }} - - name: id-key - secret: - secretName: {{ $.Values.secrets.key }} - - name: cacert - secret: - secretName: {{ $.Values.secrets.caCert }} - - name: tls - secret: - secretName: {{ $.Values.secrets.tls }} - - name: tls-rootcert - secret: - secretName: {{ $.Values.secrets.tlsRootCert }} - - name: tls-client - secret: - secretName: {{ $.Values.secrets.tlsClient }} - - name: tls-clientrootcert - secret: - secretName: {{ $.Values.secrets.tlsClientRootCerts }} - - name: admin-cert - secret: - secretName: {{ $.Values.secrets.adminCert }} - - name: admin-key - secret: - secretName: {{ $.Values.secrets.adminKey }} - - name: ord-tls-rootcert - secret: - secretName: {{ $.Values.secrets.tlsRootCert }} -{{- end }} diff --git a/docker/substrabac/Dockerfile b/docker/substrabac/Dockerfile deleted file mode 100644 index f7dca881b..000000000 --- a/docker/substrabac/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM python:3.6 - -RUN apt-get update -RUN apt-get install -y python3 python3-pip python3-dev build-essential libssl-dev libffi-dev libxml2-dev libxslt1-dev zlib1g-dev g++ gcc gfortran musl-dev postgresql-contrib -RUN apt-get install -y git curl netcat - -RUN mkdir -p /usr/src/app -WORKDIR /usr/src/app - -COPY ./substrabac/requirements.txt /usr/src/app/. - -RUN pip3 install -r requirements.txt - -COPY ./substrabac/manage.py /usr/src/app/manage.py -COPY ./substrabac/libs /usr/src/app/libs -COPY ./substrabac/substrapp /usr/src/app/substrapp -COPY ./substrabac/events /usr/src/app/events -COPY ./substrabac/substrabac /usr/src/app/substrabac -COPY ./substrabac/node /usr/src/app/node -COPY ./substrabac/node-register /usr/src/app/node-register -COPY ./substrabac/users /usr/src/app/users From 5838c6b740e61d0a8c8a5858f68b3ac0bd4d430f Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 28 Oct 2019 16:29:27 +0100 Subject: [PATCH 447/457] Fix extra comma --- backend/backend/settings/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/backend/settings/common.py b/backend/backend/settings/common.py index b08f9b21d..b1f0040db 100644 --- a/backend/backend/settings/common.py +++ b/backend/backend/settings/common.py @@ -178,7 +178,7 @@ DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 -EXPIRY_TOKEN_LIFETIME = timedelta(minutes=int(os.environ.get('EXPIRY_TOKEN_LIFETIME', 24*60))), +EXPIRY_TOKEN_LIFETIME = timedelta(minutes=int(os.environ.get('EXPIRY_TOKEN_LIFETIME', 24*60))) TRUE_VALUES = { 't', 'T', From 609820e5461083176769ed7c397a547e19bd04c0 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Mon, 28 Oct 2019 17:54:43 +0100 Subject: [PATCH 448/457] support permissions --- backend/substrapp/views/utils.py | 9 +++- scripts/generate_nodes_fixtures.py | 72 ------------------------------ 2 files changed, 8 insertions(+), 73 deletions(-) delete mode 100644 scripts/generate_nodes_fixtures.py diff --git a/backend/substrapp/views/utils.py b/backend/substrapp/views/utils.py index e4c7f95ac..19e8b23d0 100644 --- a/backend/substrapp/views/utils.py +++ b/backend/substrapp/views/utils.py @@ -7,6 +7,7 @@ from rest_framework.response import Response from libs.sessionAuthentication import CustomSessionAuthentication +from node.authentication import NodeUser from substrapp.ledger_utils import get_object_from_ledger, LedgerError from substrapp.utils import NodeError, get_remote_file, get_owner, get_remote_file_content from node.models import OutgoingNode @@ -68,7 +69,13 @@ def _has_access(self, user, asset): if permission['public']: return True - node_id = user.username + if isinstance(user, NodeUser): + node_id = user.username + else: + # for classic user test on current msp id + LEDGER = getattr(settings, 'LEDGER') + node_id = LEDGER['client']['msp_id'] + return node_id in permission['authorizedIDs'] def download_file(self, request, django_field, ledger_field=None): diff --git a/scripts/generate_nodes_fixtures.py b/scripts/generate_nodes_fixtures.py deleted file mode 100644 index 6eab4b10d..000000000 --- a/scripts/generate_nodes_fixtures.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -import collections -import json -import os -import secrets -import yaml - - -def create_random_secret(): - return secrets.token_hex(64) - - -def generate_network_credentials(nodes): - node_ids = [node_id for name, node_id in nodes] - network_creds = collections.defaultdict(dict) - - # generate random outgoing credentials for all nodes - for node_name, node_id in nodes: - network_creds[node_id]['name'] = node_name - network_creds[node_id]['outgoing'] = { - other_id: create_random_secret() - for other_id in node_ids - } - - # parse outgoing credentials to set incoming credentials - for node_id, node_creds in network_creds.items(): - node_creds['incoming'] = { - other_id: network_creds[other_id]['outgoing'][node_id] - for other_id in node_ids - } - - return network_creds - - -def create_fixture(node_credentials): - data = [] - for pk, v in node_credentials['outgoing'].items(): - data.append({ - 'model': 'node.outgoingnode', - 'pk': pk, - 'fields': {'secret': v}, - }) - for pk, v in node_credentials['incoming'].items(): - data.append({ - 'model': 'node.incomingnode', - 'pk': pk, - 'fields': {'secret': v}, - }) - return data - - -if __name__ == '__main__': - node_ids = [ - ('chunantes', 'chu-nantesMSP'), - ('owkin', 'owkinMSP'), - ('clb', 'clbMSP'), - ] - # generate credentials - network_credentials = generate_network_credentials(node_ids) - print(json.dumps(network_credentials, sort_keys=True, indent=4)) - - # create fixture files - fixtures_path = 'backend/node/fixtures' - try: - os.makedirs(fixtures_path) - except OSError: - pass - for node_id, node_credentials in network_credentials.items(): - data = create_fixture(node_credentials) - node_name = node_credentials['name'] - with open(os.path.join(fixtures_path, f'nodes-{node_name}.yaml'), 'w') as f: - f.write(yaml.dump(data)) From b42c581e5942e2ed3db9497d67df4aa67f2f756a Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 29 Oct 2019 07:54:16 +0100 Subject: [PATCH 449/457] Fix docker copy --- docker/substra-backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/substra-backend/Dockerfile b/docker/substra-backend/Dockerfile index 08dd0ed2c..12dab083f 100644 --- a/docker/substra-backend/Dockerfile +++ b/docker/substra-backend/Dockerfile @@ -18,4 +18,4 @@ COPY ./backend/events /usr/src/app/events COPY ./backend/backend /usr/src/app/backend COPY ./backend/node /usr/src/app/node COPY ./backend/node-register /usr/src/app/node-register -COPY ./backend/user /usr/src/app/user +COPY ./backend/users /usr/src/app/users From dbf85e10c856420524fe96a979e595ae84cd948f Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 29 Oct 2019 08:24:59 +0100 Subject: [PATCH 450/457] Fix celeryworker docker after rebase --- docker/celeryworker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/celeryworker/Dockerfile b/docker/celeryworker/Dockerfile index c31a69058..939d2d69f 100644 --- a/docker/celeryworker/Dockerfile +++ b/docker/celeryworker/Dockerfile @@ -13,6 +13,6 @@ RUN pip3 install -r requirements.txt COPY ./backend/libs /usr/src/app/libs COPY ./backend/substrapp /usr/src/app/substrapp -COPY ./backend/backend /usr/src/app/bac +COPY ./backend/backend /usr/src/app/backend COPY ./backend/node /usr/src/app/node COPY ./backend/users /usr/src/app/users From a57f7b640fd0430ca74b81e86eae52147399b6c4 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 29 Oct 2019 08:34:22 +0100 Subject: [PATCH 451/457] Update README --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d851b77e..f3aca1030 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,7 @@ Then, build the images: $> sh build-docker-images.sh ``` -Then, go to the`docker` dir and run `start.py` (`-d` means `dev` settings): +Then, go to the `docker` dir and run `start.py` (`-d` means `dev` settings): ```bash $> python start.py -d --no-backup ``` @@ -254,7 +254,9 @@ Check your services are correctly started with `docker ps -a`. ## Expiry token period -An global environment variable `ACCESS_TOKEN_LIFETIME` expressed in minutes can be set for dealing with expiry token period. +Two global environment variables `ACCESS_TOKEN_LIFETIME` and `EXPIRY_TOKEN_LIFETIME` expressed in minutes can be set for dealing with expiry token period. +The first one `ACCESS_TOKEN_LIFETIME` deals with JWT Authentication. +THe second one `EXPIRY_TOKEN_LIFETIME` deals with simple token expiration. By default, set to 24*60 min i.e 24h. ## Testing fabric-sdk-py From f221117aeeab4ea2c4e5adc2e6ef5517a02bd623 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 29 Oct 2019 14:34:29 +0100 Subject: [PATCH 452/457] Update skaffold files --- charts/substra-backend/values.yaml | 6 +++--- populate.py | 8 ++++---- skaffold.yaml | 18 +++++------------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/charts/substra-backend/values.yaml b/charts/substra-backend/values.yaml index 9db48db30..a7a45615d 100644 --- a/charts/substra-backend/values.yaml +++ b/charts/substra-backend/values.yaml @@ -70,9 +70,9 @@ incomingNodes: [] # - name: nodeId # secret: nodeSecret -users: [] - # - name: username - # secret: userSecret +users: + - name: "substra" + secret: "p@$swr0d44" persistence: hostPath: "/substra" diff --git a/populate.py b/populate.py index d151de142..8658dbe0a 100644 --- a/populate.py +++ b/populate.py @@ -28,17 +28,17 @@ def setup_config(network='docker'): print('Init config for owkin and chunantes') + USER, PASSWORD = ('substra', 'p@$swr0d44') if network == 'docker': - USER, PASSWORD = ('substra', 'p@$swr0d44') # get first available user client.add_profile('owkin', USER, PASSWORD, 'http://substra-backend.owkin.xyz:8000', '0.0') client.add_profile('chunantes', USER, PASSWORD, 'http://substra-backend.chunantes.xyz:8001', '0.0') client.add_profile('clb', USER, PASSWORD, 'http://substra-backend.clb.xyz:8002', '0.0') if network == 'skaffold': # the usernames and passwords are defined in the skaffold.yaml file - client.add_profile('owkin', 'node-1', 'node-1pwd', 'http://substra-backend.node-1.com', '0.0') - client.add_profile('chunantes', 'node-2', 'node-2pwd', 'http://substra-backend.node-2.com', '0.0') - client.add_profile('clb', 'node-3', 'node-3pwd', 'http://substra-backend.node-3.com', '0.0') + client.add_profile('owkin', USER, PASSWORD, 'http://substra-backend.node-1.com', '0.0') + client.add_profile('chunantes', USER, PASSWORD, 'http://substra-backend.node-2.com', '0.0') + client.add_profile('clb', USER, PASSWORD, 'http://substra-backend.node-3.com', '0.0') def zip_folder(path, destination): diff --git a/skaffold.yaml b/skaffold.yaml index e819de845..7fd90630a 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -40,19 +40,15 @@ deploy: fabricConfigmap: network-peer-1-hlf-k8s-fabric backend: settings: dev - defaultDomain: http://substra-backend.node-1 + defaultDomain: http://substra-backend.node-1.com ingress: enabled: true hosts: - - { host: substra-backend.node-1, paths: ["/"] } + - { host: substra-backend.node-1.com, paths: ["/"] } annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/client-body-buffer-size: 100m nginx.ingress.kubernetes.io/proxy-body-size: 100m - auth: - user: node-1 - password: node-1pwd - header: "Basic bm9kZS0xOm5vZGUtMXB3ZA==" organization: name: MyPeer1 peer: @@ -87,21 +83,17 @@ deploy: fabricConfigmap: network-peer-2-hlf-k8s-fabric backend: settings: dev - defaultDomain: http://substra-backend.node-2 + defaultDomain: http://substra-backend.node-2.com ingress: enabled: true hosts: - - { host: substra-backend.node-2, paths: ["/"] } + - { host: substra-backend.node-2.com, paths: ["/"] } annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/client-body-buffer-size: 100m nginx.ingress.kubernetes.io/proxy-body-size: 100m - auth: - user: node-2 - password: node-2pwd - header: "Basic bm9kZS0yOm5vZGUtMnB3ZA==" organization: - name: MyPeer1 + name: MyPeer2 peer: host: network-peer-2.peer-2 port: 7051 From bdac12949ff13565982570a761fc5e0e8ca2ef0e Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 29 Oct 2019 16:36:22 +0100 Subject: [PATCH 453/457] clean after review --- backend/substrapp/tests/common.py | 9 ++++----- backend/substrapp/tests/views/tests_views_algo.py | 4 ++-- backend/substrapp/views/utils.py | 12 ++++-------- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 76ce9d074..58da8d32b 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -30,11 +30,10 @@ def request(self, **kwargs): # create user username = 'substra' password = 'p@$swr0d44' - try: - with transaction.atomic(): - User.objects.create_user(username=username, password=password) - except Exception: - pass + user, created = User.objects.get_or_create(username=username) + if created: + user.set_password(password) + user.save() # simulate login serializer = CustomTokenObtainPairSerializer(data={ 'username': username, diff --git a/backend/substrapp/tests/views/tests_views_algo.py b/backend/substrapp/tests/views/tests_views_algo.py index 9fd6ade20..adaa9abe6 100644 --- a/backend/substrapp/tests/views/tests_views_algo.py +++ b/backend/substrapp/tests/views/tests_views_algo.py @@ -95,8 +95,8 @@ def test_algo_list_filter_dual(self): with mock.patch('substrapp.views.algo.query_ledger') as mquery_ledger: mquery_ledger.return_value = algo - search_params = f'?search=algo%253Aname%253A{urllib.parse.quote(algo[0]["name"])}' - search_params += f'%2Calgo%253Aowner%253A{algo[0]["owner"]}' + search_params = f'?search=algo%253Aname%253A{urllib.parse.quote(algo[2]["name"])}' + search_params += f'%2Calgo%253Aowner%253A{algo[2]["owner"]}' response = self.client.get(url + search_params, **self.extra) r = response.json() diff --git a/backend/substrapp/views/utils.py b/backend/substrapp/views/utils.py index 19e8b23d0..77941737d 100644 --- a/backend/substrapp/views/utils.py +++ b/backend/substrapp/views/utils.py @@ -66,17 +66,13 @@ def _has_access(self, user, asset): return False permission = asset['permissions']['process'] - if permission['public']: - return True - if isinstance(user, NodeUser): + if isinstance(user, NodeUser): # for node node_id = user.username - else: - # for classic user test on current msp id - LEDGER = getattr(settings, 'LEDGER') - node_id = LEDGER['client']['msp_id'] + else: # for classic user, test on current msp id + node_id = get_owner() - return node_id in permission['authorizedIDs'] + return permission['public'] or node_id in permission['authorizedIDs'] def download_file(self, request, django_field, ledger_field=None): lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field From 5be7c3ccb4022403a9b2c234831dd01da67d32d7 Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 30 Oct 2019 11:57:42 +0100 Subject: [PATCH 454/457] Use different password --- charts/substra-backend/values.yaml | 6 +++--- docker/start.py | 20 ++++++++++++++++++-- populate.py | 13 ++++++------- skaffold.yaml | 6 ++++++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/charts/substra-backend/values.yaml b/charts/substra-backend/values.yaml index a7a45615d..841935870 100644 --- a/charts/substra-backend/values.yaml +++ b/charts/substra-backend/values.yaml @@ -70,9 +70,9 @@ incomingNodes: [] # - name: nodeId # secret: nodeSecret -users: - - name: "substra" - secret: "p@$swr0d44" +users: [] +# - name: username +# secret: password persistence: hostPath: "/substra" diff --git a/docker/start.py b/docker/start.py index af1f0b7b8..589837d2e 100644 --- a/docker/start.py +++ b/docker/start.py @@ -19,6 +19,21 @@ 'clb': 8002 } +BACKEND_CREDENTIALS = { + 'owkin': { + 'username': 'substra', + 'password': 'p@$swr0d44' + }, + 'chunantes': { + 'username': 'substra', + 'password': 'p@$swr0d45' + }, + 'clb': { + 'username': 'substra', + 'password': 'p@$swr0d46' + } +} + SUBSTRA_FOLDER = os.getenv('SUBSTRA_PATH', '/substra') @@ -116,6 +131,7 @@ def generate_docker_compose_file(conf, launch_settings): org_name_stripped = org_name.replace('-', '') port = BACKEND_PORT[org_name_stripped] + credentials = BACKEND_CREDENTIALS[org_name_stripped] cpu_count = os.cpu_count() processes = 2 * int(cpu_count) + 1 @@ -165,8 +181,8 @@ def generate_docker_compose_file(conf, launch_settings): user_command = '' if launch_settings == 'dev': fixtures_command = f"python manage.py init_nodes ./node/nodes/{org_name}MSP.json" - # replace needed for docker-compose special variable - user_command = f"python manage.py add_user substra '{'p@$swr0d44'.replace('$', '$$')}'" + # $ replace is needed for docker-compose $ special variable + user_command = f"python manage.py add_user {credentials['username']} '{credentials['password'].replace('$', '$$')}'" backend = { 'container_name': f'substra-backend.{org_name_stripped}.xyz', diff --git a/populate.py b/populate.py index 8658dbe0a..992be8973 100644 --- a/populate.py +++ b/populate.py @@ -28,17 +28,16 @@ def setup_config(network='docker'): print('Init config for owkin and chunantes') - USER, PASSWORD = ('substra', 'p@$swr0d44') if network == 'docker': # get first available user - client.add_profile('owkin', USER, PASSWORD, 'http://substra-backend.owkin.xyz:8000', '0.0') - client.add_profile('chunantes', USER, PASSWORD, 'http://substra-backend.chunantes.xyz:8001', '0.0') - client.add_profile('clb', USER, PASSWORD, 'http://substra-backend.clb.xyz:8002', '0.0') + client.add_profile('owkin', 'substra', 'p@$swr0d44', 'http://substra-backend.owkin.xyz:8000', '0.0') + client.add_profile('chunantes', 'substra', 'p@$swr0d45', 'http://substra-backend.chunantes.xyz:8001', '0.0') + client.add_profile('clb', 'substra', 'p@$swr0d46', 'http://substra-backend.clb.xyz:8002', '0.0') if network == 'skaffold': # the usernames and passwords are defined in the skaffold.yaml file - client.add_profile('owkin', USER, PASSWORD, 'http://substra-backend.node-1.com', '0.0') - client.add_profile('chunantes', USER, PASSWORD, 'http://substra-backend.node-2.com', '0.0') - client.add_profile('clb', USER, PASSWORD, 'http://substra-backend.node-3.com', '0.0') + client.add_profile('owkin', 'node-1', 'p@$swr0d44', 'http://substra-backend.node-1.com', '0.0') + client.add_profile('chunantes', 'node-2', 'p@$swr0d45', 'http://substra-backend.node-2.com', '0.0') + client.add_profile('clb', 'node-3', 'p@$swr0d46', 'http://substra-backend.node-3.com', '0.0') def zip_folder(path, destination): diff --git a/skaffold.yaml b/skaffold.yaml index 7fd90630a..47472d650 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -67,6 +67,9 @@ deploy: outgoingNodes: - { name: MyPeer1MSP, secret: selfSecret1 } - { name: MyPeer2MSP, secret: nodeSecret1 } + users: + - name: "node-1" + secret: "p@$swr0d44" - name: substra-backend-peer-2 chartPath: charts/substra-backend @@ -110,3 +113,6 @@ deploy: outgoingNodes: - { name: MyPeer1MSP, secret: nodeSecret2 } - { name: MyPeer2MSP, secret: selfSecret2 } + users: + - name: "node-2" + secret: "p@$swr0d45" From c374dddb4adb3708482c9e6ea876f02f834454ac Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Wed, 30 Oct 2019 15:13:11 +0100 Subject: [PATCH 455/457] use explicit password fro node to node communication --- skaffold.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/skaffold.yaml b/skaffold.yaml index 47472d650..a142de5f5 100644 --- a/skaffold.yaml +++ b/skaffold.yaml @@ -63,10 +63,10 @@ deploy: hostPath: /tmp/peer-1 incomingNodes: - { name: MyPeer1MSP, secret: selfSecret1 } - - { name: MyPeer2MSP, secret: nodeSecret2 } + - { name: MyPeer2MSP, secret: nodeSecret1w2 } outgoingNodes: - { name: MyPeer1MSP, secret: selfSecret1 } - - { name: MyPeer2MSP, secret: nodeSecret1 } + - { name: MyPeer2MSP, secret: nodeSecret2w1 } users: - name: "node-1" secret: "p@$swr0d44" @@ -108,10 +108,10 @@ deploy: persistence: hostPath: /tmp/peer-2 incomingNodes: - - { name: MyPeer1MSP, secret: nodeSecret1 } + - { name: MyPeer1MSP, secret: nodeSecret2w1 } - { name: MyPeer2MSP, secret: selfSecret2 } outgoingNodes: - - { name: MyPeer1MSP, secret: nodeSecret2 } + - { name: MyPeer1MSP, secret: nodeSecret1w2 } - { name: MyPeer2MSP, secret: selfSecret2 } users: - name: "node-2" From d201b36c7bd275bc061d2f16d2b6634e63f6b1ce Mon Sep 17 00:00:00 2001 From: Kelvin Moutet Date: Tue, 5 Nov 2019 11:43:14 +0100 Subject: [PATCH 456/457] Fix flake 8 errors. --- backend/node/generate_nodes.py | 1 - backend/substrapp/tests/common.py | 1 - docker/start.py | 3 ++- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/node/generate_nodes.py b/backend/node/generate_nodes.py index f46cb44d9..d1c336048 100755 --- a/backend/node/generate_nodes.py +++ b/backend/node/generate_nodes.py @@ -62,4 +62,3 @@ def generate_for_orgs(orgs): orgs = ['owkinMSP', 'chu-nantesMSP', 'clbMSP'] # TODO should be discovered by discovery service generate_for_orgs(orgs) - diff --git a/backend/substrapp/tests/common.py b/backend/substrapp/tests/common.py index 58da8d32b..bc72d2abd 100644 --- a/backend/substrapp/tests/common.py +++ b/backend/substrapp/tests/common.py @@ -6,7 +6,6 @@ from django.contrib.auth.models import User from django.core.files.uploadedfile import InMemoryUploadedFile -from django.db import transaction from rest_framework.test import APIClient diff --git a/docker/start.py b/docker/start.py index 589837d2e..a96a2b883 100644 --- a/docker/start.py +++ b/docker/start.py @@ -182,7 +182,8 @@ def generate_docker_compose_file(conf, launch_settings): if launch_settings == 'dev': fixtures_command = f"python manage.py init_nodes ./node/nodes/{org_name}MSP.json" # $ replace is needed for docker-compose $ special variable - user_command = f"python manage.py add_user {credentials['username']} '{credentials['password'].replace('$', '$$')}'" + user_command = f"python manage.py add_user {credentials['username']} "\ + f"'{credentials['password'].replace('$', '$$')}'" backend = { 'container_name': f'substra-backend.{org_name_stripped}.xyz', From 33b2459470b613cade52edc0eec3cb0b05e2311a Mon Sep 17 00:00:00 2001 From: GuillaumeCisco Date: Tue, 5 Nov 2019 11:57:41 +0100 Subject: [PATCH 457/457] Add medias to flake8 --- .flake8 | 1 + 1 file changed, 1 insertion(+) diff --git a/.flake8 b/.flake8 index 7a28d7359..69a7abe71 100644 --- a/.flake8 +++ b/.flake8 @@ -5,4 +5,5 @@ exclude = backend/substrapp/migrations/*, backend/substrapp/tests/assets.py, backend/backend/settings/*, backend/node/migrations/*, + backend/medias/*, .env, .venv

        =Dkch^E)5ucM0ObJ_dWS z{43$-TN1a{EpllZ_={Di-?S*O^kpjr=$Z;X;CVy`0qeFt?c1*J_slt9tS|?>PRkkf z#d_$y3|}ZV%sc`a#pToYHvEX(jtz%bn(awp2VVP|m(}jewLY@KgZc@E^hl)@ntli% zQ0gmKklYwqKIao7wH33l~06GhJ$;Pb>ygA4zCk4;@B4 z-!c=UA^@oMv3Qm)rChSh&4Qqx#q{UeF0$$C5~YrD$TgQ^nEQZl_y5YeeSv}I?K z_V=+Ko|4-c6vtwczU{M`eMc{D@r0Pphnac!QhX==kr&JM??Rpr7q(NVV31~YmFEi1 zkcdyHOdL7;|6Tt=J8oe%4Au$uJzMCxc-_HCOuKnRb><{J5et}BQlKeZZC2HD*$i9$ z!B#uLx3kxbjJwP)CfkzLmXQ{}7U9!mvP!=K&6(q(DW$rPyxenr;HCCi9K7L-riHS; z1`)b6D;~brVK}j7KjTLfCRNj}G*oL7P(c|rep(yGD6&b3$s`rmhWX*?=$DJ_gkiZG zT|OQbYjRcnbS|u2l9ok6;pj~bN@xa=TedR$O`3Z?<2U37xo*`<>aNvK5G5)f2?QLu z8!heYc7Dwd8r{E_g<|SM(JJ<3g1=MjIP+A3m+0IuBsZQ<+jcSMIXw`f7y2{4R=-(% zWcpQb{LPZPpI}?vh)D+lwhE~8Wfg8OSEjV$bN>_UmG1c=6!{K@Ck@+7H66u@KVuKF zHOT$FWv4!mF}f5%k+}HCSn$ zo%DD*Z#o#(sdy%aqkjr5{J=9^@R4zz|HFmDp!lM1vey7)B&EF+M;P^nv`Z4c>6c9( z)ml0Pr8GL~uTbF3_JqWXrNpQ2LwY_KS|=yU75vEk$wM!A&6A3KMnA!4#M8MVqY=kB zIs;Q?F0;wZQ+E$f(#Dzpul#PuP4j?Nh~3J1t1ydtA<0toj%V%QSEz@FKWW-rjkOnp z2ge-z=$Ls|ZJgxpl zG2`41NG`XjlEbJ?@JFmb*{jnbH=p*Xm?02})b67gbmnU1HnFGvef`L!L8x$;ly^tm zGfLc>!j&s{6AWi?Q7I0(>o8Uh_oL#hbfCS$iAzf|5PQZI>xmGh4MpgT z{<~5|P_QK@i)%kFV|UF{ZyJ>uR(1a~94|Zpf0#mk8Kt~@R)mI`+E8FS;YUG_bhgVc zm&ufyi3^MQ%xP*_h2<0^CjgYykv;T2Q6@bC39X~iwFCu-@4 z3SFCD&EAlu8lL^c76Q?=!>+RRy_Yd&@qku}rCl~I=Umca#F9y;^IdNKMxZl&po`yn zp^WiWUZ~8g1-e=;Ni%S#DfC8NiCArq2z%Pa)3Fuvub93tUxl^d@}ZgJI8b9=V1znR z9XBUbDt<>fOJL8!R8=>$WAOQVmP3b}-I4BV*d3PcK=RpVu?jt@I<~M&yrfEtrl!`O zS#G4$H~6#j%FV76>2w~iM0#SiKED9=VWpQEQk@uUeBA&bQH5J!i@T!FR%o)@%(Atn zPh!cKW!yDwWM3_SbrI@dnKUx#MKvQ0=7LDmJ8v1KTWRS|dHpc&*sg6en>18RulKeI zcsxj4c>9Y-%pN*^Zapz6JX{yiTgGT-bx*}G=iO1hrKDNEP(Vmx`=ni@g<}2&mk=1dWUom`! za=1G$5ce{X#AY)cJ-WH}bc@B(3f8C${$o1H|HE{84aP;hrIh(F_aB`qa3rrL&k2vN zn8Stg357_~h<9-6y=e8jI#2w?3plvhm@0E4CiF32{!{o+BcqFe|yX_$L+1N zkOaA4x%Xb+sOu7s0Lk;QjsGEdnXadnr_1L0E867ZiHf*!#VF9|lhKf*UxXATGyXur zJe--$@=_8oTAgK@`BO`W|3NWnBZ!3;;Us;&6icO zb4r08sN8Fy&CCA_KSKyawufH1f$e%f!5aED`ytXDBr_*VK`aj^Xk(q>yeL0@+L=U$ z+i|BhRs@xzK^j+fmnX-YQclxMFDH6`Df{y?JV;NsDG^?Qb|_>5(|$d_NiEdaULXmd0K@WVUz?xPrt7!8 zU)SnG`+Wp=QY?RGNPCC1gTwJm_#~_nO#6$`ZiWes!Mc!Xz@iUwro-7FZiHy6!rDkC z8KCi{M6vt$(^Ir|{$rZ0F;F{&hk={F0`vIS^`zYipKi?UE>hcq)teu6R2>d)ijLQM zfd{PkN(TQYHwf}D4ugQW0bcamClu6G@jy`t&N5<_86d(5zJg_l{)k7Eiuurl`_zz}X$h)Q zaj%HG<^t?oH1WW}wCktd54`8@jR_|IQwtzf_u{}}la87Fj(@N6=fep)oXS(cKLDCs zM||0Al0)QC+M-zG6QY)q^~T;knKx>5g1$=9`P=FbJ5-o_F}mITLVsMXk#K=cm;2e{ ziRVQx>TH<7QSZp7;@f8Ei_PrzUC?02afp3mh3*>CpP}58$@!#URN?}c(bhCf$rdxHa#*lntcL(LKjtEVcRf2vYK=c>r?2u^Sz`WAZIAzZBa*GyvBjVNZq_0wH`j+sQ2GMdA{3H(`+0VDrriPLZtcCF zP`Xmi9@{`zBou2H{CA{~BpJQWWQkKYfn4a9N59Oi5 z_~LWg+C!T$(aCa+KnsFD#iU=-t;pEEKpwP{Q|^^yv1gOH#^pizN7jKrvM` z)$|8_f+UhJk_qja&Ci7L-0@NOU<6g7z0Z~X#2s+ku4c<;b=P=h(c9CsDbg+H>lU$W_`Ru%4U6*3n2o%{)WNko6#7aho6HP8s&s!R2O zVQ=sJ{LdjML@l+llCh$q!s5);(ecAKGBPU&@xSFZOLg#cz!6w@cz6N=$2ibp9EpnN z-K19FGEfj{d9|;S{^}NjM;AS@A%FofhViF>H&N8xt{3r@Cr^z2+Q*o?y*l`B zS4?q&i=wMwe(G#e$o$ZXhhEW_hG;u6avymDoARphQ_&RD^O_SGyvmuFw8Q<1Xd6IJ zL2b#B=&=Y;@PRJ|APlxStuuU_|D`G=n9)$DXW8&p-c-rAJ%ReaSCEnyFAbpnzO;nP*+uWSfM?OpKR zWsVU`5c7_j8Olm)AdmG1*!&{y@z>ipTtAG@qkNk@4GBt;*o=I;-GV>PoX`KZ$x=oMq=W(x5$ z`tBoVWb1_QF;gRZJs+W6m_8W$94US^z4Vff+#)(%WhC>qz7X z3!Tho+lu>moBn&7&%|B1cDB2v3~y%V9ouPTOK?$dXL+)BYfi!%CXFWN?XVwlhcR$z zvbQoTuZo)b0}*PzLO+TBI~cDZhHDbtP#0Jut;NH#CaB3XO%_N3TY0`82Pz!$8gCwN zJ`dR0+0lkJOgjkH`^9A=2JB9ZZ}W54a=i997pJ&Al}OvWDaKT(1AgsqoMF-sXq`z$ z=DcNvG!uy^UxF$XF-bhz2d0!#0u8V7=a-?WYBgR>jxgirFn{3Oa8jn7%;sXp>fzE~ z>X)m0X-9QQy2jsJ*`4@fJkazv0gr)zz`0&+CK3T)+#$+{)4y&ojU zB5v-h6c0NaGsz7PzTe-RdDnEUbcng;{mKP5Ww>I#w484I_P4Gr>za4!GJz3yw)k^Q zy(QC8BT`-Haq4gQ0Fy-XI<4bwZ%cZ?b-(n#g z;Q-^t!YNcRgOzzSiy6NL(mR=zAtYVM@EouByqIZY;KQ=`y38|E&a2pX-`5C+#7p&{ z5;{Zzvq%H=_M?1+(D$)`4m8uotxEw3ZFBW-nYS)YYNtI~$BbBQ<0(87?#uj69^3et zhjZy-H>GHbwdM~wYyoW6vLf~G+E%qMFDhl~f2bi{nn^J6gckM;55Q?@Ew5{)p>!XKB2Gq_*&Q2qjavZyfCf1>0e!wpFE;!qEx1E>dE%RLHUeSG6xHZa$sc zH2rycRJUBsPv0jnn#eCLsAL2%C$|bvpEf7Vo2f9JE~^Z_@em#Dh*bxwR) zB4;q&d|i%1;3jx9`A(UJQlM8ve@el)^|0hpms*zq!^|u)K_ui$bJs)TGkZN3T915i0;TX+QwdrPTrGn|#)%&TDOn1c-FD;yRRv8T69XR~W%NMn%Xc-G zDwKP&gS2)rQ^QsfAQ?W0*zGoiw*B7XjyrbSKLmD|xC@u$CQN zo!H0!*i4m)52E!bAdsLmK!I|zpZp-=N}+cKdL~V3cHjLnopx>{w0^gc0DCZTvE6kB z{Iig7_@vb2zWo6{sZEO3PK(E@+E49har$<lCcsXJ`*?K7rr`C6M})5SJxV5v{YqR9G+Bssy?F6MTS;N2-C6;YgJV$OdoZ zF*kg_s~cbWbEPFoEnpL}BhqC=dYF8{3dlv&-A5Ts8@a?H#Zm5`;WCBHm$559=;KQk zOO|=E#1-eRn*p%0c`du$#|@8(FR!y26IS7)s<&+@O{0cr^}_JOgTI^{`v=!zE1YL! zgG;x~&5UeMkjNO*#t}*d_-;Z9FUvI}BGPU*I3wN;c>L%40jEps44F%PuJSW|b6f4Y zHTQry4@)0(*{NB`Ge0;e#b1nxRL(BPR%yR^0Z^Qk0XwgD$gF?%NO#lh{FGBmQl`pY z7kul$=Tl!_{dD$24$Wa6`019x`!{}5gB^GHTl23;P{j6g^@jYo@veY3t%V@Ik5*4C zd1sB=BJoM6{KON>EfT(2rT)lS=VH|>sw#t4cj7cBb8>mDIv+PR!BSJYUJ{+rVhuUn z@|QH;X76JhD{NcR!`n{orD^Nr#?Yo`DOSm)*39)J`pqOgZ?olMl0Bsfxq5a;UT-H?wvIgH+U^O=Zy!r6UfX>v-HK{vZC+8 zNE4OwKG3o@sF(>|OOWs>`(lsjy2Vt~>Y2KariqAtPzUQDa4mUYuO-igdB{inO%S)` zwWZHAwNDtJ)6D3bR3INwpObU%D=0WZOl!LLgB89Zj!)Kf5}R1l6s;)Q_) zU3IQ_drHh-SZ?Y-N}*+ zyT6}qnBB-1Mz=Uj@+53gvlEV6nLG;{p2nBoP6<6b(gdA|vy)mX$3AAzV z;aiq3jqj@UQm?bWb4TKA@`fSE$OtP(pnBn>mXgmrdO^rFv)OyYbL|rVzyq+fb4Dnm zx2&$5$HU-^D41D#&@sQg!*QY}u&o zFjo_x)QNw^1|C+>YHA!A=QVlP@Q$i(HMf8O>}9pHxUYg4dD*N5x{l zMwW|m!-s2&11}zMbqswFK69D2X9(iou?uzuN{mQxe4k_-VZz5dL}8eN+FEAyEAoI> zmg3v?!^|FzeZtZ02jRA>TkN`|g|D2ukVZ*E?2xc!?I*4y8vgZeDH}CuIll`@OBZp)hKB0xFEf_6tNVEbO{kyl7%sGEy!oFu5ED~Q9&P(VX zeHD5&$!gAOK4&Cph-b9JkmZN#WDO}vx~sN5RYl2Y6=_++^E5+!E@8_TKbMdKnkg-D z{mm|7=kkD4YLrE7VY?XMdFxVqG?xV03HFpfh&`G%4bKsG80*cN;jDMdt5)-$)PdU+ ze3%xeQ7<)=tRNt@y2o?Xz>vys^Ae-GmjM`=L$zE2=+4TY-h_ZH=)fty*m8MLtzq)= z>V8_Yo=rS@f>dB`E-4fz*cDhrVu8l#Zd64V_)H1NcI+ZXr@rB(FsaXKE}ohwr@=2> z57us#$fqu&`>s0j-X|xPd;NNWg^gz2eSzhK4aRW^Ha~n0Ns_ETe7d4>^DIX}`W_;! zEdds$^7V@=mHz2&g*@lJORv;$)spuy7J$OC8xtf$doR*QpAj`){Lq;&Fuk0+5c~l% zQ$QD%_?vR(y<2xaBK3g-mBK)c%P=j60-nm>@WzHle!IXi5Dja=hTIGNUO!wu}UBp}->G=hCB8PX_Itq9a@z$>J4t%s_+QAO|RTVQ6FoIY&iBHCw1Mppp`O zpS~iU^a-yK8@tgsNfk#8r7+k%}Ge zw`3ob07wGxlri?|RRl(tCtjBhrE}XT99e}$#NASS=1pSuIs9PlMKM_&JM2VEA1a?Q zwC0G1a=9@@q&t*aHV!1z$c!u3bgWZV*IF%oq_1*pixHH*^PLQtE{|VDfjs z>p>g0zs=t6)V6=w`kP(j3R+&qXXFevj5Eo$U`htTyzT5Kh-5;yFO$*8q@r7dMS6GE1qu2^o>wZ#MsYb1%v-O^LV2 z2Mdo3bLEJDI-di!-X9*iBe=CZ@Pym@*3X*ww0TvY3CgIYAswd~mLa*ng12Wsw8)?1-HnKHp69p=m`J zOVm$wu>Fm9s4W!hlpK9KW*SP8yIPhAZ0^l8`We>U11Q`Et~~e!-nKycGT`k5?UW0S zIJnnfDaTK4Oeo++<2heeK1@2Y+_(udu?aL{0)o+nY9obGS?&2Z=P(55KEAYsf}O>LcZ)N=EvwvDwmRC} z)9E|3yxwt9et}&}PNas-m+WPU3a==9cwsKAjh?fZrk(lZMqPwhU#dEoaWdX1k6au| zwsxKE64#>aSSMy<5?t$Qa>Q9~;^7R4F})g)+!m6k6$>b4jC148Ht|M{RmVoIITIOG@_-$&FSTRaW8k3cBePUi?%?Gasqw*7T3tlzbU$;-KJg z_}BWDi=(?raLr`m*8)e%6?fZ+DaS~RNXDbB4@8Ja+2{X{&sGH)DWEOKM(;TQNnj78w4YMyM&QTCNi(i7rb&~~d zdT9|323vdp+BEF;D@OfwX=xy)TBLPh+wa>4ZOF+O^Km|_&rz?C`VHw05u?9%>G&_s zRPnyY@uo?d5ole+Qb5lt=l0WbzM`=p`=o$?y*Jm9>l05E%MEb8k^RSK+okMS4m_iN zuYCeO9@m~SUvZ_@sliLn`5rCOx+8iJ%|~xOsO{SK6oEUzcEb#_$P#I*cu(x%xw&%D zo){j1Q;WMgXm#Hy%b|N(oA`AH=XzYW9jRPJ@~#~3ORtT=-EcJH#S<;z(>+;=rg;w zrFC)V*sYR3lpb1huwovTe#vh_*c{gNbFA9^{HnWn55eOLNNY`J&9n5 zG6H)!8#}tn>XE!_5l5H<2D_sjXD7e2J}McVJKF07@E4=cvm4mk35VZ@hm9?vydJC3 z9Hs;hV0olIrbQpZ4jt@d0K_M!ppAL_nrpV*>EaUtAG4N;PI8E^<%=r3T&?<&H`5P`p}Q7 z{Jo4S%5%}`J0fYObkjUHP<_aQ)y8)=CD4x-tV)#5Q|~s_QDfjKL#6btOjGF!cK$9d z6>g^Y#%G_j$%uup?j#3}fLcdU789W_x}$_*($ZAUN#ToHgbAPKC1`b#aK}nE28DH- z1XmJV?R2g-XB|+qp=&mhMzL@96(F$ar{U-RPL)n2ieI;OR(~%tCCDogvvk>3% z{-kokt`!_v`GrWOaJ?O3rTa_Y01S~<8ZS)v!Eh_h_)dneGDaW0)*y|}Fpf$;ni!Vu(alrnD3)`U z+r>b{_;zg*4PQltoAU#}QM3}8V86pApuHZ7J5gfhklB9`_E+1}KL3ah?PuU9pqV35 zZXUnelwtAOds&0kY8HSbw6{4|Bj4446pk0|b5D1A2gngP4Q93FPv9?gA<3!JWz|?9 zDjXYUmb#^>Z8T2eKqZ611-+6U+7SoWB8o9Kd2Am4nX;$NE8Abh7uj4ov&Ek6K!P~S zP%`HQte*xm+MZ%LIeeI~cX?4Npbev{OApMr7nxSyzsHt!X77a7xwL07O4|auddM%& zV_>Q3;Qq(JtC!P5-yHo$evrQD9rWc zm0ab&X@_~p%cN;E#_+RQ8JUK|6_S)1@!F3qj1J{TsJGpH07Pl5Ou~TC%*z$W@y(qb zC$U}7F}kN1ev^pkYavcd`Tf$%c`;Ab9-m1&a+`E)XckqPnZOjeembEUj{H|Y~-cfy!CYcxKFH(rC*E+ zYdkJyQKqb{z-Fs_>N z-Jz9`Ht*S$61urHr*UUMHbT>l*iZ#Z$q?VS&E0H2W z>_)z1dt*vlS`)1!mgm}a?APRK(a4!(F~wabK40$-nVM6`-Wc zO4pUPHS+&(0jff1g6Pcx2rFpcr^@kYb1AO2({snZ<|yl_x_q(O*zM~btJxZiwVZOV zsS};~>Q35X#AbZ_+or9t4euO>#&9Bg8e@$g4SoK*sCO$sejV3V^wMnT9w!yYc84k2 zC3eBiLBSk#@0Pgsh7X-@#t46|?tvU|-FswneFulsu6;A03isk$N)4IR(!SvMw7U!{ zWJYUTH8Kzg+Ixb`3NzROrA%5};g2+>tsFcXfecE&MmB10t+XKQ z0aF96L9Ff>QQCODLs+MZLKz@u?(sz2_TaH;MamY-;_wYq(AHjUJ|?w_NVR<_5TWzL ztzf2GIm&q;ng@^k_5tBwaom4e4ENJ!?`|$U@G6w)wQZ+yQ~4 z#1Tb49YPy740`Tr_{zP^&ifZc{ppC;L+-{*7SXs9oM8Eso@rsWUOx)_qnUi5Xy1Ze z`s%eW$($0?CCWr>l?j>Yl2lebq})=P9^rK}TKGOQrADXmZq$B86)l6{7#9tG-VQoG@ za}GJ40;t@0m?KD|J<$vZ3ibj2A(`BCM&L z`H8)g6YZjJ#G{$I8d={&R<}w6k?;Lsta>e2uTZqH7xwC!NQ>bsNI=IYz$f?a0onhaHI&tl$<`>j!>Q3TUo(& zFMV&b-)H7j*vupmNtDIgD{Hv6>GmY=v;rdDHgz_97#JecC9;Y34@(*a$TCqA>9#Q& zd>`~%=5L(RZTZ>B8~^Yq;ghR>*Ot;w9#P9$83t&Ywl}jM9hODyPv(GJvxajpi}NX8 zl}1VliLfdLtAjQf+wMGEe9KvjEF3SaoLXA*LM0}oM2h-s$IKz@w*)&wpEbPtv9Uo_ z$YwXMcIVz{=_9aZKYPc@H|XN$WKSK4XdEop5-Pg_x#-KtHV~D<&^HM>b~W4A>j*^= zRC0sj^=K#5mLV^uDqL(eL4tR+C|<6|APzE>y}G+#@S0A3NXvA7+fBY4GMbQ#^8&Tj zPCx44FQF%1Po7B51#C&Uy~r^GZS|%HX^f6;%%)>FF8VRYxaM2S zzR~jrrY8mRX4JJ%5)06CZ{%qFP&MSrTCJAo})sjGbQU9dSw?}fV$Rr*E@O(1j%@%UeQ0EFAB>$FweV2kKA8qu5 z4E4|mGcToWd;&hF;b+SP?M-7j&nS%euSL<_pQ@}#tF?-~f5 z50h1_x`xTtS+4e48T}3_Kf0LuW1bi30eIBuu7Wq~*&gQ;nAr;`n%&u#ndrE}?LKOg zc1VDl|JldG{=$wMw6oVYkaPic`o8aHNt1m0_QH=9Y~wLMRUSUbdA5$BpOxkAyW^nA zA@z@^5^tn9_|t5|&t`vq_PQGxy(oUZd_MctA>q_~jPYTR+a5Sv_EWNorj> z+vl6~p9!lIHR`pUU$mt(lS>W^*H-IEsd{w`3rz1o-j(4f*Acy2nD8+&1w=;YOm)E@ zcxf`-xga41G$%#YRo7^%%U%cxh)dIXS2r^~-JRw-AI|~b*nC13*L$PF!f|(F>rG$^ z-6tFz_h^z&Ia}Or7oSH{**n+u!R_@X*#_Hnnbj6&I=;09&%&lAjhXgZ|(}CH&E-Y3PSf zebTx!e`)3w9q82X%=yK2_|JV!BcE(k$NW8)4-&7HB$P0txt%>8ND zQ{o0Y+gy$I6@zw*(w=)l%@VlLlDwS6VhVVB{$YrzspBO?R8%n8*j%fJ#KB}dNXh&d z0+b*Wp#LirJ>B|ty_nb8sL@_~1;_>`YW&;LtMf^ntwie)J+?x_s*+5A>gR zKA5$cIlDxX>^$*5?&Lkzoa~o{dCQ-~fkjo%FE8R!QegVD1~b9i`-J9Da&U8RpP&17 z3ZVkSw&p^K8Q5Fi?#~rflPl;)`f6v>x__vrxOOaij_ukxB_Z5fLj@d6Hl+* zZ?vVqhY)W52?n_SJz5~juHfG*_U~K7!6*N{OaJ{NV}queFl3Klw4;3?v;J|;g4T6Z zSYm3p(kBAHe-8VLCLrl!X7y1Vrkvc&+yZCICWcxRS5%5T`)`Q+9{V6l0IS=UNQ<&c zY`TNrC|;u@>n7YG7tKjJ?***6aL5_rg%We9`UR&ZZ}64W{>DnY+9K9M?Xzh^LGbl= zBK|vB%|2M`%lj*{qlxp~{-TPx*o>+WI?WtT_g6R^E=&A&p`yhiI=Z7r1H(F5TzsDQ zu(oUQY|d>}Y%C;uPxkEFdg3p=ePPTu4|R~Y(7cjB#^seJ1l4=fJtaU0|8P~onfty1 zPm)twI*4Aee*2zc6X%DKi#UvYXxo>6E=4 zo|gtl8tkUOe`4M*3+}2~=CZ#t<7{|VWLvn|PqtB(g9M8>E8q=qG^e;r%5JUYKt}^% zdq=rqB`I90d`_h>b?}DJ$|0}Fy)DdCLZ*jtJxhSc1$Eqw<^eS7LLTZHkA%1p9cCHG+Ldi?PPWigtMu4L2PHfm`J zc3mU=V7?uf-KESBq%1VZXRZZfg)I^~i$R}fl!^}(@nj#eEtg>bK1<45#ja#JW@(Z8 zfqM@MigY$CT+;UyD_8~I_~MV7)4O2FGVd1h_*UQk%M&FPK*UyYX6$$M=P!uIGn|eY9^zHFXT^;GHA$ z1EB=?_7`P=J+9q4-&D%&GiS>+fj%K}0%kBp%8>g9(>>agXb0AhX1$!DpBwo(t9%HM z{G&h~@+~e?)sR)|HH5=^6vm;tzwa_IBtmsd6B9^oeK6{%iO~Y-dJ6i>S!0ZLWQN@gU_X>z&su5~ANLElcp- z9!qIr^6fZW$|I!~e|@at9Q8y$ldUiVU!!+~yQeDJrdK*aCX&Ix_BmSHsdvuK61V|H zg7#Ow{o`Dl`}GsS4{&sSG6H8NAa@{~NVV&4oxvTIz0>*{CsIb}MJii)({civU2I%!2J$u)j}WVK;tUf=~R%Q0AO-z!2*qg5JRQeM|rc z7dBOq!|%zp-}yJ1*meU^&g<_x_{yNPG1bGl^{t8W)%}va$!8L7w*mcKIgjUcH%}JCA0^OcS>#xaGuB@np)W0K4&~&qpN3hgw6I%+7-BSbuzfXcpV z(k)5yI(wGn19?~CUlA#C)T-2+ROOQ46r9|_RJ_MbW%lw#n%d>hT#4ANH6h z@)ecybLJC2Oq7fF{TR%f{r-0p$_!N5?w9;F=W0_}qJYiZG<75Y2t$KQK?Mibeu#l0} z5P&lwHQJ%OS99rLI zzp9SNl>d4KGtYEN>aa}_xyl?AT9i8n#$QJ!I5m@$wNiX3}RnN}f zkZY$9f;u%hZg75XyQMz#puuk!ELz+Y*Oe~YbANN&Hm0t1J=Y;2B|VoH-l{klzqC#)c>a2iA{pY5vN9~a z(hT;gl9>7i-W-2Vm*g044(uTT)|<~Y4XiIW+7^N*BQWR9Pudm1Cb)BR1+n(K|E-=Y z$F-Hqru7-ICk~w+*vnN?LAvEC!(d|GzzA*26cZ(7D43q0j?b{;(-CR5P$y*!URt3c z$t?>7BKcrXQrYBv^&tx|$H>^m5NtYBlOK$-1!3Csr>%o;#^;pCftFLpHJs}7`Ji*7 z#h5?-nO%8iA+k5$ZQ^JV8E1Aup8U<{B$ONF6ZW_7S)doBzXP5*D}xE(sSA0Nznp@^ zLyQ}lp_MS-VuIeVmUdCShZLH(1&+Rdb|fJ<_0fq-(Y&drd&G`6CI7n7u4{ly4{t35 zl|bm6rz`7kdK-XyYk!Kkrj2VnOdhurB`-9RTBpnxswfe?0#)IlY95YnA*49HBIwTR z@_gDogb_3Q-FdNXPE7Y4c|(h~qIL7Bh3`C~@(Y>aXAdPS8#@iXDqZTV&QL2z}$2*P^Phw zcIZilcYG)4ds2|lT5|MS9*h>-*BR5jwd#nP8iUts8Uj=XPjm4k`ThR(qx)#;tln8` z*!$;ydFI<*gMstlFxLY~b!&nf5}oMp7@RmTOq+QrklJEte-Prc{u6dQf;hVIX=~Y>oK&I;SEs zT{1~IZ79}R!#3l)h)~lrr@w@p9*<3VK0-B|0X9Q)*uEigvwfMeU6PoyS?THQoy-<@5C3KqKud9ddi2SIHx1C&y~3dDq?HRw|Ts3unO@1|ml_-B0j z=;k&>kxo7{p-n|i``?j5Lh8R9E*SM`vw>+=S5*iLuQ!fnJT?+JUS|1B`g1(aatX_3 z?k{0CwSfBna5Lw9Ox;IL)3eLX7@hE~+u!modPh;iu)EN9aUiwp0CkRHK=iKOUW-vR48C+)2*p_ZyoCswjB}a zr?&(~$$vGe4ReX2VCUdG2oja9p3{?NQ(x>;ygZEg^nHwTAWjUInT{Va1E9%8kgjN( zD8G4lDu1HM^_M`#@2up$wf!-XJ};|3TNr0}iK=n|?tnpiCr0|6fX+v;B1j>atxs4A zHz*br3}g8-T61g?{0v7&P!5Yq0aRU2p;yIDsK>a`>c-N9=8Bu8X7!2 zJj8b{4Glofl<@9B9ml^VBr$blB*N(n(q_dVc<^eAUsOQ;w;pBEhVs+>rr~sG;j7vZ zqiwzssaf+C_}%zMjJ;|p*_Z(N@x(LZFojle$>>CvPR z3?%KgvY?bBNtdvuvob`*lcKpNX`iDPawBc>z5Or*+-taOX-t-d(wmOAxhRaq=D_O* zu=D2m;!2iFlhj{7psj3jO$!*}S52h~w2agd7GF{co~! zw~i+o&0*W>1=Q0H4zK+qTwZAH#8J7|d`2o-ijU6M?2lU(U^YWkxu0^>8js4;J4Fh* zO`{eF?<4&^sg$ndBL5q>_V$8BVcp0cXH)Aq8P`XK1S_twcq!fmj_uv!@Fj8GR^*?KuwiME9GU!!TI~|X$yRS@LXVK_TX_be3+G<#Cj@fpL=#>Uwjj)+nV+O6ZvQl=IGkrsSh??s8)?58t(C zFm(LYRLNVvw@)QhS-NjDSp-y9c_6=v4AO{Z(&YWo%#xAg@Tyf6)`1;Sdf!tiVjVa3 z(>`UE2qDj2?cFPceqDOpci=f+PG;fzgXRWT)b;Uofp94fcyOZmohJGH3;CUz&ku0g zd3%=AV^TDR`m*yE8f}TdZbcoc;OPiLg;aK1auSjpDdW4dRY@bG9p3N*`a{6A`ZC)I zfon|A3&FW7tLwi0(Xi0oMppo5tgNH6V%s;?kq*c%2%gWspijf#yn+7Z$0 zcWYGi^hlPLma)4I4h}GIaDtWdU_SWdp%XR&loOZst90q?9!Rxxw#I1i6EjPM&kF%M zdJouZiT3>S)q}#@;-V)d?S2;c4JIND@r)~|fD3;bM?A1;E!e5>ZSlQjjmp(E9dI@x z#0(zxy^<*`acgeboV`LbaNZl{QMxg`&j~`)Hr2|hi%-Lec-&la$HhW?1B^sDC!h9H zK_+n~7-5$-7({4}zN&J@gt5?hx*&4#{}CDjeoHlpI(LOZCKTeDtfi>kX~IPR7(ax| zZHnv_P%@e2E=lqO-%(W>gRg?IH%wHvqc2x^)<}1uzolN2)9LKfp@-!g&`>%RN7zn! zsWKIo@q+5>5w(*~NL&OVr1A+wn=;&oSAW1ik-4f%N3LS|MfBU`jNt`$K#_4i1)U8A z-s?*D5rVbjRPF1RW{y(so!|h$KzD(MA}NvmzyN; z1|Ps}r9_^C8HGE?7)pNC1>u`!wo%^(sO&Rj3C4N1G#Nw*9@6qo&sp$rHYQYm} z(jBVCaymXHfRPXLLN$I{;>i@1NVgIUe;2vi)fRV}SqF}r;gGT#?=)2puz;APfVJ`G zmxc4^ri~97)}GfhenU-~>swpZVE5D)F`pK$7v2*T zQzhZ5dk#?Nn_=Om(hWp~NZs%DfwJ$L_fy|juJNvYpFTcGj89f8cwe7VhV`hsxtzPv zj?5ZgX`t@P${Khv%gkCR6l<9#)TKRdsuvuQ7U?@@^U%D`n;};kNvoK40P2G8p9n@f zrR)oQ)+c8=*X`rDzY?RplHXnLsU5R4S3PNFoUjDSLxiY-q!>#=8rEH9IxgPEXx~AF~BRj%apy)LIvoeYk&+mI3K}KjN>ydQu5zY!nhD0CPp|B=xRK+9%vTM>m!O z8Uwzn;F>-kyBL4Z#MN4_30_r2AbZNQC(ctR{WFs&-tyDf0b2^#{R8{@XppZy1hP2W z$*qpK0(SC5nk^=blb_G@2d87Ry&&(E(gnv^m{obcNQbtb~oGZj}Da=Qg>dwp(>lNZXDcOCyD_`+gNtAwRY|lTL<4%?`xsS@Q z#fw3WbGjqzm|ZbR5g&X1VIi7F5@k!P4O(hjZkXGKc+TdWnxoA#72AG*u#w?thMqLr z5VLA2V)$eW1e#t8wlc1q5?op{1|Eh~pl}1tHG*3V&Nsxm<>5Kv6(@AmpMH9qP@ye{ zY;JD(`$lY90f9E zpL?FPyl4m9ec|VMqN}j=meAFeEG(^AY+>{FcLW(-1F&7Z)RXfA#K5Cn$k=kKM}P7# zLd08sNnG6_!z|yhb{Fi(0QQIeuMso%%u#hUOh@|`#WD@=Fr@YreNBlr-%$;rc;tp( zaVb456fDVHT$Q}5@&z~N<5r^|=K9w+9+NQ;#-9^9qGfmEDzcsnGT9YD$7Tu@1l#>Z z+HDi1bPT8FU6*Thv$ zQ2-rQLK>;#*<}*;FLxIVOT&{;Gc}c zGSl}n8|D21kjel==YS>nb`9)y#B`95Nbc2R##ay+2Q>pqJVleu{MPSh$%Zjaj0=b` zY3bOs_y;o3sKG;kVF63QP`?Dg49OICN|N0|WpOuq3OB z@FKXs@kZxan#z}DG0_?>IRA5sfI#^Ymc!lRXTEH4F_j%wcQed8*6x9q@~$Np{z2bS zS|^eKOfkaPkRDdmE!?kzeQvS+6qQQ-7I-^cyaGC*R0QMA%+uzC5r|~D$J_2S-grJ- zZ#*ATiVvuhwra1x*z~>K97ot^H0slbD}%Qo{elZfGjqWsWA6WJ4r+uMt@fAot){USbAy`)hh+7<%2OJa8 zQNzQ-Lic(Jn}^WJbH=;|8fvXWt|HP3_-&jE8{HC4s*RbeaHUE;KN-O^fUQ~OE#1`i43_vV0vw+mQ^_pcx&xq3oGq^ z&f$V=Vf}<$wwt(nt+x3{0%@@uAAKSwJG)Ms!GslzoNeqE)w?W2>4LNnE2@zKp%orK zRp`hf)V0>d=i6ys2=(Gtpon4-55>(beKv=V$+#H361DewMRMp9#}Tp@xQqt^@^E7A`-b|(G4tU~ zEdO8b%DKsv$23{y{ts#6KhKgfU5B5xzmM?!rXc8ksQ6s^1&51Z)fRgqJ*BT!(aQa_ zvg<=p*8S2=DnGE#^Wxm-{eqK;$FoMp)jPS(-DB;l=++^4UEA;C9ifD_G7O%XjUCTX ztNS)ts-;YMx+JY03{%$(${$Tt6QAc%dNl&RE*cr*jr3{7WCVVt;hZ*kUrr!_M~0yT z9xOUtT+&aS&v-RpreYHayho4BEJ&M@c)46A*~4gL0;Uul01!t)BFxU+0nLt$Aut1BWVyI9#ze3CN8-& zDmxyXzs$0Bk}?Mw&3*hVB>ms^WeFIC0)m}N15t8*43NKW$X9Ty=GK^Y8AT5Dp_*c0 zjZ{P_b8oF@aXL5l*nN563f35N$Ka4}fBGJ5vB&7UM_Ut&kS|o!E)qLNeQu%T{F2(u zv~PY)q-3Uv2#M2=Y)8`iiH>GD_h)L6Tz+*wSa8Lw%=j>*8P?SL{iJ8?WWMfZVs!M* zYB7aoYLt&Gf-0%Tj%-{J>m3IdXReDwfi|e(i*J2OeMl*D6(Hc@QV!qFB@l1EBDeo* zXLRt0rB-`>*P^;&9>4)7LII~!rH5c5W2=zq+^+3~lIslg^Rl+3+RJEHVLWw-;az8$ zbDGSQklAFl>eJ)4<#L>9L)j)(W{m30XeN8r?eqFc#Kj)QJ8#V5Mw{x=0RCf&vb{{8 z&-NTzFWjL6h~mr%Uqj20qRGiVEsSMjwGVGh+Vmz=c}BM_n3N!(O7&1YZOI=Oo;G!m z70WS9-QJtoQU$-T_n?78eMV6Jjbu~9hL)HU@_XfSnk0lC-k;;xs) z8X1-yVI$tNjh-nZZ}~}+64#1VqXKKmKq%8AeTMs)$$xEylY0Ly>%=ey3&sK(*~`n@ zQTO=e+1HL2fuvXW%ZmN(chGzb8c-Q z$-A&h)Co~3rE{3Z`EAFN&^h|>Hwr$w*2o3N(lOliW5OWcvC9Vl2!{DxuTbiw)l#QT&G^?L2 z;p?=>oGMYVv_5T-Q(n57nfg5UCFb)TSzu@=$|rS`hZlbsl4LX1ymjEQv#!owhUXbD zEqQR{WvqE0WtQs0O9e(*D4&FA1*Z1q*Rk{U-&3=L3!=^im%37J38e&N1Npw-kZv z0&hZB+Te9r*OABIGp{AjN6JhtMn9HfC+Y27CYl+upe_EP^qw7={-grEexW)nnV>{?Vb?o_8Zw$$ZWZzbzNwl_NRq z+Qo6T2&Br({6A9GJ%&BsR7SMOdnqX`&}hNq2SCKU(*d8rrzLbeD$CE7{XA>S^3Q5$ zM>jsH0s?Gmm_60*z2x*pyE)1uRra^pI*r72$gBaLi6e?5mo}V%n+3xUE{9%lPe{3z z+O5o=THxlKTUjg?WY}z8oxH*UenL{&UaR{m(5hNvuZtGURzqVLSNlUqSU1>g{<>4Q z!{m5Z>joEZrGz~XIMMKdr=}h{%DX)Dis@(lB_h=545R)uwD4j{)~!-P+f>S3z*_cU zgRGgnf{e0qz$DFFPWlD8(2*<&-8#BwXI~r7xhctW35!FoE#-Mz@5Mw|T62Zo=8l+M z>7>^REIK>|Py3ltKKp`Uff@J$^o&;2&BWta2fJ=;EZCKhX@A=%>^<0BXP%M`T4D@0 zuRJ%gD)sO>R!7uaPH{3L^gq-gZ52@V7y;fb<|A5$MIUsLgoJqQCeLiw6RG^Ny7nQ5)+yc{aPZcWC9nv{DHLswHQFkq>#l>B`P(mUi*$7NJLS-JoP-(7C+4+~w=f5s5I8_}`Y~gekAoE~D%FqZKyb(RB~V#izOJ zPEys$_d!^VEY?>Ja9qHxVrH8XlpK!a{~uu1Ev<%1 zb|=qNtz5nu$;8Sne~&R32k!5@Z3h1PjXLmOiPpa_DZ%{vDTMQz6Ex)({}O_tqe>Wc z+av!smj{eI5F7nR?kh<`LZam4&7fVW1_}{Z$>q&v9n1zI`AZMlV#371QU80KqAyHL zO!04Rf3OXE^Z(P?^ca#P_UulpxoW|K0}vwS98#0pe2$MW3$B}bHhO&O7+Yai+d>x> zhMXOf|3MTJK3A$ZVC;jWCdJA#iP{@GWAmOtUsmZ2RzD^?V1kP-bz^ZtfWuF=725bf0wQ zgu#f$UoobVqinhNVlrTSMP@%20Pip$!o1A(r2^)fOvUVzqnW?|8H`62PXrnAnuCkb5E$YuD%izwR-uJnJ z)EpT7UB?})=bwU4AKYT5Ze3k8K2B9gde=0TnE*xTmg=mZaTULt&9mL7tR@m-ZNcho zOl7jTn=YN_9r^!hr`2=_47Deks4YM&aJj|ddC>iE@|r*dh`T7DwRI;Jj(>andeBZ! zP5@0ovgA6RPpG`bj$E5oy0P}D5m9D?V1J5p+_t98zFb&gdy=DkWSqr?$5&K#-w-ix zpH+L4y1T6LE1H;zx5j|P)Bk?)^mgMB&1$~C}P z_5+ytK*kSh!^<~!P4P@lXv`MmA-^%|1^sT@W!D3>LV&<=KK}AX0iE}(Z~PpB%Cj_!5N$Uo6icH z%Q4=yK;VN=nuw(Sp(<_G!bH|GBQB5dDMrr7wI$U|N>=eq=VP=G0{GMRte@W`JF+6w zl%FtWxP|9qBuEglUrF3QXr77;cL~|Aw1)&RSuUj5#|uVS%$VP?p5i{~LHPNf-0zO? zWI<{3J%p1&lzU8!NNVpjBdP*p?X*O`0l(2In|%1_iB?Moh%J9EGInW=qgtcOBs=Nx za!GB}cVlrKs!$K@k55Udw5E8ePX$eDcaAxiRX0$xwTV>sENP4h~$+Lw%a{|AFo$}@8Pb)u68ddBkGuC^= zAX62Wmm!feTk7!ds5BYYaOra29(>mp>6G3Dn{snP)V>AX>vOJ3VpINWDAqiI^-A$3 zl|ONqjRhMAcdz(5$BTf3Ux>w6Yw5^ry0o~&T6P|YXqm8m^V5mHL(kf{LA+cm86>$M zf=uTwT^fV$Jswf8Cj)@&X}Jd`b)Uw4W%1@#f7>||t+%ZNP2gs@DU}MSHL|NaKaasc zcE_vjMR^8Sy^~!jeUNJvM>grvF}?2T7~!xBC_iT_)VE{Y6iWPA!r;q~MQalXW7SSulV`3dv+m>Ry&_*I5zwi?~v3V(l2K`{Es4{0Plc#(90*VRf>#gqUd;j zp4*tlOuhi3pi%Am4GFvM0bS>7OJc<7c`q3NozV--FY7b-B7bk6@w|;_~rS8&43v(i+}je z+7vd_0}dG@i~EnN5LE4m6DvOvm)OzkIrdNXME~x6#~MmhjqfADiagxs$PK6BMlOxZ zLaGR63|2-8^BuGfsedXZK_Wt_(B9hAdi#B~PMMAV{DxZ#_rZvgecpfWyuPK5jAS!Z z=kF;Q$mIQe?sTyBlS;Q!=g z`8+?zL9u~`%l`Sn&|$TDjI-NRxqhb1$eYrYSB-2l+Ny?{zM(%e_mllCN}tfCCwEUw zM@K-+hL66f1)%;G<$3HfGcNUoN;>*(0@sIYDJgO7C^V6?=u`-sw}WDq@IqDH)9foh zc?i>9y3M@?WfF%dUC%cC_!^piGnsw?R4 zzJAqR6?|L+!u%=*(=`Qox&(h5P1UFy=CaAZ4}fUbiIz$2ua8vx@=~2PTdi?a7nPTX z!-z1Cj8<#T-alP4KsAxgFtFz}g%rb}xv_bu_Z(FDw)1YUJ#^YhkKERC`I-|9FzzYB zvb8qEo@IES>iBe~!y^|;-Tgbiyf%r)5OV*t) zH}=`jeo5hoFyUFhFmX}K{3R2djKxRqO3yp9=5znED=5O_0$OhK<~gsud|^b$P7GIx9tZ~LVj0c|z8wYQTQ*jz81JQZW5xNr5e#CSD(jt@-=e{`mb#6Jx9h*{cyplKOSXkCKFc7>Mpo}gX-wIJt^Ai(H*!$7tfrf;wy1~qcIFE4wRke~+uujo z{H{m2oc70K?))H_slh&+j=)%Z$fo**=2r!-#36h+McVAsJ^xho52SOI2BF6<_Qy!d z-E_Wah4cqqz%^TcxbQ#PSfj|x(FMeihv%yq#+Jyxo}N6cJS%sKYba#V!3iS+`*lqx zjW5;0sRrlwdjB!1=*^evFHNA<4|vKpQ|S&SI)Tm}07k=M{u}oQdHgW!MS@B(Ia~7I-u<0|nFpeKQmk8yAm1%#=0G_dACQo&#qs+UC`G zWzAS6prdyF$~?Uu!TpYojc3!~{H^%#E^SM1X2fxIOa z{2tjFerB%Z_WU9Zr#fJ|)DpP+KprLqZaFU8c!32qIvrA0EgS8=5Y70v<4o+f?#XxkX;QJoZpO*q`I`=VFS(YOHl+jpKXX+$nQ^fl#RZgI%wL`Ip@8N*EXf1LtF$q=mAlu#w1z^3Iok)-!~Juhed)RWUPFls&=sGKrNYOUMf-r4 zB^ueAPnh7xP}cg|QzzA^IrdC1vhx^JD#Bg-5u|be`=lvIqVZ|k4@XPu#yM*kd#2|q zH`I&=c8b!IudoMpvcl-B+pT(|efKb*tMSVp6Hw+8pS6s17LW18o{_Lz5pC{E_#vEJ zz!yl}+if)kHeTLL3>r1=UoQS1zAHl7!u|aDbDNWlmNv4o^6eUy>I@pl#jnyw`R21L zl8o|YKpOlNW3j2VbUO-Ql2@A18w~xKloaK~$b89L`Vv$!S6*f9T|Kd_nT}VCsZ!JH z2{AjFO~yO-n!nv0$H&I{iYOdV0?_`&KU8!y$!7h}1jKMl353@m3`D@zb7-{z-!az8 zP1)g-yjZ%1X5qNg_0A`&c92j^Dqi09&l2Y#TY;eYzP0^o=%yzOSlGKc?iY)V}&EBGRs0zn?kO- z$)3P>Vv*W2Kb4mhuJ_qg?0;2yI{eOP|@hcM9zl0@yh^k6XP98$y|NCG1)IUHb z7@+6}i%9v${{T7fH-pC7kn6jsokO0a>?fg|=k%|dj)tP7{w{d`xzY>QXk~_{{oK+t~*FHZ01GWilUkUrlf~FB{+;g%t@6G9l*9HqA2)NCd^M`A6 z8!7unRnzqZd%@O|xdqJ^o8SAVpHb2@0>N&Wd{#S07aB4PeS~ROc6*Yr9GnUkD-XqM zr8JfT-1G{eb!W*e5rM4&QD4DnmebnAcZXvf^S{xbW|oVKRs<9g@X0ZxH|&qtKhj0? zK}x|01nX_d{9!>L&omg|?~_i#$K<|11WI+xkpZN-%$tpG8^yXY$E@5(%FprPaY3Qs z5o`ah8}%x3xYg+Jh|G0otI<7HR`#~_{~HUC4&q8(y|lC@RYkYRu;jo@>)fu~VW)sn z8|@{HJ^}fX?amg%%T#-vnMuF7FxcxjTsJBw-L=CZms$RTk>x8`6Vp05n6v@S@!iaE z0f77cna9)C1<^i{u&-&RCVWpFUlfQqiEM3rl*%#E!JQss*~ZX@o|Gc|Dg?KFiaDER z#vs1fW$PlHD=tu~j8icVk`S~(P;K%O3jDHGf&qTV)Dz~LvZ)9_H)5s&a8d&DAq;C`JPhFnzHrZ}9f10%h5ssgcKKlYFXa9)i z;l5?%nzAvKO?$Oa$nGlcy{jwbhy!yd9?lhk0nHJl$8mrs9Xy-?s?*yQbp%LWmEI@d z-^|r% zu8wMTD*qxAyG_4;uL9q75u_#+eM?Vr6b+l-qP&l{aB5Ienr@LN{2B5E;j+|aRU5EP zO?`3Yl)nN3^*Hz<^)2z6aNJ?DL{_SlN0%w|Hl$i&NNhtFgg3HE=3UO-2Vi7QM;!?7Jhr=HyV(*VpU@4O3EC&>(6wW`?~g z$qBN=sU;3*K*M31;jYvo>Wvfq zPa7Tr_|O3K#4Vf0W}hW{V-quH-H~CLT&_zl?FScVOKitw$!RqmQ&;C4rENTc#-$|C zf>~GH$k)Z0DqmD*!jkGMqEll!7PuE&p^@KQshpmX%dSJvlxV)Li_7Nj#`g?@-2Z*PYfG9oM(} zQ7mM2Fe2N=ES|+UXc1>DS`3GM+m`5Pv~_@z$=u=yRN2zDpr)%PuY=6KI{!#Hr#4;N zG2+w9>%;_GNjm>YH>zPf4IMg+k``aC_IN}^g-^#E)SCZlW`MW zwU#NQ{LQv52$SHpklj|x`lDs}DSdu9h0Nv?`C;RX^gsEm zQE%&zX`20WmYTvzpCvX%wl&_@sl6{Zwz-oegSk#*+nYGN+r z&pmCiUPOc$ZqC5w^0saRKIO!HnFT(?hZ(#jT8wn?ZtTM{3s?Hyh^8||z4 zVYDq*6igj1SkKY3?>pU+eJ6FNv#)IFQ_Qk2`=0Ww~4u z)pfRkcc&X1kUOii`oQM+!8#vFZ(^fD^}>=+x|JbW<|AS2KvwgpeRwc;??sYv^`-zX z*84%u<^-NX$D%_d9R~w$1pv_KI^YHTj&Tk~&Uo91?bu-C48>6VyD1+x8CvO~!>%^T zRW+#_?ix^Sa0b^+vJ}tex-uW>Hsm8*9&-`sGE&FJ0w)M`;z4a6SB^S0CU zPUe!6b{{4EwH-yuZxFXL8n6gBW0>a9snZ|etXNW`xE_xX(FC~lzCrq^GJ;#4WwE&VqrijhS^TqIU z8h$CW|6Ju;tHhaoDqbYd0}W1h2Sa|fL6WlJMY=yX`*JwTi+#ygAnchI>U-;H4z?Oo zV^=X9vdxR^naZ)L2IrlehjCY#>iwI9N1qE6mD^pjT@4LhiXM#3q@7<})H62^YO`lC zW7!|YT_fBHeB!1GnkLIW`8c{4il56fnqL0&Cdw_1puD~zvdy~&?2=jMnnJz5FEXCS zMM3SQ^=R5|aU!xc4Q+D592~A`?^@^1Wai$q0osv}4SQ+@uXvSXABW8Sq}6{OXrHor zxfiG0Bh13_q?z&-uBxqT;j8P5lJWXKCLQGIxx~I~>Ss}B9#n)L=`{0>)M2IR-POpA zWuGGRhhwYkWWl=|33=SUaud(gYVS)VS>*!8_SVEY(g*wEd8iL6^k$NEJ)AldGN%fr zj(@j=YuY?0oik_oX}1pqnR?!A#8G&7UlC){X>D!v)r_2&`G7l5IGoRB^$T~$7e?l> z5HuF)GYeb1N1F=CYRHHJ>jNx4I`RpU(Nsgak1xZt zHoS8XO~%;fZ@At)RU31v4Yv?$J3aQOyd{QxKhIr7$Aq-3bJzkj#ln-k87Iv<==vXc zbM6zm8CT2|lmg+VDa%RfekXG&a4>y;d5fHz`Zvo%=+Tmvk;t*2$((XJt<}{VSmx}@ zG~9t^YdEmqCM{LL$Kq*--J)Z*Ej)!8IMIFaCS;J~3vEX7ov@7jGniPLU}RUMyRh|Q z0Wr|~l0dHBjM-=>IW0}!$|^MEy=&2n?^n+|J`Oijl19 z_F)+eojA7l^^DNDF#Gbh&X8f_W7BN2|kIUL4Y z%L%%zdc3bE($IVA_iv~YLBuClUMsprh`2zvlR*of%TVL zGu>S}>${4}%itOvC9U|lpYwVJr5%Sc*{~q@_I8{@{@NSxqqPYEk2fn$7#sB3$%S-O8rc^pZZT#`3am*A~%KgWA|+(*AFhmdJI^(ohedX`6ydyeaWkh)HZq{*MrS#hD5e$ zbS6R~p-;(_dOS~7pLaJ^=gf}bd?aUcFrLJUaet$~l%GREhnBX}`s9Qrp5@WoU(zr6 z#m>6r%e^PWLfIhf>Ka76*Ml?!gClzLL)`E!#4tt&E^0{a%Cf1=+8cq`-nul!@i`@u zJ=Bs%^u~kiX7Xh;`!*uT9Fpfyj3Zb)-!khhdSlj@PAWLm!yNsbc}T|VPc~dRt&{B} z_N}V8-b&LF{ZW0rCgHsG7UQ_IuW?1+WXFri{!q4tBLeEkC+minBAH>0SJcuRef-BR zd6bU$^!wR#oY9geC>&zg$1pKK8lbtsO7ziILhRer)N+eI82>&7W(gV_lPg`89R0UI zjWS@$cD+M2E z{IX{8(QVXoDJ^v^W%*KNm4${yZRKulTf$(&x5fTliWe&8as~q4$bdi;xa=+Za&t$| ze3NAgqxol=)i0((YWqi&hn{kBFM8)p#_)Ilt!Hmgu`knEk6Knoj6!tX#yr1egZRU@~m~cAkCGS z;eU>quTY%jwu{k*3>Ve_P3h^JPCYvZXn2z9#|&3@B+VS$Q+T^(ukrXI9LY;fZk8n+ zkmx(mg~+%%Af8J{Z9OpsfI0*2lowH^PC!cv+NzHy9l=(TT&AvP<}P zK@Hg->3$L^=c5R-AntF0v#$YWEJbU2%!H#@l1K7uH4rA~GXzo!CD^kl4%YXFn}%Y-fEI5ojG;;4miI9c}X%PSiNpI zRd1^rid?uqilnKX$c3#3wkx~|(v zuvysRG(3IR5G~yEdFgl8mM32AswW_Q=%|&L;lz*f2e%e~Kh#Kr=*;5X_Vw*Wgh@Io zc22HkPhGQ*0|VE0H71<~iI>lf=|`0Jp0;b*=Rp<_ISlqDhHe7PR=LceSm4$bnlIrr zE}D$*8rePxeY}s2R2U{lQ-}Hb{}*A=z#E5Vk!~p_F)yQJ!-R(hMN|Ave2a@CcaVZK z{d_!wgn0cC^Xf3mCv4fayDLF_r&E&cAuD1F7vzX6A z8?~y}58rS?Y&pIkKYl=&vAU;Oy3XC&pM8@)Uh}3UDc&uK_^G(o^ zc0xW0q?cVIdwjG-ITR%oCO0?FS!>&O`<{9gSWV3m#4>J~Dknp3wqwr8&TT#~0|jY% z%QUW)>-=R#J8tVb_Rd;lHk*8ZS~s1Ra2IVw#U;p|^#Hvuzi`{(`9;@rZ>8Xs7LrnO zYOBQ(@+&F!}w4u77nu@}N%%M(pTj*6AILRWK}QNBQEYM0WNxGOnQ^aF&Eo1@PubMVQJ9aDKm ziQY~Nhu*YChH7xA-fP2=$yj=Ndch$Jz||A2Y_$jZM8a`B`4(Irvm?E(Rw27r4yF&B z?xYQKCRFCnZU2jtA$i&>ah3m_2a6#ozz$)r2D#E?=(TjooKS&`%2x|FUf7E*Z4TgZojQB0wwWbz=@gb>UH(XYqK(!{2(Wb7&VPiP zCwXCG!zwD}TfncpuGYsSB+I@WoQ z`4CFv1Rg@ER>&iI4(Il%Idwe}=aa8rnESIzgrrFOgI~}-{95t%{hy#D&weT6E}0jK z4N_m-7M$hkMrZoHGalFbbZx>-o*@8d_p3-^`p!DoQ?vSnQ7lSgNzfID4xd zS2Sn`zt54;9jvsH90PSdG=lT;AtetB-bwB~XX%-@ZPkFIm>je#Q}~>Zj5mdF6T=^) zkG7lWzXS}`P{`b77)EE4GYduK0DaCfiATcz3)N) zmLR$)XN2dwxhyx?o?-asV|xxiLctErKJ(E-mtt2$?vh*i>tY{|n|q2)j2~3R()xBu zkO?e(B+X#kebe!z&4=^WWqlw0YYD~f9`_-M8%I*KE$zO`j5cWPTkh{gQ`kf0$S#^Y z{LFXf{VQzgUQ@_ZHbd4A=Spu#fs+W?(HtZ~< zbHwcfE&Bzkw&XJ%Q^9i*c2>o@3U=5nWulS_rR#Dd6;pmcPa_dV&?ZMh67Z*gjSDNn zugZz;z><4$_HyD+>>nf&nE1O^xA4L@w>(4GU=EutP4v=6vRY_utQ9D89t9NNtW=$- zR<5)MmOe6b6xAJklR_ZHUj9J?NmRG32@KGgFqm=HmS|cP1A{-zFbJb4mn|AQBhPJ z9JO-&jg1XBczC8}kLMK8E}}&+RRyr}ME1-Q)MA#af#p?)NgPD=tH88=wohrI< zF0*jNkd8uACZ@p~q)))Fv6dwh=FJnfwx4zLfEiF;@suD8eQ98k*5k`gch`O~0%XCp zyE^Mh>gbwkz(gKtLlvb$cA)5BdJaOsiP{r-lF`Pb!7-t4e%wAVA{r{w8OHK$e*UpI zhB%xf>bTtaE4OF)(PQ@R^OTy>y``P zZZ9v-iTly};!mk(m(4Nf$M3xG9G>HC&rqldqNM_|_G{^+pYyU@y-74BS30XMSYG|q%DM=elp!Jedv?_- zOyKddx0etvUiMm&kdogLJo@U-GfV0CXJv~>UIE!Ez_Z(ZKoOQ%gIQw=i&5{hmu|56 zJJXd8#!0R1&>-Brf^_~cwuZIPK+sg4MpggHO7oUbbuoO`qgD>2?s=uvv#P@i-sfV{ zUj1*YX%IprSJa=0hd7;z3*nFR>#TBmmD!STq$e znezd_QXP7ChxWzSgR%qF<3sHu0R>7 za;I%<{&+R)Bz09oSS_nPa$mb(GF$YmfSKFIS6FdApuvpz+f@I1aRG^7KyoYJpP*03 z&i=v(nmHN{bh7I?fqw78@Y&PIL@iDdC}*kF9;}6PIUnFQHt*u{uI6SJNzyksb@sJj z0N-8`&)>fy`8-qKc)!GJU;$hHKg46Kmpj-*6!^Oz>yNdg5py-KtjQO`sRi{`J1C!p zWDY}+H~~=tpCIO=@A=bbEi=}Tnisat<6S7uU_6rLliBtScSkhg`P#bQocif)@$eq? zaxwl)RE4)&P~t3`1Vv&wyM}fzdCyanA4SSmiG^(iI{)r|Ny_xP?ixTKxWjJ*;*q~m zf5898mnrZN_dS5)PxVLd=3n$dHNQZ5|0dI33`C)Y{}LzuY!XOSRjSsU08c7;V4>B( z)w6g@!lVkPi|0Ay0m}nsco%SeELZ96M4(>t5Vg!^yA-hW7VMcsgaYpJ|Dm8z=v1r5lY1uxmz z*CpV0Ym@z(*DlKO@brwJG^WQQu>JgU^_#*Me{Rmujp-Pv((#Z$A=|O9c$xg(Os@|C z%4ifjs%X*Y4A#!x7p!xz-3$BySx5A&L9@r-FjYZ6n@2ES@Z62SLqu$aRROc1K*VorWs6gEljR-ZVW^n&? zP}5Jou_2x@m-Yl?-cbw?XQHr@G>4KoU9kRswLvK! z^$YfgAlP8-gqtR5iJ!A?fF$>yU8XOeGZb&apCZ}_S@|=(eHvltm`q0KK?fH48@2lu zknUeq@Tt`Y0Z@_yyT6m@&UMuY6R9%dGly#kNHqm}M(lz}Rq%z?=fN)(H@^7=l%XE; z*1?5XNEbz20w+}ahS3Y>Kb$?JT@HhqnKPlYr)jhgUp zbI*H;ZD>8<5@6%mL*^XX>*se#KkS=h`)MYIg0}q2q|8H#mK*&kEu@UWPol=5Wodku zX?6Kh!EcS6DJk!pDC)REuM2&1So;{AOCZH@kpxnz1x0P5UD5fHCv;t*9y z>gb2x>qT%{GOI2ld~THecSuGL5U#-E;k{fr<(K8Y-czEj(fP66GAkpjOA76YszJgF znY$38NYRwpUocB*lHKH{=;J%JBHO85-?v`iO28HJo9udk=)+us{jK!=dq2N;V> zPWPM4Mpfw86Hgv`A-9Wm%hG51%>C z`=68B_K)Wrk;f||flb=B)h8xya}8|?mEUblSYwqrZ&wo}zZXY{u@b8GfD8xcMV)q< zMpmiC+RK#lnn!AAIMCiR0Qz%dKESz$qICRJo*yLdm9{~95MK?xQ zHaV3fOM%L~t8C506avUpQUF}wyXh`Ia8+m-B{H8CK}uWZ-^Yc9PMPq&uKzVx0~C%U z_P1v;%8%YrI}T?jFb!VWH0{Mhp@Pnddv#S`BHq#$3DU1dCMKIfk|c}yT>xDUmO66G zuW!4mD2u`}6w08!ok41}P3sD!A8usZ^4&GO@16PP7g9`I@9*h0BE zQte7r=r>CLSEM)_;KyF%LuYqJ9TuA<0&p29i>82Q##$It@vd2)uUg0b()(?3UOJ%jRt5#pV|zxfC@+6J%P(oO6n*qfNuZ8V)J zB%g-!eG}otHqyFjToz~l^>41(Try3Oy@eC~aj~eyCewk5@0a^>R_}BMpM;w3N2X?0 zJuA5zPOCi!hXJqg;DwgMxg?Yt-i~nA+oX!9aPjj*bktX*D+DF~jZ!|v{;!m>_+Lu7 zQV)z!P;K&6*{e;nyX&1OquAKA-yF|a606_E@cYP7BVJr&~4Zi4;6Np$o9wT&;%b!31?sK$(^X|2%m>6rzpp_Vj zD<5H$r$J2(6FB39`t$v$F&~pJtD!>;J=1KZMO?tFay`-ffy^##MDq2p9V?=lh&pCQ zS16;e0Nl=-g@pj+t?j*7XIIAj0U1?u1=uxDL`{L^XJ+P_sJLwhYIL62(0P$Ac0tXE zsgIH>(SuK$3+&uHY=#90WTHu}0EH52ow4;i6!F6_k*SWKb=^BX+Z;W;iJPCQ^9z@X z4ohqA<~~+Ge_z@B5K|NL+8Cuc!H8Ni-#rWtM+DZ6ajeU`eKiz#Y$&*pZrIAVNoR*_ zx!ZrGo$-Fo!XSe?^093J)Og^8BLeuC@JJpc{guBsh~x+g28JP#F);~EY_c-Q#eH5d zI*ZOYL-{&=HHuxUgD`D_Olo7XkPrheEtp-RTzfWox$4afIT;x&#P@})>YE!PBgx(7DN3L#{L#UDG9W$c=Cw9ZdOZuj z1+#dMRs7i&gU{G;Ym_$z%K&Z3O18q?wNjgoAmyAVSMveY#$AJ;^(oEmhNHMTQc6fD z?*|H&QWv-HE!t-C?N+Dlr)$?e|RoaRj*OG)XPL|!$@ z5IqbF9!QauK!i-?If#r7xYEDA+0^>fgCvjazUFv!Q*pxJu5Cu*T7A}KKRcI0L_Q0DMwxY(Uvv2__4ZfARxwN@6eUctvsbvR?8;i((sip$|K`RYkm z2q661x=M$kv+$C>+@v9Njvx!TLyaoBqb=#}LAlf%scWJ@rII$Wj`vo=>%mVFwen~e z(7>xJNU_3NT2`*}(1h!1xN%6$5e;obfUW)#I)!h3NY(VTJo8|@p_oWG(ACQ?-H(*$ z!4ef=<<5?&JexesO(yXs<`O}^;rNTiJGn)?gx`9PjMu6Pw~m|Tvwn;z$h-)YbEo+Z0kK^I$>bi~B+6VwberYK&? zb>{LEH@MB~sA6I!Ux<8oGXo;(SE#kCklkm^c-@Q`6}?#L z2&Ng+bg~6p)6FcH-xfm z)W73OPrk7ZtZfdH%q5_qYs|bZSQTTU`uZk`?~WVZx;;*dhd4MaocwkJet)lK=FwIy z)vkvtOUL_0&Whvu-PP_5%0wfTx4R*kCJxJbvomj>%Laqh2^gy-3ir*dwPZ{C9QY<1 z%#$XXRo$;Kdw!?kwtFBj0x zo%?e6Gp)N7m1#Ycp8BQU{HFcw+zkFZr<#Jg?FeqxWBkBYr{x+=*R#9pTIc%U;9$|x zh&{H?DVI!qTb_qHunv~|9?66|gCw9;$7GFk+M&Zr{h9^#3_+YNORfH2BSNstb~Gy_ z($634K^cIw6FPE3Z5i19EVpro-!|->nG&-xJQi9{@N3VyxjhMaFZrm|(*y z*1VJa4AtuiNh4U~-B>GN(TTe+G%m*3CFUXAp*u8B4)u?u-2yyr&P2u?LCVmUI)8N4odz_b zdN8Y5Nak^86&DxBD)c&Il!}AYm+g-tJel#*?C4+~T&xRs1t(Qm0bWIB+Wbb&h`JiC4B4DK^^d{vHF$~NuAhn&&(&f z*2x#d+;vbplB-W)$@^_7C}q@lPWyBIw&gO%CoRHj+PI8}v5P$L1^lfg5Uu%_hFso| zfw8gsMXTX(qH9Kt3l%A8-=U{u7O$pHO|W9bFSztwYAO9ILeWYt?t5#X83UH16_1ER z)VY}kF=VjF9lc8z77{urU;My+Xst*rZyvr!kbkNo^v}q{p|HV#Od4dI#kv|$5VrC} zwb7Oj;*MLPIU`s}N3?Sbk&dSa2g7~&_wQ2WD!ArW=h~WsqWD2K+Qj2{P_|NX7uHL{~7W`)AE8s zX0_;4N{ZJX{+_E>5OU_c{)5SU2}fl9zn`{dC*u75A4KaCDXvrh^OhxeFr8Zzez;@Y5PMmeNepvui$pP1$%`d zZ=l*jY0M?FqG28iy5~SbM~o*2mu#ZlU51kxuK&wfD{=S-&ZxE|i8NISj!0j}vf9Q6 z+Hw$@+Z`P8i2i{(n0;?8WdcIa1h9Cws!YW?q|oPrXmr5?N3Ce$m*m{wTwy&~g2toM1KHt(}~s)|7$I zgDWCMw4b3~+fRYNtZ=g&&e#bQuvv?*e-cV}doe6?8uf(hxhZW4T;VuB=^XIR@aq}L zszA)*0Yp9JHXTjwsJ!Z-uT-&DQP2fY5EG+|dxKE_EXtVFuFRnmzS7=3##Aa=&{sdV zuAAE%ln)pZHKWkjt|>vfOwlc#Fy>Kg1!K{){zp=}z*nM!rJg#f#DA26ZO3JF{_d_T(&3R&3pYN1%OnN z9KuP4kYY5Q(wgkXD0XjAmpGp00}s`d)CoWnWyljG+`o@0-D9O`x?!LE_|_gCvxQF- z7Q?)Yw@d}Glbr{tWJb;BXLF-b?A770q}!9ayyn9c3JOI81Wo@L#V8}SG!}enQA$TR zXr?W)1Pc~gO_{9)8K!f;n2vIh!MndS8xO~AQV9`9O{M0mjzHWR{1j={sGN27l}{jizBU=O(*qd$fi|gr$ z4>9p{UB_Y+5#Nf+^RAa+hjA#PYRePL=NA7J^J%yp23>Np_+H{LXCZp(4K>PPd30l7!n7A-ba=~ z#k-ZyB79I+8i8#yjK%rJUEbK7v|OM3^_q;X`?H%t`J$9w;qW^qd6_6Su999`%<4C& z9}Voj9KIpz(h6@OP9LmFGbkAOz1>l&Ge!g`k_iKgj@R%%4RXcVD<0g?S8cNwt&M$*sawoDdydu8NxR9uI{aiQ z^}Ypq$<7cA1=T&aFBIo$uUfaxF5X8=pc0#sAzY9BRp%>zw%Lb8FRaZw7WS3?u2UlV z0dN75$RmbiWOe!qqoN3(4z7TE8 z{a2yNlc?mRPJOm`l{S0yQ`w{E;p!vrt2aSEcsenA;sW8X6qPD?fAAc_X}7jQvM!O% z&+TkWHF{!@U@%YYNt1XES!1ymWBY~Gw6MIo`~w3LI>_@;z8#K6q+IXIzjl+%4#}F@ zD8gVyRPXGsbKk>Xs~o^}j6+p_GEmpz=1G0?ikt_x0Y%aT&VXRBlmBKvn~mHrm;4d# z-I;w2KBgd_pFW!h^t*RR6ivt28M%!8#*1gyTd9E%Rc?yL9`;9Zi2-#i2VDI)t6fLQ zN9r|%)}(>K@4!9WDP616JzFXKeOV_jkV`r!BGAWj>HVw`+4yyH$sV2;XPpBmYwRsy zg#pmVejn5MfFJS{ZFD&826?Naj!JgGhjzG@ftNWxb@7i-7}m6zLHs%;VNG|b$13`` zdN84yOJj>a?B6;WOc~eQP@gi=idlW*$%?~UeBk2qXz_^#_fIr=#k3`H9NWY$vKV!> zYO5^keOXBp(c!U;M(m(AFc#wyVY3T;tud0@cVLt<2hfr)7u^+0O8=!rX4=u#UqV6C zxL+P7HogA=h3@YT8-vsRiGAO$U%SRvI1CefJ3YqXH0i_g#Wz_*Jl)$-CicCbPF(Kr z>UNW%uu_B2)UPvJkhtJpEY`Owm*!hn2Puug$po%_M{$d%JBh-x5qapI4Z*Mf>|eW! zat;<)@_C*CVUNEBhksr(H0x*Y1{ooel$%0o@LD-y&uP`g!@zg!_Q32LaCpFlSP7)P znwx6T=Popl<-u;?cS({9uYc~WSnB|u>@To;2!>cq`V5yJpD5}cnGxvk+fTW4Qyt8Q z4eCt|ArhqL7QCnamEcD*Y<%ubm_9bn^)ji>;UgoG73E)|V`Bw6ydEjdxryZ^fLVN5 zTU%QP1b^^CqfX|pWJh+q`6DOEsa~rF%vB3k^>yVmU_WS~M*Q11N)U`iDj7C5b~qv5 zYRO|kUS9O_QR@)g{Qp3szf$q?omjwW@$svdSCElz6r0iP>)Ju9yK)7M$FtvwgT}A1IqPt+kaP^} zu1r;>_P#dtifs4sMl$uC*>=LiOTXrOx);O|&pp=HNcs@ot!Ys8uu_=ZHUS&x)3+g^ zqw?7{B6e@N1bHw*;Jl_G49Mx{YD1tepek4X_ON-$ z`zv`r?=0_g^uXp=RKclZ=ZqxY?D;e|u1XoX>UtM-Sg;r{hwn{junUp(FoM;7hEQ%G z5bJJ78ZV(f*N}U;4mYaQM&Voz{T#ziJ7`t%wgv|vt0LUkj)&c5TnjCbu%Hx6tE8apMU5yt>#r+prGXk4tN^HN*SxwWp6oGGD z4BHmEx7x29jwiE)zNaXIe|KTEY0f=9A(jg7OqoH6Ot{u>?4wB-(sNvZ!ewkMDFtj)d3kx`71|v`I8njV^5ESuat@BB=Ac(sb=)fzbPBUuuV67cWIu8t z?HuoB?G}vwG<=Xx19acVHqCicc1Ryf>lj8dSz{w-Ipg-@c7R=y%zz1W|+e3BPBAm*d> zw5K8rf8UjvF;pR=)pMi%EDMbN2W50m7X+B{^|9mCQ(acP#?jH<@@< zH)Q;uojo1|VKJkEzi8Kmk_HkeYsgLXaJ861OuQ{>Ws>(FA=kRZAYFtT}ffIjS`%{7Ko`T(qGH-DT$h&g;p=s%q1*?F6qq z%LV%6XtBSxgwt-6BcsV{=haB}6$*!i*V*gTi2L~PZp-b;8|{oen>7Ku<&!@MTYwdbC<7=|x0m)NneICCTg}SxQdSs56dFZ< zjb1xuv*ntDwIzCCio)uqycTb0Fh79Ay_7 z8xV-yF7g(B1(g0joqcswRNWgch=fuq(j}nqNlG_}k^&+i44q1M3_YZzh)78ce3H^J zbmI_8%!o7$UDD0a+%xd`i+lgM>$lf}bzsifXV1>}d7gK_`#W~mg|tpeoZ`7wlx{NN zA+!ay@J86X3atLYc)U)k{4*P?g!0Ld>u8xPz40_Sh(}6Iaxx6H0R+zQm$)V-G?sr) zehE(#1dhU@5(jf`HK7^6K9F|nDm`l8&s(={8QDEfa&%C6ur7~XLaUoSJNQq&mqMCxgcc%9>sz=e<{ zwVE3&;87xzaCC0I{{>`MJF$A>%gs94lDi#VETQ)ysRAb?@)u}%h;c^OTd0JHfiiQ_ z5`EYbfD}-FEMvi5I+)r$~`mOx!liUg%>rv z*l&KyxW3}UHec=geM^7WDz)OXJ-x!Gb<#&KdXyzcGWJwAUl}!&<9wkY*zn+~fnJgz zJ)P*(Bo=2qQKOAsuGD}-5wm3`z@}YMQFmjX0XEx0(J$a5`44nIigaOERH7~qfm5o{ zE*uadhz}dTLYT?Y+lq}-f7iZ{HLLACO9Plc&*_KW<*g4_ymMm+0o}P&?_g z&e-4Jhes3=bI;9!b@;S%7x8@)y=8}_&t>lUP*0G!jEs&-bQY|{>~7^t!+5z!;bzOD zOmTO|7>xFY?#X*vwRIBv`V}uME}Gr=5R5NEH}N6#5n-2Fv3|x^Mcdi>3v9?j&T^u9 ztl`W}Lg|YjcoXB&FA<#gU?Rq;Pf6109l82jSxUO6+y|d&p1hIuNl)IR$M1Uo<{(e{ zj?_Mj*vZ_1Z^CKg{UYP;wFfnWBZ|+_vd`+5GPi)5udm2J;6;U|SuFw8+P|pIwu2t0VyCbQxax z`30xz13gEhKP%DnlN4it6vAhry91x*-#gw{wmY-B*h1&6=rR-Zu^&PO`69i;4$F{u z#YI>`huI7dm|0f`{YyH?L~PxxC&0++L#<6u8=eurLt5B)=)AdpA6ZlBLt-rHvopH| za_xFCk@VzuEbTCRee=0+iQ2e91FOa6nQGq;=e-KXTg$SC&-d+)tuD+(yT1QO=__iv zXghzqKGE9lS7FcOyiFh`DH>L%zq)f8qfT^QL@yODX#A*VZNuwvIplFEP79wg%jV5r z#UA29kaMYN`uB^C;;RGP63O)Z)3bRk&sLnDKQHw$(`Cu}niMNvkCT!?(=%I{B|;PL zM<~X6(AjP zYUhfpx5)U}qTQ88oJX^Wjqaj@E0YcPGj_TYQZh+=FOOND|O z%_VO%_1L6HO<+PmNt2@9ljxXV4Zqgtwl0m!Q^#t<5XX_0ozd1R)Ifu9 za469{Vk`4^x*PipOuzy~=3(Y_VCKC~-}*DG`e(IT(DG&7srynhsqq)&iPFAf`qN6=HIB1Kag_Z&tvN(KPAnS;$M7mAuNCv+ z?LW3a@tZdm7T$UU_)mdY*ykq)g+)L_7%oBo3*S$1h6d$;(kv@m0JTmLp(CLq!3Q_c z4+xY`Y`har?bALQvVigW9NK;Q^yvvvmecvQKx5pefLXhStWWk=3jPQIK=+P~`~p}V z|4Qs3CA%!wiyQzdf}y?c+wDcscH__pxcZ5E!0PR&j%OP1Ck)M*gwte1irzdGBOx}SX%9!ofOr*>^y%cEFeq4(RoHk6HOb|;nt_VzW0~0MeKxx zHpRLz|Lv}_Z_@L)yg1L!$?31Q*Z&5Gm+P#8$q2&WZT(pax-AgNT2Q8tN^Th!fc+^Dv!IS#NI+G>Qtr}!J@;7Cy;Q*KiOe~<=) zF1HmY2T=ECM>`3dp4Yuu{bFMe&vcmokIb~f!kBpP8cc}>EqMB8-XK~R^;#eEPdnxy z<#%i$#t)c9{!~|`rnh%8(`5HQU7_-#dRVRc#%%f(GcoO2V)m{^_pJ&J=c2`pSpx{k zuf&(;-I|U&9p9?5EyM^^?G#FT*q-bJrmm3NN(S45r2ngITDl$jrMfp_NMkIW_MS5T zc-xaswqA4kv&hfDalI;kovM(S4!U1?Z1*~w8TrK&#?FSgXNp2)h3&Y)DOWl55g z-kMvi5?#=4`&d{R=DK+={j^Kqy}r~EjIHZumi5E7z%T7pQW>|9zHNn|Vff6$9;4>S zW_z*-B0?t4YC)XMw6@T=ylPWpWPHgNBJXW-hlWbZN%5*|rPQe8eR$xvvT=!ukP(OG zkHgNhAt6I~GN;O(V5JMY6zU$Y`9wl1a@v1tP{gVm2 zH5F|QOy@N*lMNmq^vCP5mL2(8i@a1#g@8U7YXA{Bq%fM`VG}5sWDK%!X}`(x;4`9J zzWm@UwR0EE9e8u>B5K^n%lk@%w*iA^`*Y2Is+j&i-_ zSS<0qJnK}K|I~Otx;(%ff1s0ODZf(Pw@fJ7JnV9z*yu4zaCe&XM}DT#b^yTBC>mP=J+IZKi}QG{(`Fnut*v~og2kBX#=e1owRrS#$kKk zpJ2nES()r8_RpEOk$#`@k7opDtnL`db@K}^`blqy_frr(w@UNe3n<4P=uOqZHC}Ea@+Mu8`p(N?OafW zG9Kt3ETeLzMuiaz2gmlc=nnlAibcX^-u>ed9D~G*$1siE7u0df7_CvG2ROnqM*8v$ zKeo;IC zJu|6^b+25ypL6^gjU_AFUIm=gM1E*HRc88pmNX6?Mhcvz05UxVLL-o3MMOl9*Y^P% zue|qBAt52RCu^=yrlP&3R)$j*y#yj<-Fu&~`V)#N2rqvndmO8f(N8>7eHv>|mZFg4 zKBL-HbFj)7UAr{iP@Z#~2t(~)H{o`wtJ@iVmGSs-KKEXm zHJEJrMy0a(s^+OJRe()cf;dSI8-)Uf`6VXu1e>vUM5kfyr8p@Rq|jpLh<4nxF8h|g z#ZDbcIVE2U<7 zt%WL%6%=KeO*vceh;_^0-xLmCj3`(2`duNf!Y~nkOSNdGtlVx#Cb5Cw6F-hdEPqpoqVw@BeP0NU$qo(PIdOL^@s@Q)(_Zd=0JsK#LuVI_@= zde@?^u6}f)javScR``){6Z9I(pp4!l0dYI^T8fv@)RIiY{#COM;HNQzVbLJ&or{N$ zXhvP_?WSYf91BVIdW_JLDKQ(O?J#4}qth8GL`3w$R1a61DU7EpCY)8W_OuweGL=m&+?N)`yCUPD2njIkBEG?r`g7+@-)rfY z3&W?l$gfV?!1}2XTx%&WnMED1H(n zNAr_2nr0EO>THetf)`5EUCN_=wEk}YyHum|^i(7Fsx1o?Y?})034V|u4{-BoRcRba zgzTxv%FHocIW6v_oWHBy!3u7tMt#6x=W){>y(aVLparY5zCs1v3<&o?cEBsb=9UMO zlUx`q-Ke*;;@NT}D))L=8Gi8{lVO zJwYu=k|7t*i3H%9L8o1qfJ#FF`bBhHYFyNi&4IV1zrQ~~=5d(HTGs6EyPch%BR$0d z6E9XTE7M09l+@lX3-A=cRE@DKI_?u^XiWkwQl-awv)tMd@9qK1_5r$Z@A5JwSIOul zx55Cw;tPU9@AKckt+Y#xQ~?;6Z`=Zbmb!sO=(6+jVBQBdnORv#Palj@ViQnM|Ktm% z3TnD<3$A+qW@6SLXQ1g1`Qcg(d+UfNlnVHmXtEp~=~ySnjmzTIRC& z0yra>9pYrk1eD**+#Cp&B|dNe$Co8mqs}Jd3mEVV(PHD33jJYTL?`Kezriq&f1!r@ z7AYwkAK$MvcN`p?2w;(kGPjH78D0-z;PcoUHu+4~k3EVf zf5LHPbc6n-{pfE#vyAG{I08BY;57>22MkY4YV{kcD8RViv}^v$Oiy}2n8Zb)Jd3gV z|9xw$849-#u^|u%0elsiZ(y1OlWs=h_LeYk6hlMxY=Dv}Vpk1bXB~Tw2;M5tr@=#^ z%b#}TI%RsrRH1=GHe6@TGtGbWo5u?VV?_5)oBuY3?a?ALhY;F@RZjYw zdhYjc_T*a6If>lfx~htN1_UKO_r`!KV%D{Pi~NsJ%!^1sl(45nh4vs~$cb~HILn!o zRBk19m}!Jr!|z4ID<|tA1fmUg^}c+~mrG)vX2bGA8wk##uZ3%z6og8|aL=Pi?VCql z9;(&@0-{bcSoow24~2zmKFNE6clP#JSXo0yM|DbhvU86)mG*SY8e_p@r997lfLIQ>QPl;cW{C!nNtMOgZQ?0p!Dn)^TM@PRwOju!kot=gXUT5>f zDs|PxptViFrmd_L7_YWh_Vn~D@9wDoKI`PP|66^y)HudErM;`mr>c1gCemlwvHM0U zD)fgO++sPArew;F;Ux!iDU|UzHj)y`UN!>oO|`F0Y^t;P%%t-H6f`YbR&p;#~y z(px=~DYJQFITKA-ZCsfFdj@p#*wxupGNp7pq}_F{1HSdS$3;3*h`hpK+D&g!F=K)6qVK`vBF}&P!~n{I zbk|XX{pP$TC^7t68+DH|BSHg)Uas{pu*;@IhcnUTokfb;h(HE;VbSq^HmJJrwk62a zwO@#~qyQRtPv)wPfztVYnf_IfrcC(vRWDJ5Wba;G$04 zM+KOg%C>N#6rpU|Qu=*eajW+isWuZV9qtp=fu(aT1jqg9|8G1I~o7}m&p?H+&k z9$DKWltu9anvK1+H9f8?{k$u=W%tS6;e-LCa(hztFFl8DW%pOK~;TurK&q|Q_~Bm_ilZ*R-r|GX4CUS=2H61>u=YZ)AH=w zBYklEEswM4ZO&+mE4)Q0Z}tLH6^IE|_;;O^EwM*aS`Q${0jhQrFi{y!@*L?6_>*3_ zjlR;Nwi&cdY=z^%BdVS`94b|>JKxda39wLI8z^%A%ie$N$EDEXVi=-B$7(nq8=Ved zw`2@(^m4Z+sY{TUDj@b%A?a%hZU#Y=;0@`PorE~nl*?V^(4ON%Xwqk1MBigyZ6|@GN?@{ zu}LD($M`b3DqrCTq1{t-f6Vr(D`-FrtE|-WMa<@znAL4AZNK*2CVbJ)18KGw;!rlc zMbK`FLgKdnrT53A7K4{I)d}H1XpOZEp3kFjQhsw$#|v9#9^dAmCbk=j5@?%?^HoiQ z*VmGNWzkBbeL`5*THY#m znv%Q`UMyIinwbrB*6G$WvQr}gw?OW0Os{rj=ER9Czjm(on}_YM9zM#_gv_T?SSGrS zgdFdCUrsf4Hl}RdrqZW&oi9jo?JwOdd9j7+88ZY90U!D~^VnIIQO5|Rz3$`}rCf>!8k%k0oAS5Vi3k+9i|?RceY zvatrflzF4x<@MX2=F>+w(wjDj@Is&ap?z|Tm(4b2sl&4e2{P z?q)mZ_CJsUt~%S3+ze;V*rjqQ>rmd%k{T6@)=<#zt%hjfPNF5HjMHPQMFa0HYPzw? z&#Dj#r*)I@(KZS4?Z05d5Ve|Z7S7KuxLNWSsjNL2nPH_-GEnZSU0cT5Y!sf}o^Op18*1v-Hz0g1XdvD%LguqpayLG0@ej_*qYUl9q zq;?&r^rd1gy^pZHio7o+g$^(9L4u{hZ-*AWqZ9b1qYEJUycfAadmG zWMDnFVf7e7$Za)vt6bSLgO4r9fxTNd^==7ag+;@4JJ8lh1PeUmgo5x(V8`=^Q8BpE z4{R^hA)|)wru^}a4&Ai(MM)SRMpMmYDiikKP+|~l-WI>4fP4K;1c@xK$z`7xa+PBp zIZqLL3<&f2i|+(;e;ME!(5dT^$sptRbTzfTI9`_Ak3bq5wP^VxaM#x?cTdiQPz{^f z^>VraR3~R^*xWvQ+!i?!FJl-M#fr=d8kk4Q*UWPvTksh)56if4eEB@`ZTCXH@1?AC zXegybPtwBL=0ea{&AovwZq`aWB))OB3w+}(XG_-6#ry9)wa%lm4iHPJm_sVXpFcWO zGMvMsGU#OtaQEf&H;*|Hh)v^B$K4QW- zh5}{3{XjKAZ#UU947Egj_=Nz=Dqp7r!rkE0SUF92Jqt`~$ccu|hd?>W&WIS9gNa4l zyt{@U7=I&fb#q#m-BBC^b0+OSkT#>~+@6tRMPBG+i`7?XnRc2-yl494wJyC75V~nr z8E2QypRB|KLHwduaMmgQtQ+>-UNHU-w7+Bd|3dqTnys-P=_oA;@iMMUjW-~L* zI3fg(&AqY*q=H2+LkkILPPnHfB?AHpr%bE;Lvyd&qKS*qiW=@upP2&DyxlH? z1oG_vohPU+`Y)cKMHckb+N(-?Vd<=`a;5NxWNkuupOiTH(fD^UXQGM0WII|kX$p>s zhGe#dE2T)%A>E(F ze2lGX?*qS2zxp^40b8yNr`mgBOXYfKt9PKlt?~ePXGI6TZaNNPF@sv1bbHVMA8kM< zr(q^Q7N+BAy(u%C{uRXpTFDzd_jZ~lBs;R{O?Xe>8OY{9^|V39n9qZAdBVf^jc%UD zv18c(O-9H#wBCsUo7%gQ3mT@D@*QZGm+OK!YJAG%yi&o-+{cljv5|>FD6!mE;Rn5bT&=}3KBScN z2m6LpmyI|>(Vn~tR1s!+6Pgx`YXH;ayz4E|bHqTBzU399{h#{NBDDkq!{3d;DDEU~C7&lY2e@rYX?@2VCu zr6zaumu9*DS6aiS@Vg-C&f*~Q2mP6}!&>^&*ZpW*%5&&MLraf;9`{UO(j1mQcjGMc z@YGmBh~Q~?*TLd2^_G(+8R0Q*Zw{x&@m$qMkrO;T2{*xMH=lR5db);^`MzOVS?p<& zCXcUXvl5dbQQ<34XCutQ&kqw4$Om}VyF1?l@F7fMyw$+o4Ho)w*MN-l`qn~s3T}h% zkCF^DlmO|%?{uSPe{*u8(7nJ-Y6G+Oiz{E2Cn38+y<1RFl=SCOQv!X4sn$I6EcPOQ z*XRr+zt+?-ciwKVr8?kc3HVr18ygz~QDA@o)sN5goTh>Oy}&7~0M2V9Z?ZCxslqUD zgWOl}G*&D}kAuOs7FH5e8CsaSXKlHamh?H+(&^nLRvjeO55w-LI<|7z;k zO}i2wmgkpz;9m-Kx(yGCv!zFvjGc?LIqF1#jV$kJ*o4_A3x`e#8;?&<ZOFv?F( zUf%rH*4BadKhUIcZ>6Z{KA`22pNtfCDL3i-vQOgYh^cxa@IH*W7`KX1qkf2^^qLadDbE!QzBK z(aC6Ol?@EiM%HYklz;hZ7x5>nSt77qt+lQy(&Nf4Iach^{|AwxK|Y@cV0u8r!^Xxo zDlNPQ$cQ&mhW0(F?3VA4KuO($|FP_d;1Af@BfozAy2|jP`0kxMub5^N76yE^Ir}UZ zAJk=W}d4Gx^3yv1}j`nI&8vpJ(53MN4xE2L8@}0H>PFA)vj6w_}sJj@A|q*c1zqo zOkrcL3X2&zDXu@)H*W;Js-V#W^0)byHaS;S!JdYV+l#sTFZYj0N>g}S=~ud-<8PD z!Pdmw%9zN>-OiZE*v;Go0B~EWOf$D3<8lc4bo{0RUJM&Ix((|Fqtn$LUwGnkKV{QX zL#8Y-;%Q5c-G?n6{Hpu;-0OR_PkSI==}dSLTg`bg6tC;?c3-%O`N{M-Q7yH;ds&S> z`1tua5SjO`{jm#WquMq4Y`f^|Q}q0Z`_9c%$*23|&GXp3PVxDoa0l>_yFV1&Jxo?^ zd85xd%Wqcye13d$?|DtlV=v!GhvLg}q#@hfd6VkSQZgUEu}xU}k{NMxc)vOP z^!}}D`DXI)f1q!2s;#CkoKq!V_dZ|sW}3&->D30;d*^Fs{=^A-$*1zt z<#2KKqe4;RTgQX-`5Y_jUz(C=kAT8PkrG_>mbt7+|#$0G<)Mhvf@iovUd+$ z4e`hC-}ezLp2bo=U-or1a9qpy1~_-T=#QXT3pXXkH`8w(gZqBJ5gI?9J|wCo4ksy& zlopKGMcCiRAPC*enMG^H+s~IRQ{-oPNmebpF(PtN-tWv;Hq=?xr>ecD4nBR$|1^ic zj@B{6>*oDyILqF3muU3j#L&_a& zRnNVA_lfGjRo!|5=GBZknuFZiIV_Wxemgu~+;;UmXsq&loFl1lV*kihmhbx_^8`iK zf!V@IYS82)l;*k1gf#c=5)MZ;&x#lGnf1b3lB3jS{p+0~VduJ1cbATjtNSbJK`(1$*8*_(hIK7vGaGSy)>^%)@vPCtbC7sIGmLcY+Z?6h?(drYqZ*NL zQme8&XydVS^kkhq)71LwuXk9DmD3BSMJsBHUvM|0uX{X;^-l2-ffXKSjzQsp_QS4J&qonu~Qknb8ie97>sNZleGC+j6|<`1hVzqZ;C zxyp*3iIB_gSQOi`eUjxD)5)Z{9=6JO|8&RR1UO5UtI$jVN78$bM947H4&(QS*| zd(Ex5xOO<;wRTg~V2rI#T4z}2$@JJUXV9`ZS1pgexpkI!D)+>LiUGF79z%#e<=+=o zW6V}jk@J4T;CS$w(7K*j#Ts)uH5JSXcoc*m&Cg6Wp{lelE4bdupdVBr-wB4)To}m7c zl@?hJ=0(}*SazPTb84EyToEbAO|&k=uzJU>W=wR*fbsdkR3NR>&Tg=z>6=_NDSX31 z&42F9M-(nhU?#Oh2nS0sV~_4vX?mEbL|jS~pHvFwQ4V9mGJCY<+5_`2 zV{vR8%z`R9285XH2ooP3C4W~P=0;@mFyDK`8EB4PSot z8xfi6g4e*b9r-Sb$ShAIPEl>SaG2hMBLcgHS+;0SUAOL^;P{*kwyM)02TjAqO3)gA zU3GxI7YRWlI>r(=xX;ZqUEf}rT1vN)1)cdVrqSSbU!*X?=1V=ek!P$56LW8t&T%R5 zZzvlug`G`Za8b!v(d`G?sa)PJDQR@uYF08qCRd zfPB6W!8asfo^0$kH)y&Euii21Dv_TwxniyC0!D$92ffN*d;}v;qbulT^rrz12VvRw zvd$|ps6u!^LQ5}xz`m!lyM>KCl(7cgHf!>YaQ(KC3NZzJIj<>xfy5`PZx_~HVVkF6l5ol;%TDl zLY^VR-?$WHn62P|bSt3v6w;L{qUzoKU+cZAnUVs665Dq=e#V)*fdTz5YJUv@KL8xC zg2Ds?JgFb3MciX>@EiPei?ttzwo_C?{DRwO=}&NU zKLg&m86?&~HJim$QF(dOCXQy6UkUgN-oQi`f>_uA^v?NW>PcjljEhSED4R1AQ!mYH zKHwH(uo4$>5)vG#1dAnVhbE3a&S7CTtM6G;jP5+S`cW5bAX@e3$dcsos3u<>9IOXS z5jRIW5kPhcabtw!B(({9HP5b;gDN%{)_=8AL}>gCv*8|cdCoGOoRm!E(S^lrJPl7+ zR0V9ru@vzbO|P7m$POrKotOHjgrL)Rj2+p+i=eottt`&xf(^(=fhEu$j~F6{zA&Bd zN+bhpxiW)cNkV;PKc;6e5QtOW??nf&56P1AS6+lQ^sYA;9I4(@UvhY?+fxegAe}bZ z3iy$#lSR~khoK{0PsP4XTm@rJDN=cX&qMREg@@n>PsE@hBq#X^pzv24A$uXbCge53n-T{YoVo#!`JAX$!1hBi@>U8d$nu;NWxaUwdxrK9a78b%3`8NewK#Rc+& zDCzc|IuzpN8gbJx;gRr%3fkP^T4%-Tple=16Dl-K8PZO6S&6kc1+)Bt3^_FLsSVr4)(b%^=IcCFVvyydgB(4Pb$?3hR( zZuqkmV}MTv@(&~Rx(IyA$U+pAz$em%>aWYkVw(b+CzYBdJ}}8Rp#0+7>s`< zphP*~%nHdc^*wGUvjjcNzg$l|R$FLWUW`GsKt$d=JxkQ*YUtO*qyfUTW3tUoFs^-A z=r3UGjw2JO#TbSB-3zX15&`KZEIvKIFd}hYt^!g`;4TcgV5EQ7bqOLZ zO5S|XIA@Bn?FQ%`$MA7$;_|6{ThQ5x(%zaPfOMc_8s z)gOE_jdh40KR|&(a4`&u6Blm&Y?Kc*78N`pc9uwxw1|Rl3stQGIa+{S>CDc#y~Q2< zD|pZ^FK?(p3ZN@Jom4m@cfceQ8A?=LaHc-X9PD&*#GfQ>J2;#K@?D&DvzFu*K{^AN zI~yN_2a(Vi=(!i_5EK&c7Gc^t=7E+4XA?1H28dWu$vwq#$_7D{TfdQ<)CRxT-%Hox z9ib8M#xjQ6-6&3)qykJ?GL`{CN51O2Q%zBN^ad|s%iI(jOp1cKiW3cUkb2sjhet@L z7lNBt%2Zf0WQtevzgLOXUv#$UDIzt1g*7nhf)WM|HgPq7KJpjRNLJynWNw#MDJ0QVDsjGL1m_x)BZ4KV76=s&+SFaYU7@4opL4$ zU5mRh$LAA)P;Qikut|Zb#gy;qbNUt-PD7js?PHnC9~TIpR~IV8?*dV0wqr&urhOF( zqnE>qXBsA|0OckeEq;qW$b^S0&UQy%Dz=vWGiE>?mXc;DA_F@juQZP=Z|zlydu0R2nh69j zt_%Enw#D33^N?)URC>9lPqAtG#?kfz3})H{DEY_g#LCUVfaV(Jhfa(u-@N6P{d1uT z*CSuW&}BrhbKxcxHW*xxc{WLtfI0A~H+IODI>Im!GXP(f?O?E)n=71|Z(&D02tSd~ z<1Z_rBQi5cz_y0_NO-M3sMh6RrU3RfM&=9flwY1&5a?r^IU%2x&3$h&pOj8nn;|bU zR1n1dmh!Y2SR+D7qlj%o3kRIy@zC!o<>MC^W2+lJBwc?!W6v#x7-x-gVZf2n!6w**#v+6%&?PVIw3?%nr4ag+oEk;;r}%r|bd38-N}K6e6W{DT14N_$BD(m@lA@ zL(^$F8y89huoP6jC9ND|#9blbM|<{f(%gyF%j}^e-*bWM{f!-r)MyrE55>_Q;aPZW zh5~`CN=EQhktWnO!R-EJ3`XfX2pIrBL_{bg;Jb?d_XiZ4280ZjM~=oRq@5u)qY@tQ z7mN}9AGRCvRB7SSelE-U>BcZ{B%(fAAa?HV?H>$I7ZN7TpG#k-AoPTmqY%LZ0)xE- zI`hNLJbN(DmQhF~M6#9L*=3YxkSp072!&;-k%fj~$N9d?vRc-%qB)U}<3b3Sl<-rb zt@`D8sB2FDQr+H0yM)^Hpe9ps7-8+#jGf#9h=V84>z#J3prE_|8VKPK{H5>q?vf{c z(pV>o|A*XL&smS1${6y8jbk#!JUlWUI#nD3*q0QJAlDpl?X5G-Zpoa|KIF)_{0YW| zskfr7>1A<@407aI@NabR-Tr0db`}gTPX2;5I<}}MgJ=8+nyK0=HYngZ87P6CFq$}> zp%+wWMiCk@zx{+S%tj?fmjH5`u96Rid<>J&KHCBmscSt3v=2>sTWg{w7NsE;->Zf^ zs3@BeB?(rRd{MzEH~KB)q!-5(%Nl|&q^Aysd&HsSaDs2rYWCsT44_c|!2idWE+Yj<{D`QM!;yDsqGzHqltVo)KoGjakZJ zSuA)xtT~aph@=YE8Q??7Bpc`BX+aIXKLz-%2+=}{1+7Hb&P~JV6CQF|Y+lzSDmeu` z7&Fh#%_mMu;7_F~OjeA}=!^{)gG!B9CiY;Fc1QXf1w$$NQPz*;0{NL+2Pk zm=`Vf%=SQqy78z0)i?tc@cZCW8^ZdxvF#9o(CvU-%&2JS5DWiJYhLs*L0ypi*pP5# z%ERQMkENC7UQE%z8rd5HFMo-aRF3AIHoVOgu{h()^u7s_rgXZx=9nl$^fw7$X`$hZ za;n4)iB9`hTdD1vq=?Y~uGoI409pIqus!O$`Ez1&RG!P}FxYy{rf@;K1Sv~xzfCap zMFh+xzNP&jDr=aTZt!jW6LKfDa4MRm8Zb+ucn!fwxp zC=HBtF?zTH;#xcNWHLuqFG?rj0`inGllcpr-yk${a)i2y?q|e=DHTZ7*M-p{Php8| z`RM>C`k2;tIf5zZFOW~Y%hERB!w@m2S{3-N!()7?%-#NifrH%USNV{5r^CoCnwRLy`>vt}^qW zK{05R>D$Y72n@_CiNK{*uQI^k4tMauImqZP)jv>tkwmLW$D)1t2yn3xzQjuX&EEcS z{@rc50V49IpH5NZ2TR0$Gx3)#U>db50p)TJei-C0#UNFW$Uy>a+B}A7ilI5Ayu5qS z35A&7{w132$CMwM$Dw81Q{NDuBCzB$pIG1iP;j>1hQ5=yP_2#3R_*BNwV6k&P_yDM zcxYa+HU6Bg`%#3f>ZM+PRoQN3-9N3FU^ub~olxq=J_H~#6gT>5hN2EI5GeLDO*tuu zhf4^O_UEY0=a5 z4;zaj9w=TH!}i*TG%|P&vc>jAreeEox$e0eMWOd%#E$UnvQuy*u+=l#G&IRVgQ*i# z`}uSO|z;w2AAKfoty?4f;4 z^!e;SbD|uX;ujRvkk1bBrd3gfmSZ=Q(87(8M`9FtWB8mBopXfDFF_;v4HtVDBTq+EGVt`l`=GvYR3pw; zd!_leJC$FADNB9< zcU0rn0j?D*PpCsYlSCd@>Gj(ZBQ$J&WltD14aaQ?Gmg7O(HGDC07(C%C9OB~1T+bH zeZ8;KJILqws6M~v@=d;ojsVydZ%ob|`Bhgu227+x%UG`YZy2U91{mayl>ba|@Er@N zcms*fNqIWzJeBsbF*V&OC@Q)NPh7pz;wj zDE1K+!F>Ot5i|I&6e*H4^ix!uyFKbN^0Ci)Adml{05;jvnVE?H)NsmMrS z8Y1R%dz)wTkZc(nPwNsh4~48)K;-|#iqTz=<7*DUQK9@C9d-?{q zx>eM$!9bXY$6CtFdE^g>ehy;B$q-N8HdiRrOR=%WL3QC2Ad5YPu|(E&O%VdjOpxSE4yIht7q1ox&w?aO-!BW8G)*AojeAz( z;jcQd!<~RROmk)e{!$Qv*@(H$eq4-OTwvlh;4+i3;rRg>G4PpkqGX@zE$~pBMXIrN z#)386m{>F_$MqD`7&XgL^bl-<4#}V>BZYBoAwpB+|K*ANb8w9C=;wL;7+Tj#QF-}t zv(Qjvfm@>yqp?H%<0S7vLj$rt;>UdfzTOcPVJ2BVG`|R?+RV`u!gMzo0M1Z<(T$j= z&l80`35erFhbHj-ifA8V*9*bRt>lZJCDc9_s#_x@q=o7mj`5Zs?|T&7yyWy#jPw$0 zCK;9Nkk)?pC8V;=tYok`A%wh(#+$&b#U~y`E{%d0mO@w}4awWzDf^6-mItxDy za2|(e4EiEA$vtA{2^W}SW>0afHCt@B5E4-#%qo#Pq1)Sr^;Fmz#zHy?MrWf~+1`~? zyoJVeK^8!Q>WALd2^OOw0E}_Zz|jAgk-nh^=NHDgL2m*!iGWJaWVUXnFp)gYSXiwT zx!w{Zb_@6--4_#t$6TQprzcEgoZvkELCZ*ldv|}tJA#Nb2se4ECOCl*VnR-K>gd2a zLrvT!e$<7#m$@j6FL_}+-i4hWQkjfav<2!2)l#F@v;zJBIS0kVAJU$AIn)%;DC>?% zX)fjjS1!{UYf+*e?Rb8Po{($0Z0f06e|E$r@L^LqzxxyKT3aSZ#-j;cvzwjN=$V@V z37BKqHBUAaKhgyssX02QwUMzp87jU~o}=FcoS8TTWBF=|33&ONZSwLeRBt}lJ#zPq zu|)6nOo<+Rg)NQmvS#rvGq4UhYi25ZOsJ)b!e$Isi3x;KXPox;Q=yG=xuRyI(rX#9 zKua$Ruyv?r(zwzRvk5mqOW-yXJ_lwWniFwPyLk|^}#4iPDk=#c|W2?za6{3 zW#1v+edav?03%#f%*;xgyxrcf4>s#+(dwU{*I{_evc<=e{ z&WU&Ia;cVtfdPf}-&wT$1sxqaY{fJoI?@d8D2%IKaSQQ_g?^$iWuQc|;+6ATgRpc5e0 zaaIRKo$c-IKooZNW>;AaCW}T+9v&WQ>hRqk{``7YR#rAPI(2!av}03Z?FBH%=lb8sxLtboQz&SCio3<8zLMpiz~1aVR(R@Qyw@XhkMIps!8 z+E{UlupLVYs>HAX14qZ(v9U2^J3%mjB;mnxy+3H(UL|y3AKLtINVQMcN=i!ip7q2S z1D85a;&Kj}yZ7z{u^`Rm?LQOi@DbwTre|ekJr4d|Sinexz3SrN;?mO86crO292}%h zl=SrUY}L++ixY&cZD=T<2#Y=v{jUVZBqX3m?Sd30Dhjd)sHisuD-)9<$-9x3~9K^qp6VtG&I1tSp^m*5am)&ZfNWl6JH>GC)4}#!KO4)zjTwL`1~c z*!WnNk&&^sxp@-z25ieaW_14zQ=S4HK1eXhn3;(Q76=lJWFZqZH8lx|5Gfj5kYHCg zXZGqdOSwEnzX4+(!wdK2)>h86*_W?fl7(@@MsJH5`dF2!=`k@m%2Xo6sC^8Sl$0PT zv$3(gXn>|h5jJDS;?TObu%JpDi{2$^Z*OnWn5K`#D|_n1>CfNuDWOZgiS5tln>%j- z66^E3B1nUyb#E^WUxa2GwCN_t#+>Zzawy7jB2}moz04h2wR7dKuyu$~hK!g#!UDV& zf9sz2Qmd9KTQq9s%9|M&pkZSVcau z4(aJ;k^E_pIbDYe7S9$I7HVi}o`~^*`PC(YmST&1sATWt#IiYC975LNejDuDgL(6E zZ~0N0p00%|B`zsBBj(}VD<>)GaTxJZUUH|u!7y_=Nl!Eb!l(>x-Gm4CB;(ACjNZP! z=TH&i*!+Bw%`hmyrIxZXI#9TL9<-Y9uNE$ypY7n8oLVD%10Q)BOG~|k8bHQZs!TJgsiARvNDQ6HaQ{01CsMRjIc#9(WWKzf1{VXPNN$lE1_p+j zy1c)?zoew3p@GHG(UCXkpk4Bx?YUJc3JMB- zEr@j=1Swafrl!Wne+32>nS<<7N=hnGvT)u)x7#N(HT8IB$H3GyIVGh;nQDD~{n@7N zWdt>R;Q07>U>(E91*B;)F|iM8H25IUI**!>uXvS96@z@Qb_NgxLz0s*KkqWFcRgC^ zS{M0f7dTq3uIy^n$FlFxLxn*`-1@@u&8f%4&GWefbB5$E1i&lGotK9vlP@76GP2No zWqMknd_K<{cB>C1RG4Pe!tv_8!LjhVBbt_m<}SJA_IwhwJ3zaLXACibg^z@=7!K%F z&I%MRR9x@&)#Z!StOOzaKH=@+JtL!j25AR}x~^isZ6ng+ z0E$h`DqU;>-Cwn}j54zzXz}{KR8c|muHevxTTU-bmwZYuG@tx1aZg!daDI07bOG^p z&Ewldwy1i=+IPwA`15TNw7{kiVPb#&n6!UIQXxT@xVEltCRzg#U`(yX?53bO;Arpa zdPsOhd;3x>LN8gWjPrmhUq1iVL-^LnCo*>XrbE0KlXe7hwSpi7Slr7T4Dv#j z18IeX1myB~d;AmuJ@uejGBbPL9>{>)iL!Enezsg!@&e06Tb_9t;FM zl7%xvLqmOi0Y%5YpYQCOP1Rn>Iu+Kr6eAlOS(g(r85tGIRIE6W;-rFEFi!xafYh*;Se150S-49us zE?J5+4iv|Gp(~^_^%rBVZ6Z5`!pu8Nz1C}GG20#_ z1Q4t+W%wbVzlFkeIj`IOGnGWi#Kc50w9va5|h^Qm&eR9e%Z~;)w>m zNtjqdMrQuI3dp-!TAqSBfq)9s3-rKC%f-PVQK;CbzzxrrtePh=B_;wBsOjhvu=53Ixc_5uw_AZ9%@%*ybe?0JfONZvj`p<)x*il@+Eh z@o8xzn?vLC^YcSPA%x2lYin!${lYXDw~O;qq-ebSE32zqKYm z&&rxOTm^{>#lYIy+Qvp!L0McJ7T7;DM6rpwVxH#W;(`%A@Unl?2?q%d=G*4q9mzdf z2SRd?NT94~2JJy%oT{p-LG2G(S{VxTwzjqrkR$x-98@6({1;oiyMuwywF^ooR~`!+ zTLC>WHWr8ue|~;GK0f}O^t`uc)aM@FPAix@wY;24*x`4XTCG~X@4)e}3b_2X$@ZZj zImF5U10*FUFQQ+no4jeB52*JU(OufZoweq11Rf`=RadpJ=OIK8AkRp*+N#4Ny8j@89M9 z#nc*XB;Q~_JS;CRK0e%Y(;-thR;c7SdZ>jVQNEOP7KU7v&HfIq4G z$LM3_%2ULOV+HGLurV?!@Xg^ZzyNY8_GE5?1GcyIkpD%k|MHEV-?^&gj_aZLrw{=7 zrYDy)uf7f+aJ+l4f3biZtibDk`3h7|9SvWe*v70b_{{3U2D2Wb$L8G-T>P`N5SbXVlx1&yg(!cADd zyA)Ae0{gE&eEi|9b%t0IC>Jzy-$)AQ<-Ful{+EpL4-DPz{fxX7zXt%mkxtfc7bC4X zih=GG|5p-b~s_P^esN`Ci|Tc<*#^%L&@e=kCzj5a!T z|FHkg^0lf5_Pv!*3{xt^WZwaciMKTI-077Yb zc@(OD%Zxc3tzE7+#k?yP3CBq6@@mxdet)@FtJY!sGFxjXW@%~ZRq(%Wa{q`YPab8r zUP(wv5r@5gd=yKeUprrIh68qWb-gJi8E135gHkV0+*My+FHJ7=?cewSfY%uJBztJG z#Hp)>yBxLSPCuM?itTC>?Ps1~E(04I-6bJHpARC)w!VIsHNq;g!W5Wo01Y5d5dlg7 zLqhnoVEi0tnV4?go^P?Sv4f;Z5+$`7E%wjOB4|Mwv7a2vr0)w@W5vwJ?qD<=5M;-d zTFnQ#?$`DdF&*8i`2w}a= z+0ns)$|wyK$qD^NLL}hE()y>vpsQuDtLLan$Ir`Z8697`zb5%snO1i1u7`Q=o2P-X@qpS-NlD34 z_?=?-NpoID8`O6I@UprYY%hMaQXC%^ zH96c-S?nI{&zyAnwr%-*R*b>qSlrdVb3Fi(q8s5zkvFfctxKO;Sb7G+F|M5CB8|4& zut@Q=najl*DE+#x?r^*Qg+h!13l0u0iE(frEg_+G{M>qzh57{9#|`YCo10r*ZI6J@ zFT@D*#i)88@hxhG)wKXn*e0kQJf=Gp&ZqG_a;mW_eedwWa^h&5J8#pBR3&4TPj`;>d8OXjP*^4?WnaD+SLoJIGs&fUsb0No<9n62ajbB8%w2Li+lpfV15ws* zvo(L*X*M~En%b&yc}|+>+InZaSv~GOG-jNib-WE;B96A^WlOa;yBnAiB7cVwi+=HE ze(2mfJVc|f%Iw@xHp0FKn-a~`T$&wRR-|fluwJq~4*JoxRo}X*{D>e%!wYn_U>WibD9usF!);=GzhwFH~g&WHZWhyFMj-{zT8(rc* z4>mpNjz?~~x~iBEq@+?i#de1W7=AhHB~P8ye1?E{ zW9;{X`;to=(^JjnSLDOzYI&e1+iMSpzCNmTN!=Y&sDdob zrmt?19HnE8eC{7g2(NVYsy?&zN`q`Z_vsH>ah-g$29bpad>Vhk)cRU6T#sg?FU!8t z@12ouR#;w6d24|WehNa-EnQhpHi5~UE?DLGZh`>LfjXVJFZj6XZg;i2yF&ft;aOW> zhbl1&i}9DSMy>ikK5A_SKJ3DHUh*?b^I&uj0~%z~li7TWeDj-wRe}CGD_$dy&2NYF zJgeT$?afup`&h4Ro1gEFeUc_^YGNk$gj^ON>V8wz5EdxxXgoPjuu4yVGsMkWcpKuA zndXwx_3+oBIIz>OE2V8qe6^B?hJwv&Fhqx%l-XsCbIUNvG2MieOaZ`xoJEO`{f5`)tA_OZ>WEfP zw-PcDSl~#Y7v`ht8SLs*_3S4k^GBO&M=DPunggwHzis!+Thgw7d$s7IJ^{_;hR#Ry76wI1uDCulZ$E8KzFJ}$HOtzQ1N?iw( zY8a0f^N#+nnPm6bl?2@^_oL<8U(3>unED90XC>|2slBWk40lZ~_^i^OJI5DwSt^vu zHOW%{3@SQ4Pby_LWgwLfb8E8ZtUm37{TWRUM_8?g%Jg8}K1!W$`l8?0{5b52{2=B!#_ipD;Y$6WK zlkiy!+8>X05#7$Tos)`AFEahOVwt6VYBhIn)z z%wvUStfC3XNEj>{U8V-`Pmw4XE_m0QJ1p!bbTnp6_xJUvN=TV6%VFWmuZ5q1`(Uog z?3lalAYbSnMa)}XNo)M-)uq3&va+(U(DbFxOX1^XLcCh-piynDH7_sEX0vO2(<=+5 zmoF+TZ0B`V4MYI^V-j8!tMQE&y&v2Lg%B2bl{@d-VqKfT#;LVJC|6n>k}3N-vvs>- z6V}K6xcPGA>moY(FO^zXt75>>@t8t;q`^l}IbW_PcshL+Mxp#X+Tg2F&8%?>jFuJ; zWRoHHU1Z#!@`u3@#Ht>~+_9M~SHt+;-w+M@i&FQ-9^vn~n3)KXbp@%vs$I2)n^O2d zQQppAXgAF;%9Z~5*T?)5o=%j6A=LBT&UOOUw};Af0nA$n2TY8+qSk@~W{cb$%$`U;1F5ThfvWt{%*qx=3s^v#Se*3JY4l-EN85 z&NP54ExsU9;qJNucscC@mc^nc%u^h!2A*tuvTWuxqqJR_iw|LyOrOqx8%(i1c^g~2 zyu-)@e`|s+mLczhBP`8FV|qb&29Dcm`>G-E3Wi@9r1FAv7rEK}uAK{UXr6uX`I`IK z67*i4IuqfZxqaL1(B1etMU8K~KGyv*8!j+xH8MY1o$kezyB#mJ$h7oSo~%2EWM+{y z`TWEGu}6W{hy|EnT+bN5UG?rwlSZo<`AxI-IrA5V1R^e76-sY#z#vOw9-RJ}R%2ym zfA=LQ&~f)sqw?}&_tH#zc>dMv6^h_ho!r=69EV6<6HZi$-8~t zS4KugK%6)Y@2E<57Q5bR&odXyo7t7c!f4;9ue#@*tQ)7)tZ;0}^+~}H?~iv3@gxs(ct9FKeQJHg#U(7dvfmcAd9aqE$=B8#RitBoPb+W8k(}N3jD5v1@1hg_sV&Z zkp#+{U>q#hBZ%~#EhA{0dlmb>{@^;1NqG6FYhqnE=x~M4tWv@me3DtY7F)=31|3=o zhm|#AbKeeftn*AAK@s8`?sBl9y+sNEt<`0QPo6!gS|61_ z9O?#x+ts1Cxti@Acmavc#$*W4(ODquj=DkW^OtYevdQ$ibbSn;8jKNlFAUYQ$AW@_ zfr7dD`T3fa7@;G2L|nT?o8vdOoUYfUyd1xIte%?S3}qKKx-MO$Oi9urH|82YHVp94 z7+sKDc7k;?*VyMCcpip}&d;oslQ;V7`-8{>kBD`GzODwlu)KP_579?2tUJEhYpEHg zMQSb>+Bh<>p7lLd85bZsQqasI*qh zf7Z9CBBv3%@2L-)vP`rPsrUdu7(SW!SnadYNKL<-ZB0Ynbe;$TGII1J=@|WpTorq> zx@|*zd^|`;`lDW&nrVuq38VXC@<>l31WL4?cUD=E6V+rNJg zJjz3^{5TD&s#!#!`aPAjpsMU)XkV)up{p2U zSEHKE^V~=tM=XTxpnv73T*E*~QeMU6Dp!3o+wW3FJEz$#vabu95i0h9DusbRx$F)~ z!;S>yE_q*B7{kd79JOGi;ACcpZmw!;?FW-5SKUrNPTg8HNut}@JZH8=Xn zlKb_lO*B!Ys?X@4&Q_88rc4~zY|I-@C3%j7ic{Bkm&g;dW>pf4x9-(J_>{9s_-m}r z*ASPLh}_1*{t{t~i%4=C&ZU~1ax#ihg78Icyc_3E%_O9SsIJV_XINeI-O37`zCyJ%e$+3TIDHT(GNeyY%(xx#BdKGnx&ft=sb zZC|2<|L-n91XEMv*qh_?m2q@mymG@_SD0<_zUM(hJjUFZ)*O$Pzh}*3gcNtzdr8~- zr0$|?%yG9)wzD9o@$tOH(*s{u*%*6I`qT5P z84|bcN?w~E$`1aN^3&=^FfHykhPJFBU%OLNB`sxl^x}F;PJ>(9K5g@0YQ@NJuix_% zSfw?bG9PE>V|UZp>S~fXo}A3iY28ArK`4xVNkMET6I~TAJNaomJe4b?fDgDF?)#0L z&So9v0eI5;_3PKkTq)?AnFXnp8Gz-eCdOQ1Sf|9F@xPKGD_&Omf(N{HE>ZAlCSfE z|2U`w_0c3+WCHG#*jR-j77&5H`A2emYz#h)jEAR_+h+QAg50_HzS+b4Uus}P0DhBnlY=P5RS2qU2(kHe zpvF0PhGnv?cmWomVJ2bD`M-`dP*MH6%<$iDsOXj_TU&a{*j^00yu2mD8~BZ=9LtwG9_I=j+dM2V8+XQI4nLeFmi>9E=ShbQ%b2;o~H5EV&(JqS5!?w z5OBW@6hfrAt)zqnqA^=0pG3BQI*3`y=dkT8WmK_RN0OP?jQ>4{o89^PzpKuc$od{= zhlh!V=5Tj3eROn`C!JktGMMGHt4F21GNUnuPBLS<{$~Al6f4voxr|elA5s2zzE46L zXm_j+ER7oXh|c1*eMm`4VqE-8Tl5^V)u#cb<&gE6UUsEwG=4@v)qh7iR}XOihEx1n z%{@QdYWO)(qP!|YjEt{UKXQ1wOWc1yoVU1-#AUZwsL*J%n9mb_8AnD_ zYjVDJW@*KV)#$&4KADP77p$KYPH|_guqGi2MEPrZQ|mb!gkG*>RW5p4F#hOuM# ze`Q3Y~Ufoyq`j2EXm6^SF_v*D)f9qS{ycDA=?QDG(pZuf-jnIwlbUFMS21{w4hvi!6X#FQpF;ZT&2N9%ucKUOY! z!nIbDR_C(OR?2H>CV;rY5sI!ik)d(eMbYj3Ooy|f<8yPJ-Ro#fE*Sd z(tj8BM64lWQ7b#6TuAbg(Dcs9G0GAN0kzy9K8f7Kedpzz*bPL;n#cZ&@v2oFG^s)S zFPBOXX5)X%V@*@!kB^{Cl{b^svWn;*yY~{{+OcCat0cq=9@KLD+s&I@7j#|EpllcC zwpE6LI=N-uk-a~IF&6)w_Vnbft8WS~T>2b-+lVt&ekL;?PXE^2?D2AQ1K@pzXZv*% zwQGTFm|k~0!i=N^R%c(e1x*-;wE}WK59JVie{FJ5SMD?)Z*SGIJF&PwS+W=Pq{@np zq){R7+Nr1%#_TNPbvy?TPC*nt+At0a;ah<08tt;K!+{Ar} z@YG0au}_4x7p^s5^=maa^mKP40NnnOtk7JI75w-Z18_AmWZ$A6J)EGu@x?%VCW)Gu zd*x-8*d^=-N(ymrnIg#9NE{;m?EX8sk8*?#HIFY^#kM{ERvEyMEjhVG?+Xfg;Vkrj z)Bu)D&V5_M(uDtyx58-t{lFstegF4r-Sw+Xz-DKO+(2PngCgqf{-3=UE%t}z{D0(a zhOTt`t`Qv*D;=?+%>O)R_|{`_@vGINOg*b6+PS%D4rMbe4!!-2czt8hfdLeW1BBZv z9@4$xd=af&8Q9*nXUnHV0%jNaof@h9Bmt^&V^<@6 z;bO+@cMoMcF8+I4Ur!{C#EJ)ep+PUE5>4MnuZDc9$n~gqmA&yP;El6vn9is{iMc#o zJz(`?$YVLQ5X63G(%qHKQB(XL;yqjw;&wsrSUA4(#@BVr(5T`k)7#z4Ik*+C)D&%<08sI-G&+uRE85AQjZ{*~tn=t2J8R~u|;J>*$&K1(C#%J>J<}1ZwbyCRm z30V+2z2n0+#n_;scG6O2tn)>6n9ZgG>K4=YDX*E1v6*V~EKdpL&@(d*epLxXIU>A+ zSu+E&zBI%-zAWn~VYI3TY`#XDqTDkLcQ4@>2T!}S&1xFX8E!Y0-R5meWC_K*+>mKv z;+pza=YhmC-^0)~WUfqHN2{f=djYBuOe8b;t*3>7U>w&-?q4c z(6XoHFcUAhxo9tVarwOS4*!{S6E>CtWqofBZP{GXdEsea&=o1ckfoEFWOXz2rvQQP zbLLR38jzp~j*h)M(o!w)q2z3q-=jTe6>XoGqPl&YBM=!!ckX)6>jQoVV+ zuv0H&aNEOfzgQTT;BG)fV?7tjJ;@0a0))(A+IeT;^#}qHUo)tt$Jbd5EE33MzBDyH zlvT_{AEOjMdm^!Ptk7sewCJTFh?tSm5RB-6^P02}Yq*VZeQEf6N!8RmuS4=ao0+PV zLSn>~)SHFbd_*1Y#zCEn0x}A3S?`K-*vQP>pnrx`;VItK7|rGN*c1No9G$sQxwI6; zKHelz7zv3X19@xCn6(yEv9adRkW|$FWVU53lAhN?sQ%UQ-YLvp%QMOKuynyrr#~KN z`E72b<6@maA#Al19Y?e#UyRFJgd{!0`b{H9;zsi~tSQw$eOh*qnrd2(73 zj*{Cc3w^a!S2c}s&lg2pOupBYF{ucV8)2NBZz;w_$LlNf$;IC}+J32#XpYM#ukmJM zjyu_3jh6jm%Ch@?*3VJwWdYmSUZsW!`T2S5A*xeVPPNjYqGs2f6&&Z*?!YzEHxu;k zX`%^#lN$LuB^Yc;&TdjBQG3r5W(*JcPPDl8=j%oHNiNcY52xV2TgEoOdATCJ9BEcU zBxkBMLhKn!`-DqC6!pbSek^_OLOg}KFe;%3!(jK$^Ycluw&UZ&()7hzf;Y|yeNXzDNmiU!Oh~kBW@Ko% zGxDWP2cqT^SIYI_qqsuVL|GP%0OF0gkv*eufIANFC>~awxg;$^LPSS@@k|}Bo_kd8 z>hU=v9ZiBnu$6^V3Y1H|dnN1A^Cj#V3v<2GwqZ%=HsQO<8cF|NyiIKaY&;V^3$34( zn!){Dq!1dm#uQFkHa2p~v_K)!Vv0sXHfAmBaE%9~+}Uo6F1mn&s+E)WJQ-sCX}F_N zVqfa_cbbbvF-}$zevztNTt@a)F|Ux8YB?NtYa&1*S{V+^`ps zQg~C@48n#zM|16MB=4@#4z=Q5a@HF=B>ln;yNA{M;5pYOp<8KXBZ|4F;=Zd++lTj9m_ zQrjnNj4JEXQ;#0Po~933bN(nQi>8G5HP*ifldjg3G}(??#O9<@v=6U?KUJR32S_T= zjFBD^X|lQZrYfc#q>v+cY2zjrj^(^4)v)_GpOaKtrfTwP*LmkNk!JN-K=K&5)`R0+ zeRAkZTVXY?j&{TAtan0pn`y-+@+Z7z?LExcBGReWn@`#(v}c`;d_vI$Op$0SquFhk z>gM}s_Ge>X7xj!P6fD`{2Ua{}n*6w#%PryDnl6U2=5i>_wx-S8lf>%yD}E8mlXP)9 zb~u98doJqQE7G7O*_`3y9^IR#rY(3e^C(Do%M)lYV@NS$wHW=gD#UPiCsXAjoB6t9 zP^*6(x7>b;C3mIi`BTha!We+fyfjJccSWmv4QFUELh}wIJ(wDkhaAlhjfqd_@2+=4 z9#9xW8$+&du6y1gwAj#)C5s<$txQiCP~KlpYJ8r~hW;)^E?L1IPi?Y-eJ`+|JWO4X z6dE6@v1v@a9z3B=%thjg$5l+IgZ-H$@mly$o)K>QPqH6_TXXPg?2EusJ>}rRqSNvy z$&Y>X=ZoCmwp6%f?nimt?v9L=G-)Sb9C{}Dm5YyKyQDTP(+-{VZHY{_xPF8+4$kq_ zCdeJXVl(I43JVZP;#RRMI_?y2@Sqfhcp-4jTKz#=+hHZbuQtWJybHn~AcEgjyd(%t zSUNwh9Z0N(&0F1y!F-jTd848G?;_=C&i0T z7Io;?jt{7bEb2Kqp*5PZe7a}R6awx&f0t$Xsb4bF`yjn|^=flh7nkTO^;cGw#ip-| zgFLRprFWBB??lu=y(lQXRXQE9+@2x7a zVa3Sk9~ht#P_6Dg0u442k4o=QsZ56I?_u^er0gi%tJYht+ zqH#@iNl6L`(<1f7nCIT;QL~QC&&b66WY%ts*ReTFG?tU+4`quXMKWk=casPuGbes3 zXK65V1qR+8Ps>rLis5<4vQG>DeEk4Fi^b7E4Z#w+0HWA~$Z@fNiY_Q z*4ol5>NKj0iYx#$u_y{oiT?PGhpQdv^k+wC_R>OI$P2~p_8aQ?fy1$b((;M61u|(u zmEP!5f1+gRAi>3zS<^?FPkVN7WI$0V5WUUr%3)=Kr}2R*2t5MtI2Z_ojbADL)r%XlO`kM`t2RNc4$>;NuYxw02LhST)+VPs2PW zdED!A?PH!UwoDX{+cBi^gjn4}`}G)tY79gsu1$K{iz>Mt+=hG4&jOmms-nkj_NJt~ zv!`(vDoQ;GhG`m7L~pM=E?A<=W`F&bqH~vg^**gYZAqizF7sr(4HEUe_~5qwT`2jw zmR3-RI_l10i^W0_64DDvNu+4r>53Jfg9ZEFd4UQ%3yf|@{_*dXbvG95uWYi4mYX|n z{yD84EskinoJmT!9oK-P;%K%Q0I!y8z|5of)~pq#&)wjl*l2XCAK%XA5I_oY&#tBM zCa1m8_19~c*N@YD5$dwF7wUIP8_kDmvZj*xc&eSmN=&e8)9zZ03sk~%!d^F2zo~S6 zXv-DxiIHgxQ@!f@NW%Tv$!)8Ax=TT1ilJ9PO5?#rw_QalnW@xDv*9{(=4(cX@Fi8O zPViKj6}#Y~x1Xr@0)InOZQL`Z?-#g#r+xV@OXQ$|aa;wLk{t8YuTMwTs1nkYeo4_Vk+J5n`p`k{vMjem*|2crtuT$^>dRhP`i*4S^i;XJIFxJ;2wm1WJ%e3bhiXn1l9-P&0`psMuh7HY@~BJigQ z%rs5J5YJ}HqiG=$xh>n$!;j;AY_zFes+T3wqVyB5so>uW$*#mSwceE*bb}6|#VKJ@ zIl$wRP~LP-+Qhwf4vcV}D78$)xFbD1C>Z9>b3Wv#+1T4`DM7{o!*+Or54B27rZ4z(D2QTpT3j#0ge`8jn&hb4Y$0QDlcC6K z=33*mbMIp>MV=YP8ewvzcLsBbT3ePWbMlgMPlgUl%s^eKj-w1E?$hD zYx{=uX=iJz4D>|99b;XJWYO_zjfyt&cX8bAE0zMoi6i?K+zApwBFZth*9=^E8Lk#F zT!V8QEjf8H9Y2Mkl#e^7k>}GyK$;4*k+y;eCsnE84&pS2r+VeAwf~E>e&tC+1FZxF ziit4c0>$0!?aLCide6rTPwu!l`UnZ%TcJG2X184Y-GPf&Ui=Rp--7TSl9R-f_*sf>mrSYg>N?{%%Mtnjm90$vXtCQ&Aaeni5S z`(A<=tsj$TI|j_2O@%!Pny&WRe&j0JBL6NBU@ltYAb0w;${_D|=e8cl7BTdz+aa#OQCodFZX6D3F8*zrQ{UXxx6XJGej8l_${P*Br1Il}$FW0`bcY8rYwv_w5E-@EJ| zrSGm6{gcWxQdlnF<&tN1Aq{E9?{*rd5-Y6*gOb$Xe)auxj=YA( zTwNWek4Rjyg9hG+&`@M2Mxhkl_mnsvvyU6f*(; zeDh+OCnr?2d`#-Xe>7aR|3b0L++$88sqDAt5bxJ>Hz7++UTRP)7a=YQj?Q{9Rx8S# zyg|1!QUOtO!?e^Rv;DM%+(AV=mU*v{luBHueYEn%T7H3U7vwi1vm6^2t5{DS0kC96 zQ1QvfPoPBegMn!m@6jW^9iGyFme2lbJ)0M2XS|-b9DNm7!mO6lWmJ_yZiFdCFc!@6W%dbcH4 zXQa5H9df|tTWATo4TU?tv^5C&v0{xBu402npQtiZ0FSQy>C>l6(yY|SkCw*<;SF(( zTl592PGUWqxB)^32M2n3dc?%Uq;e4_SAE-4a$@DuOgCZ+BDsdyI2Lv%Q3@I?>fv~B zQZgp3J~&>hgH)|0^k}e>F0H+0q%WJG8k-92#r6-G>z`E1wXq`mD_qy$U7IRZGU|RA>&saw!|G@P6b%aVQYut75$b;3$e9HB&{RbGqe(CkL4eOrjjHioXKJzLZ+m3OO#%ihwriuAlT(7J-Ei7Sp zA1tq{o@37G)w%pThnHAz9z7m}_wn~Ow+QOm+-ZN49V2zJeZJ!gbN!t@J)Rd2o{k^* zUSlK1Rb{D!kTjz%YV5}GPCmYIlkyX3)JSb)sZ>6;p2&xmS6IOtINyk@0R=07`nk(rHx!i zgSEfaH>olxD9I#6nOQo=b{EckQ{tZ8#8d04WpntV-ASlIbG5U&QU&OA$pt-nbZziT zAcs`^5A6nFA4kq;R5^~WJ&sRm?q`5@cCCc#iNhbYAfBSONyLsN^JC|G7=!A z!F1SFs+BS+nRj#9KIEP5203N)*RSZkKYO0NCJb))8t5M~J30qrxa&NzRQ8?BB8PaJ z{zu58`%B349>?Q*C?cYBB5`BY|Nfb3n8KIO<@Ji})I@*1b+dbrQ4@uZe^T)7^G6@% zm(Gjs!@?De3_rxo4XHh(l*-<4Jn-(Xi+iJgYKE+-&ocdceTt!{in>*TX^xa8<3oJ9 z>!h_Pdv3w}N0R;$=-iF7hD+$*?ChM$UzQ)gA6rk7vQX;te8@e^rqYXvy=&FrD3%~+ zqI*~LP=3b+D2MyJqc0Yz(xX7UomIyqLri>?|S$C05X0cHwKc{f2diZf*wyE zVb!&=)>KqiSC{vr!hH_RT(5ucm4|`zF;&3H2%i_%rM{+ zMX_4#QCe*4>G?44V$D%l*$d34w2TdLTWH?g)u-@Cv3|=vx{j*AT*M4I!&t@jz9|}g zYQU~o;F5pDJTQZCUpQafOrw#EtHtJklMhv!&iY40sj=%FIWus~8kV6I#;)?3 zdgdnaadyQjdhdUz++mcQi5e_GH;ZddY_8~hW5~~vJ6Byzx|}+vr{W)d9uNlA6*m8 zZ2N=1woF9kcs1t#TnH4A%pX1w5yq%Oe;3GgYTZw3>CTWE|QXbJHOW?S;`R!BGyXM_8FOvS1*FD2F7V{5g^wL z8u49PeJ;hGwS(R#%PyTxcqL^)8|viRgZ6Qtiw`hq2lu94gW*Ce{;EpBF>v($=p%V@ zmFw1iYCX+YYLl}Sh6wj{?SO*TB+6e~ZiW145^{>1y>QLeuLmvKj+NsyL`BTEf{#58 zCvcs#cPlRjzm)bHtf`|QTh3&T&GQqNI0Y=RzSnL0`IPA40PfW7vY(Z99l|lDd(&*7 zl@jf&jJoS4pS;jpXo9U6$z~r4*xLK!gHimyCSGE+02$D(wK%O z)2Q~)8{ar{w?FfLW6p;lA3}4X4HYtJ#U(}3erN@S&^kTUt<Bd_b)@jmG{7x7ZY!$iSl<}U}!>NqUr+taPZod-uPaHw*GywI%4 z*N62TXF*2~e0=Ms^J9K5eha26Ra}*qkjNL9#^)N&D|&+@J}4sYbCaPYzqH~cR9ODyny{Jg{eR1e%((`K)HvaJ^e?isxUbnj?&L9_hU0ZmyP~RsO)z6@XXu-G!-I%vm8ErLp+Hv=Hp2ET5 zY^^^LO?vTOHHA%o=*lbvsm@Smon2oa3BZ?jrc>ny`2!c3(_eevP`~*L+W5J8B=I~j zNR7EdXW<;7S!P@|H$2~YAN>*yJHDd0(ky7(v&kM&iY8~48dZ$|d~(u1h>hd!P|2tBv)l+B;^M}w%e9)4E*6675~*sf z;Z1+wsD-)ZnhEs}Ea(aMu;~vu_PqS5Jz0@@!omPta05x?4>wsVu=!To0NV(9ULh-)yBdQ!om`k`_%bl z8XC}*FSk}iG17q_^2s3Rdo%7{v+k!)a?fH&n=b|z_785liMJj*V;Q{uwRN+S1+8SR z9O@s8U5YlbfsJfu*CGJqfYbP6Hl{)cR?SYwk6NQmR6OSVYu)k9--#c9^bB9r_O>aY z`+Y^K59+;))o+=pv0c5}=!?S;fNu``m;`y*u;WajwD5h30M$Ped9Skx zBuCMM2J*^reuw3sN3<(h4(YB>Kl+tdSNi~fv@X1{D%)n~W$BC`4DoxN=iRkG#yfO@ znVFekU0_ZP^y34!fDoFIkpY^YfnW>|F#|n4J$U?q4j|wH`f_hBLaaBC;87kwiq8hZ zmiQlT+iAUrV|OfC{$SLjwKAf;pNnw)qw{LE->d!Z<^pIS%mw2R5Wv>gpH2KNUpN>f z^6rtL^ofdyfbM#rz4YP-iCl;qBW;g&4s7aNDi4`Gkj~i>S~)F)Oyo$jQ8V zyFyLA`Cx1v!%)hD^Supys0+BYjgNFcLn*TpkD5ScXQ1 z(LbLX#;)dloe+rj0}lSF^AtJ%U%2=yefDA!wd=TpFmKL!#Gi}6PeXu(`}KdgRa`#V zHf)W=)t4vkeV?F@(B*+tQDk;gQ&ZU(LSbf1p(#1)IN2jN;(spj=u%Q|Npg`L^ZePT zuc?P@noTa{B_+};3Iml_9WoN1&9)aP6n=T9ETT`U1p07Iq!hsHM)$BWXrFYCP#$r`aG1iiKC zTa767_4Pnt0r|xbu3|(8MO1*^n+c0C$ll&wyku@*ptzu5y9wC?I}nVZrlOLSlao_a zv@|YkYPy9@m0}10H6cxUTnOm*j*p4S$;-r8=$B5)#ZGJ`9hIVa6`BwUGkR3!t-+o9p{q z_pNtiWF)!(5Ox9^88oh+ot?eMkpKc7U0uF`Z+XJY$}*LXPd54h+dH;^iiU;;h-aBw zSV&1p`H;VE?nV5LuF(MGE6igb2X)FTD?8cR>XxexM{*N@>3UB`H!(UI85=7tCDm-V z<{K6^wA3W*><`G|%qD}j9E9eosSTD-pFXuPH~;w8+QD!TWMsf6brSY~ZqE7n`T~u! z_07#!f`IPX9ZIAjFaJbo;U$m^DbCMdhF`JZ4*(@F2o^4`Xe1fA5o~vt&;2qTjGP?d zNJC9cO)agI&`{L0A+OVIIWe)9tb|hJI}45MKYpjzfEE=n)xh3?Yzis~-|g|5C{Uze zOS-$iyJ5FkluYJ`7%-OLLO1#$D?K$a0mM*xdU}A3%8gJ+#(zXn*KTrQWMx$XLtK0p zd zdvGzpX^&4xU~Q!7j4i3EI_*zjwq(7KT`9hO{hc1L-f!J&&k+zvxE%anO9T4=R2L8o zeBq;_BXRfgvyQvzXZNmAm;I(5(WJBHhP8I7z&pLAxn_z?g)?_AL<7VPqWn{rl7C zxBU78#EfrG5xBUyZDuNRDk=cB&rL0 z1Xk<=0YoEX<3Kts4-a0kNFYoHmI5%ffEin|H5L}WqS$h#5fBtC2=Vtv^d7!E209TW zVdyk;bXF#)(ZM!Xm4Za<&!0aBD+!df5Fw!b0qjX)UN;9!-X;0|q4Tt8jYzMR9@c*X zt^CQTvoKK;F|^dcE%o!s_m)V#C^OR0<^3!$fG)24Y@nKkgX4L5^cb?fyezAs0o|Xi27+fJ@tLz4 zs;Y7i-+71+ug_q`*-UI~CB?-`a&n&#W1^$WW-Le6fdHPq1Yi}uqof4FWMBXVIp7RE z+})=w*);W20*%Ka_zavztIWpoL%_oY+*^7ngPUw)g)5?sfKBu_<~5x*)TG)3yzE{^ zTK`_)#xSdIPJQvbgXdl^t8uJ-CIPoSx}klFra{f_udhp=8?pS}yve&pi1%9UM@k`}C#0ehH@Xf?t}Uw1kO>BZ`RGVx&3**|VGc}ai@Tb< zJP@e^8a@RptFdm{>go+OHL-6I&CQ&pq)@`T-yvq!)ZjqKfMg%t^EijM-%4~p{4>dt z6bkw90@LVrR}>T!9UUFLy2wa*7-!JAShZyj@{9KAX%1@Y9iX-Y5VS8}z5r>bFcN+c zN!DyRfL@#=g?+m(%Ck@5WYnkcsNVlHRX$v7w&2CC4o)aUXG8C%{Cb1uirPIq11w*sH*V)@9(vZ1@KaxDvu zoAzf-O&-h0H>hOG@JnQhOTxdi_9$JU&~3cVQv1|mdf%0uj)tb9vJ#jh6)o)#_5FS! zpa$95DW?vOlEMlKl|}~W_v1jCPDyFt&!3No;L55M~ij`&d#WE=IZLI)@CVp zY-gOz35ZY`6XSF`y?SeBP2|lF))(CIDtLO`FF%;~2mN~CT(`CyCvB%awk~-R>Cb|1i?sk?*Z7?^8D-uy5(4}ZH zk^b`!ihGcDy97@bpF|U(Y^#0Rt=d-qLNe>wgwCguidc$O#V;70P;#F80w<(Lu9>5f zywk?n?oXs&Qdh$^$VsRROz|(Y9qO?f@c$Ngmvu&t^nEbNH+?D(eAeLm5C(=)5NV%r zF(PJwe7Oq5%fAC;VM0V@wOILNV(O}@viu-Qfn8xsXrtvRAt3>}EkJevIGg+~M_;A$ zKz`p3M86z1>s86;<-^&7D9Fh{<@5u{ACuT^QaS8aXR9rMH34Co;#1xTvYqwy?99x_ z)YN<6$FHy5@IxklN>^1^Z>&G-Qv~c9kO@diNdeykTv`|rw@BWYPtZDfeR%dZNatV$ z$S5elAb`ut&&gqRIa)SmCd$sq>5N5%L`O$ET%Bxy*g#2130y&ALqp9&;j?=q5IMkj zkVb8GI|JH}Qzm4D%*K+sy1Hs=cxRO$c7FI^+aJ$pwTSr!i6PeNBx?UPTB&Yn1by!L z+5C&-U&79x2Vj>?lz-rnk*ZX0|~(=M5(OAiMV-$LVj{ic{y=H1_v z2y7CgIHg{V{c>)FmWwsSzNy@Ky;@tzA${nX_8@V!E}DS!-tcI*|I*o=IzHte^7KPQ zlg;@)msrIs&}f#(BBrIK#lfAD`SYjcU^3_UA8kFo3?TAUTU!g>v9h9bTm;%|3-j~q z8ygq`Ab=^Ro4y{gGB3@|rC{AkCKGdYb&Vtgz5--D8l1zR@y@3agla`4r36W1pwk9) zmtLR|zkl}*xOTzF?1qMGU?ghqapL-bivj+Khqx5jX-qOJ3kz6P5P|bkgMe>X33P*i zBX?UOHAuogya7E>;7{Nsn3$LZeUT$#W4k{51hP;@dOi>kx2$r372y8(9Ud3A1=7#0 zI8$GJiEjOJs~ulpH&b`X%ROp8NIm1)4V^kpQgE0Z zb_&Ok7xcQLkuQiIZ7fRQbFb^~i{C5GKH8-Tg9^Aern1g5X5Hx@Xrir{zHIa_6=!A! z#i^OI@Uq?CPaoXiEKv-8k;{Q(AC&Li=s|Ik12v}lLawN#M@M+W`s13^_I_tTyrT!2 z+}?THdZV}NZ8j8y7P5FJ=SkYCd2Jh^uH?+!7wXqbX>At>2qN0K-|d+YyCev@;8p9_ z)LmZh(}Y%%2K6wwlf;E*Y#64eZ>`TOF=&xOhd#vR%h}=Pe)({`f{(|I(72Frxha`% z4u|=Cj;n*gQLYhAZnrA#+!o`5Y#wZGe`+yy{@J{_asFO%c4)ZBl9aOlGv(>~p)e0G z``F1=BVBg;t(liZxlcacL^s*;R@y#|7Ocf3$V?;n`Om;w&;Uo&lOmN&F`-&&;Ca9> zWl;yYVd&aEXZSX~oDn#9gE7Li6&Uzxq~}TT`aFnZs;bi&i4d{Kz73#F>>7#d_;RG8 zEE8gt3uMATw2IsnlHUPewe8>rPA0;_&s}N|THYh0J&nze>yr**?0y6RX`+t2(xBX^ zspzZ3!Uh`F!VsWL+LvGOa(;0nJ6ny1zIG-mgsPt*c49&ay{Trz@w94NfLBIgOxB9< zZK(|3%~+w;mcb}3B3H^!>ea;O<5kJ$sZkN_9@Qh=CupBMUFbs50CN{@sBh4OAi=bj z&^52XET2`Kp3bKZMKd65rSRRmaZ2rcQN(hD{edPfspk;y9$Fg2NM<$3PbbR#I0UU) zof(ZDnDwpqc}E4-m6d9nPX${Z&io>}_N1qrj+~Qj8Xw}hY^VCx)+YGj&4dca$&HKC znmB@pE7Yx5EfxX-9zxx+W~=8>t!kaNt{IcE+4`%uUoaiY#-)@2l?6pKAml|GTO zB162l3^&>8k)PW*2wgAYMP=>DXuHC)rhbU5d!w=Ni}Su?M7}v~%C<1K5U(EqKiQq= z+oAG_OVn@7mX|f|qwjvaWLWw1drwz`ZX`K1Z81{s@Of{zBc{+H$*O_`o5t$#tO{YQ z>u^K+Cz!0@NZ$|pCv7&yMZ$a<;H>TvD2-noSS-l`A&wQl*8V$R7y z#Uu+UVYXo1y)B0p<%bi;h<)fr&so)QCdIkKbdoVN>>N*;oq*1;t>-#(s*m3x@bPjV z?QJamaiW>$@LvdPA%=bpje(V&H;+t5Q0^=VgZUPE<$e_kR6`hzN9HDljM&~by+6M| z>8|V?@PSy+7KIlU_&A~AllBoG@*F8HXN2Zv7X}+q9Cfm9S27lRiDUK07xvf1{x<~$^v2ifiRxX_ z?XBG8gI4-pkVYG(4+NCBH$ReNl%J`9{Dyt?}%fKdGFEWA|FlUcNR1;Ld|s_NqMdpByU55sFR7ZyfnQ9GV?M^mWoIkyGQNa=@#`E^b}Xilt1z3Js?eL2`~j4Dcn!DkPTByPOcsCRKgLk>_pvBmDk`K1W*-jFUaeiUKh z>fc`3@3H^@{$7Qfe?m_1leX{>qwPRW)#hOr%bHp@J)IIau5lJkQMwuCY2V$G9yekI z{A$lU=RF4m3*3vxmDWkuTuz2m(wQ@_(WXjP!>g%rl@U}eXlSU+8%p|7r(3NwO*Blz zV>LM)$|o(_wjr2ZiFw39?lc@omyP@sLk+o&o1etH<}CU)=tcOpYVq%1#$NbhE~!dD zOQ4rDeD|Hd(TUVCcW{Yu+`L&~?()*-No$z97m~>h3{tkr^)l8*A@k5XZHK*Lqc0Ii zY`o?l5hEN1zR}9?+=NFZeX*||`C()1+uE)X6B`NN;%!O5tlAo#&|;H=|9I}EqO6eg;cUk!bvJF^760Lus+Q^EI{NwukAJ~tTh@`Crzw_` z;zX~%$T`d_oclwR_+p?Q-C8XbuK1yoR;ysz1&*b6#n;hv4uRs?XQ`uwpX4Szw$ia31wrikGnXf>ma$29cbA`32c{ zUSgFg=6`LTT9DMfF!ReCJ58C&JG9hdZ5&wg^74!-%k@);cgZl%OmF|~V(D@^Ez{V7 z$uLh&7H3$~(OzA|;bb4mpE{N>haBNSv5I3btj({KyEpxkK8amq{yyVS*0n>1%b8}x zY%$`IhZ(XMXwH1?@^+h7;C1`lOa7g`fGH>VJ-!LOgy0{i-bAyA)NXqB%I;P9=fZEny3&imcL!vUe|jr{kAMjkmB=AA=` zxqFS&U$h^7zq{FESbISnggUuns8j$v)aD?jK|nyi7xd(a)=#)wfNsMSab{@#!`4^(^@Q=6zF=}}Z{J7D zBsfVGRE58)EyY6@0yy6pRY7ioZ#+T?o?WyWlb z)?J{G0@ul#8&qRjW}Ywe_|ib_z;7n4$N%tRu(aUq4$hL$0f}Yo?h49U9o!hwj>lS zp~W9WHF)0ZgdpK2PVjf>S6(*ZXw&)Zi@!x;t!B-czrT39lk#=F|F%l&hZ^G92Q+o( zOKAaZxs$5`RiWv&ET8Or9~Km;>e;q7b-g$#K1VldXTZ)WX&U&``&kBBQG<&aaJ)** znaJVMH?qRwE;(SeB!Kktd0dihOXzFDv#DIM^Q;+2yLxPq!5MXZYp#)DqHnIcpt6WT zD_-guBW8g;i!M6xWtfsjpUqabO|J&*IN*Fp2vxR@Me^}1v;Uu48b;F z4rM`!*cdt&;AX~Wrj~+Le_x7Rn+}<+Vlbgeb=x{!xFA1!rr%d& zMpN;;1+8Zlp>fKxHDRoHa%hc2y7Jkzhm|86rcofY6@sY3dt9ee z@#97rNvkjn^8=NN6m2^0bx-+m0biqGRrvP83WEi@fXji;Qka58{oGDxrJy!*V=4EL zj7h6l5;|^z9;aKA)%L3zlA zq~uuz_I9jhfd49LBJ)B()`L#!QI^7MRO?ki39$<6onov88+>IEUoOS@WLivZV>&ReZB8tkIu=CowNVQ~EU3fftAI?q#3 zd1!fdgdh5WX=-Yo@u-vD^pKzvqQn3O$+()r8P7|5vHkXS0B5T+BeIHUX!|5-TN~VC zxk)_MxH0k9sXl$g>y&b4;bA+`HI9eFVCf5*kwa&!(My}=^zwxlGHZ48kGHca9eNj` zblevpe7gOJM=^8U^!nNLc8c*lQdP>@d`8jbDZAyzHZgNKNL9erVG-9DneNv$*?yZ+ z6gkca#)aF`hiAW$?mS7h9lELod-4lez zvgP&l_j7S_dY&cx>fBh}pmEl{u4b&6{K+*8Iueus($`L#gb!cCb^369%`zspe6;jL zceK0iQEhCTVFOfW7j&kTm zY+Y8gHa29gURe4jt1c!oKMt07FwoJ-DgDJ#{?Qx!fAB%6njd}t`t5wq;UjkxJ`0!z z62d$}kN_Mdc{h+zA_a@Qsl65t&u{IV_xrvTe8@-}mad02Bx?@)CPVwE1xH2(O8vdH zD>uOH>w-!efeV~tJ6@`zS1dIpOo^8EUdLHljp*#ol(aJZRdwppl+L4j+ZJR#V+?uCvP&cL(mBbOdEx4)3H1wul zD6%ABFwzhn`nR`mb}TRG9hg`dt1;aP!=hcA*kmiXxOK-&RB;K2dcEtH6NirPPM~p# zdflHhuuOldSkKV3aPfJ>mt0+*RVR=VPdD5r+^pz{5C>f5-;Mw5pz+FL?p>Q(pZ#NS zS&9Q`C;pFbPv8-V5d2Gog|jbJ+0wbK6aylfl=w5U#r_6FYVj^qDG%u=L95510T?~p zPCGyLl?(&OGtjVWq{0o=p^x%rd;8iQW~?JJ8`Gsr@@W<7q}Yx_>NuBMh675IIu&_l zOR_Tp%OSdcQ_MuvZMjeKjvIU+sAv<0D7KQ-b*(R8HFUV`FiZA){Ob!Hk~qv($V$I# z==8=VaVP0cm&Fq^bf(gVZXzl@A3@^9e3n)i(vS@b_u_$EOMqm}sm_`gX<`HlTK<>p&XE;Oc+@o3o6u6$i!nFuP-B z7moYZ$$M3q7^^Iq#=`>c9ih$EtER5g(=<`nxsFPKuW@KuP*G{K&3Pdr~`|HJtp+z>Is7uw2q=LDLDI>yb(Ncp(Lbdn5g^4xxM{nOynf$mU zDB2hwm}Zm_j4G=gI-H5ZdDln;^i)~sb$GI|CCQrnwq=ct1o4Ok4;O`Q^m^O(`}aLk zxts492+rUr?q3+ZoFa)?9@9-o&mIz3XrnNR-C zMF0?ffg25wBqp6Py}ItWN@H84+}q(0j14A*bdL#qxF(qj!AiNPtYq@|ZMIJkqK!LX z?qFs4BFe|Z&FEC1tHtSW66YwlE~es zFkSd&S$I~tAD=-uCVJGs$?F8BVI-IkWg}^4erbAM{*>?dzF(VAL#A(_fXB>T_^sj( zT`*tZb?n4@oyE#i@-3{N9ED|QlL;6rsS@=dO)N8u3R1CAp>H)lZ^*E?6^GEB!Hv0Z zfZ2C<8P?0|>2=o^kS**i$(hglc@Fn&Z+=GT+BrSuLG7%c4CPfFntk3PU@dt~y5@sd zMpw}{G>TC}rq_D2JN#dxFrwexO)Oza&X0Vq*O%s(S1-7%?P`%g5x;~1m};xn0pb9} zkYp&Yux_hWTOPVh+fp$^Qpv_IZ_afoxbQ=6QO8AgXdb=!SU_aKPy6|4gn#F2tm%Y13@H$=*P=rmh}NBQ>zeydApsF*OQrGX#3tU zB;Rn8#8bpVK$M@8KWG8nO8h&Z&d_CxoGe&L?IDHFC<^h&lJ-Sp<~cQa6QqJ=0Uq=)@h-LYbFBxB_--E zBYcdPx_On#Ck5zUZU`442Az=mxBas+4_Q@EYoEVj6FY5pYs#b9S^fL!JACS_I*^PN zA(cdAiIb%17n6Ix8cfa_l;18QI=h~SZ>{PzR*hl7*3jx^#nO&Ip(Yh1PK^zX{d0mD zMmHxc+6*l@W^W?N=mw&@2nScod33ukd_C{K=&oLJ;SzlJMS;Mh#=rF#n1sdLxJUx& zBfSsI?B6e~Q+$HoYgDWy&2obY2gSTyAtZ^rcHILIrxthJCiz-F>GXGcTG#;PBs&^H z_t{BI;#Ct|vI7$H23BlVI+QSvuWO1 zQDPMByiM;~6O7=*86xfji-jl%>xn7cMx)us{)%bPmVP6u|Bmp94_RLM=zM(^-O`0u zvU6~+Wmm&^yFGig-fc+s@&{bcNqMbQv0XgewTDv*J;N*rWI?vd_rjm3r@18-#kCm} z8T?Fw@cs@{nU!e8SVNT0kpyiv>oGK4&I6f8;ktX>q%fa|LS#{qgy5rM;K<`9_Fzks z^b{3EiDL=BnPq`q@U&Zs(9qm&_9`q`aAH!rKpROuA&FKrc~?JTO*%fea_25s+l-Wi z_+NZaQ_v!iABzC;rtzn>CU*r4zVP!5Bkz5fPD;g@DM<5sT zMkBIZQanN-)9Z?DbnYebe4@ER+$WQE6fJ$>x_9uY7XYiaORq zXG3wEi;dgrk8VIl{}=4IS&jWnZkZ2q{$ZT+YfC0-9IRhsV7>;VlM@vQ4L$u9Hobx}76Gpx6-gcMaL)eo9%O9A07pRq1P z^18783Y|fX7r}7^bfc(;p}~=Vyxl(Tb#h@r+k6i^!7^~b+1aR z6mWR2qNdhBzYl`{mzO~d_eZAepwe+G;Xx%D?GqRR3i$@?jspJoJAUmJzsZ^Nl(#J zldeJIYk~5^?Egif1;9ashlWBR2MBj@}=fmZ3VLP)uvCVG5*BAd60 ztPkTuWs>!vq8nSAPb1h*&TVm@qz9&Da#Frhz!GFNU+VUgoTib1G68auOc{C;8=E5P zNxmZ6YK7JOdn=$3vJ#flQdt-aJn*uX=l{0ubpA`K#=S1yMlJoT9wkVR-xa&nBm;Y; zU(haBE(k-kK67z4ioT8}GfK|X4Q(%mPfc9Xd<$mzp^baEvu9(w$8$Zvz0K{_R8o`( zXa8+#j_oI2>y{0eZ?W5BDj5GOBmbY3o;h3(Nez85TDrEq|O+R4;B_!{a(ZS%dZjd56KAPKw9D<9S8rdkfj?VtXBS04NfM zA`A6$`r;G;g!g#f8w!O_c6z99o?r0Cf_T`xrLx1b9F7Im7&vIIdFM2{zi*s`2tyPuR>Vws zIm&*~B=$9tZr9`dFRTzQP2+I=LS}W{|+T!$4)fq(_7A+ zd!<-+GsL?ac1@*DsQDxl>-m(L%z2!a2FZhNCkCFoWs3H$pKKI%Z*Mb!+knB0KSIg{ z$hRjhmx&i6`q@nP_AZL#e%%8TrPKYpiR<@6r1|n2NzNtPNcrLoX8Yp~7TlrR`=6u0 z%Wq)0--AnKNvPWtuTN|9*P9NKAjYTUO1&YHHLe?xn2Dqa z%9`r)B1T+h($($5`js@r`?ZjM@}Qvj?-AY1b@x~EsfDtGtJ_CZvZ~2n8+5p)6H)Eg zl;A};PvQ16`q-}W86Z`7x#HJ(S+C_GP>c`{bN#f%V?eazOpgcZhE6aLM5K$%?~!%5 z#*roC$tM=(&tl%s{$N?LNoz?zH7E=${5j+9eAk*pU}kb(NQZ4?{o_YOdSDBq>31Qm73z2lXhGfzq6ATOSQ8Pl^q`8sAq z*6V?Sb?ecHc**ZQFEt6mX{y&#tP&O6k0J%r4c;eh3aS&bmeTf@N8;BS)Hz5*sf(|Z@7}8 zMbxAuC6^|!F z`=Tq!=E3SZk7uy^1>ZVYZ390g;`$_6K-gH&!{dS*^!mbp6&`QzgzaLi!&5+S533tc zt%I+_q}01}oxc6qH7ea{vwrhxV4}0pI?-E?qKHq}NO*#I+HVuick>G__7e>@Wtm!sF^yWvmCJ`93RV|zr6yZhZ`s`t!x9e1~9`HwqI zAh-}r%wDxO9TxXwdt+LfduP{vJ~pzesvFHv!$7ygYe}`AEHd*R-KFMGQS#d3WQan+TZmj$om_ZCAiB+c zyMC?BX=l{f+!1nx%CZov7q|5iX+Y)WzE+|ILq{r}7Z|;6di80c_a&+e)W-F$F*v@zcX~zY>EQaQ8`&Q5Ma(WD=fVUiX>X zmh0a8i4;bMt2~fQi@r4Z=fo_1UiXe$pC5!MqPDE3r$M64{nDuVDx05?!fdbQ2i%;; zSWvqALHRP)AZ&UHA_y?rTPs~fE=i=jc`*5*! z9u{_=yp0>G2+}IKPk{8Qe_}&V<8r9Kw|@E(7T4%novL=4mZ$74LI;PUF|c3}dwuMe zJ}Yj@7C9BHad5!+qD_D0#I8_SQ@>Fz>s^6I42?kp0CwE?|1b+bxFi|}uS;O%lr>#$ zWPHe!2-AK&bK4JSZ_MOt?{I*4IAoWOQf9YG)!cC7p4jkwK3(7X1!Ux}43+^s6(SbB z(+Lk88|iHXo;Q$WhOJ-sa{0P;e34T}y6t7h}WKyEzDpkGh7k4d(D7Kfa_* zaj=9OB3qeZ@(SC|PInkFxuCgu+w0CtKD@ESi=Ag!zDo_eL=a!ND8p?yn2)27$Jc(d zOz1?yIr*CO+0^Rs?J&rtN`&@8nc#u69N)e4-RPa_4@`oMzo<|Ax-P?{LaEPvM&1 zt`w&%vfDR+QM$Aol5!bY{hhXV4^|6rXy^JHTiVhTM@5@oiz7!4U2twEZvk`|CWr+r!nxl@3icMwsdVlcf| zA@-z|L_vn;e3;W;hl94AFCiRUI6u(S77mhGfLIT9R@S%SkOQ$FBmLiL7!ie+%#T^B zLetn|A2H*G{z&talOL$<+~VU()8Lhy+h^P=s4Z+BF2QNGxM%eECzLUu$AMNqeI{3K z5j`m)#-geN{t;pZ~mBjFKf$8P_As4RBV(3aUDn&%SzfTv` zkB7$I*bQ%=?^I`wSJXjSN}V=+luhpU`OD#s6G$`CsB9bHQ6tX`?1Zg$AiokJ$HaOOi>Sn_!pNa%DC+te85yU}QfXwwYUj=< zXU$o)vL4qGWN_g3+~V>NYqY00?iX}Q6;IbUDx$k=1B=T>RM1f8SyPo27PHGMhY#&= zLwJnY7`5yJWQGHtA?|-USB^{&OO>)v@HC30#+&o8VGaEQ7x0$yOH;>fj z6W$pP^b4MJ8@(Nfs9tF~r;IOL%(nBiR#cKeD#Thc^lRA!N(qK_O$;UmV*KFdGcu7M z$lt{wNE|Sj8r2w;5t?*`ePUbS^XS1R_e*)!%k?SJ*22Bow_Y!uk%S+`M6(Z?SDV!{! zfrF_0GIVWn+IzfPc!#?IU`)nInBn9 z|A=DQ!q##ESkP3-&Tm$gJ}D9e4^NB>53^CT5FhlWsy>W0p0;fE$K)dY8Yp_wBZs^? zSx=fJ=@o$?swqzfx!7PSe#(XYgC!$M!k%}>=6U*67UuLvj8hXUxby9YgHU)c)x2r) zva;fmcBXf3gE!F^W>QCox}Hpv0TjBgI;uJe)&w4A>e*7Y)q;gN7j1eT2Shd+(@z8k zRg2l~cTq9JYv!9t=B$QGm*5Wb1X)088PmrPHvUw`jrOG6Lf8TOO8~c+g?Np@UE1Qs zm;u5}z$fh<&tqSmxLdPgjVM5m!Fo>Tabo2iyOu%-RSHl(WRZU?_*f#={^Veg`(b@; z#?KeA=H{pAIoHW@CkEN?!M|L;ck8Q;AfCbCaZ~uap+huvV02f0=eRz9Wy(o4c^Sy& zKi_ztUNhe4JuM0= z`1a?%+d@ff!aktW|5G5MMp7E$&GMhsx#XC{^eSUEZET_d3(*E7q53Nd7j3x$x%Z_p z$zYpJb{9Vq64re;8@f!KJ5wc8v?yz4lPNo8E}`IZ36GTi8cb{I(&CWoy2WHEPIYK& z^j!1X&$#{Vz=uEcHy#Z&IXlGw3bIq??cm0-S3{H+Fu-BqB!}U{s`gq~-)T-Z<;pG% z#&n`up$rxzj;xH=(n#zM)=qlE-A}7`Gw)<7^o-`;=67=4Ahi;@v5S@K1`!U zRVl7!s|e!cR!DA)IWyk^c8D3cNF_Ie#VqH!3F#|-JMuR%NqEVw-v~<|KzikQxf~$w zHPoU}eHA;&8MRO+6oN6NDKQ`pa_;}4ho{9!u`MaJ2WRRASD%{Sm)Da2J3vK6&F_E( z;Bg0hUmUKVf*N^o1PaewGhGkEa!MV40WVBaO#r=**A`uhHF~$s)Sq9!sYFTewZDlJ zju{c~Vn2UZ_K&}fV97TNF86S{wc?3dLm(1izsIt2Jl(y@2b-bG59#I>uQWjhRs`e$ zLAXAMI|3US8Qdp^bf%dSA)pl#{)9*TV8vljYf|10TfwxW3NOJ$3krye|jqCCZ+o#id7bW{<>L1*>g%wf8{d8s7%WEvjnI zqJNyIMdjJOno2=OCOpx*{+OWu$fQnN9KbcJxc12 z&G|Intb4lrcV?|?LiycG!>EG@>nVDi9S?rDutmEcAHIS4``bd?2XVpEu=8ui}rQyZ@vzN)Ox+@GWX_0?ApOJ64JG>}|Ot6}? zeZ`F#5xJ$%2uIAN(SX0V!(1%~YnIjB4@4|=PfIUbnyG>of|>Jtt&2bu;yv|GT4`kI zb3Xm4C8{iBv-EyeBKr7od%Dp)Ha?y`unr5Z}l5~u-i=>9vw6t*DTpW;; z^-s;C?+V-P;bfdlx_>>bs=b;n!H_<6XTL{`Ent^ht#nGh$nncz`hm{-Os}=I*Y%Q zLyGmxHetY^Gc;_Ear_)BhYbAqH1EmAt!~3}x6d0%iBo!PEKA=0Q}f6Yt{wu)qY>pl zPn>3|>LrjN{;DPpM+&hw(=x~tkB2pZ_0aKopu7CFMkpYdLh0Mt(=g+e7s{m zCSgmKPEJK2Q|_aK39%wXWC5@C2;n`^nnvthx7T>sd?~QJKCbwH z@yYj#dcVg<=O3hN3#sGzx99InOe=a>$YY6*v^JXQIy-)BXZ_Bv4Zz!mHqG#gV(Wb_ zljUbap}@LgZRBfjXSx^97{m$NL*7Ra#F~bxsNwWR$nHwQV8+e4rYE zYc149l~~=JRqBH9RG&`pvIW086ngp38M!qMXQcANC87BzoeX-Y1n)+d&91>@bPFyPxf-1);^a9ZFx^Mx9(pb*6#UOj;j@YBIAkXkPJy2S)j-_ z-L#w2&64j%9P&|9F;*)Mox3;K$0s-k>pvXP)0S@QVP@bo`7B@lWV!UhKTU!@2PZ;Jx^5}aockOWj`UTBiG}yT<{^FMb-!|#$?~9CBkNNk zi_JGDkHqsE4eC|K_B%VtC;ia&{j+u^dCW?>EjwA&+O+@z1UWNg6P7ol(IUN?_s#(r zsGy@3e{T+2CUg#sHoK%~?byHK_Hqu1aVE39%H_P2 zU=CFNnrZd@ZYS1jg+Fn7I(0v@t988c8hK%9k@&B$5bj|LMjTVjaL9i2CGeE%F#@gK zaH#<@v)(;=-eybwev=oAqMtpir!KYG;IRYiBx;NYjhu}0voW2Rp%jf7rsf^~?b}{( zNIPqX&6yOscw|koga38-w-5*H>K9vgcPDD-*OyOvOV+b04I7WlC#w9tzkdCy$Ks}^ zms3@}+i1LwT0t_98HkSX-9t(&3EOMBu1c1iw+#{wPM!mDH0;VBK`U%ZukR`f00M{Zd`y0nmpdDX7JzT^lF zr8%B-iIrvbaa(Vs&vgH)dO#;`o)ngiH?nVGdPEd`QNGiy>zh^j>Yw;u@cZu`r|jlz zomG#XnJ;QWpXt49*ZSDa?d1>F{p5et0ibW`0JbE1yUU-fgML%7_T*RacsqtbBF`$z zyr{e=sQicMOw&W|NCD|z(2(Ih{m8m72Sm&LIBz}d4FU!f51rNUNjJ(qoShjN^LeT9 zLnhsYG!as~_K>qT^QFaIIg@93bu@%@Of+}UPb!K_%E@U=us$ZWLP7`?AD_Cirm5O{ z1R#FQS!j`$f#i=McjCp7i%I&BV!dpb5*`8H@T}|O{i0OOkcT^ud3$a8Md-!>oV`mu zJL_-Ewqr4{(VqXtsDVhqjU__=b}@)1_<6-GyZHBsb+-Z57!NQHXJuc7Pei|T3#bV3 z6a`SL4SGUD+cVcTG$w$@OIN4xiafv7PvKQi1rdJ}ssb-qKM$Q>L;;jy5ouk1vTsCX zMHyY2?2n}lowqHeG>#_fVcOra%q~{69R`4Z`6y0ynHo1-5 zLnfLL$mR+zUQ7PMuTb6+}jZX2Z0KS_|Ip)V2MK^B=kn__$=TY$c)@ z-Ls=!F?a()-VFz!Vlj9JOUorXITPINZhL!5gajOpOtbD-Xi>nw%YAoE$&}ll`Av)q zqns6p#(952_E0e7_v+pW{L0<6eziMnpjB|+dg?ZDVH^Pu#7BEL+OrJ>bMQhq=pusm z6(B?e<%fd)O=f+hOsecG;%FtQB%HMacO?$7j=Et|WROwG`Z^}cQ4!6#8l0i70Wfhw zk%4J+8|(|2f}coDvJ%RI5_FnTX|7i!otYEeYCr{s1CDt6${sx?Y48C)1fKMy13eSs zC<(0YWyZe{Fedu$v|9{An~9|qsxxanI|Pj;6Ih6H&-Z^^ZC%wWmD9eOx15xsjbGsN zS9QboWRYs!IjEXDu3RlYP>{Eb$zs}H4dp1dkXFN!aZh|dEe-r6unC80q;q|5O%FA| z0x=D;_fl`~?Bo?76A*yZ6JXYmfA3NvNkpmms8Y30{f1p^w!a49UiH+Q1;GY8@ZEzO zjuQy*X`A+&K8`eL=aG{HU_W8!noJ7z#Gqb7^aMukjBxqe= zR+n>3E0#xx_?%6(-ZmmAZz=e8lP#_4|JH^Te7dCd^|1SuI5ZN!>o{AO~S;y=O~ScEr6oAEicznUXRo$L{^>DX_x+JvcjYt8hYP!*6U6cB+ujmct= zTh)*gLG<5pzed85wG-eFd!LbC*i#;i>|_UCind%wL}n%HChCs{y?Q6zWVOvm+ApU3 zY&$t#-6!e3{N7^f#ek{!vT;0Nh-F&z@bQE;Mn?kx{63Un3ZeCHYAc!8caUE{z$ntr z@=d?f!qpBySxmJmy$Li8$-cmBztpOMFs|Dp{s^xCdYvrQ zdNb08Rg8~}(^|Aiz}E7cf{_RP`Xq2VH4*W=eLmG%b;|>)A$op(%wR*%`5@I-QDuH3 z>=ipQ-#XBu_kh*5r9pK&O%zQ488wgxsz3ok9I>OImA@=B2LvtXZAr9P?VE@bMpGRTDw1YvAwOs*JudNhif>J}uaB$|ln zEPqRWzFmF$1PAcJ0Bv%)>|7#O?t`d|Rr@X~%fE$c@3ZOOoM=iu&j(fD^IcTm4^Qsa zEZ0of+MK3Zm8`PxlN`QZH9$fvl>)WISeDcut6{U2FDD}=0eiz%~=|!r_T=1)m!F7l! zk5Q44#WzdgSPQ#yrmfv&l9I1+VmP2sR@5Lb`Z9PxlU^6N*q2t_x44nrCc_L4JCa{i&2?p&c0=G;@qunxS0b8dtYBck^P!!KO^XwJ9Sc9R)pit;1XL{3n%J!@5fU zbpcd>Q|v&ut;5rRLD(rZ{gckh&p+X3N%AraVqlw{>-DsVpm4fhbN*wqdz7%)Y&*`n z++3uV3msR&%en1Ad{Dd$?7i8r))Ux^>lE|$;pf|;>}o#JeXdbS7vpHC`zTdD&m|7t%1(wXyS}R$$jN1bpbHJd8iK z6wz2mM1W%GAdT4TK6~n*za2oRJIJzeAdO1uDoKPT`L}&Ml^fcxtBxE&YXACxnNy?ss8^)v+^2p$^ z7Svs_%c#mMG~qNIxQpDXLO4{b%Z2e{g`$Kz`m!#t8`FDod?z-<)fN^ILwaXl!`r4m z0ennOBwQo%isNwBLTDeYJ(Z7#|x&5zvB~T9j(M{+Y-jn z^w5TYu~mwYFd*9MxjD8Ja{NuJx7(6d(0w;X+;lBV{*3>@A`uX&4zqh8^d0qsr$wM^)w*~h zd8!BM{-~r%=zV$2iX+ekZOq9l%1$?p@frd%|l=tF(lbH`fCldfo)Ud-jp8?;6s2?YmbaJvW@ zuWPa~hlQVE7)K9`VQ^K_YMT3x?I^H3O?n$BbBd%&4%a718H>*k10N=xmF9YRMQtm$ zSKZMwNZLM0tFTQQ*30>Yco`Y&@w;B9O2JWHbnxptGYBmNu5s##C=KDr-+nBY$jE3D z?Si@6zFUxOxQNS0Sy*iUI$EYQ!+X|@%x1K^8GCR`P<=wuipU(lxv_PY>r(*((Cgw$ z^Rsyk&aVnmtfQ-{qmydu9u13d+hjjJu39^0p0!qaqG+ZF$%t5Yy{zq+@~|wuH2h{c z>AM)6tW|`sS<-m4-v}tlX<6AojW^-bs&XVFRJzUo-d0-N5S8^fxf5L_x;x|&(SxeZ z_wZciZjB7R*a8k%CmpD_NSJ%QVK@kDJ}q4w=W_L)?_wJ=v0Sf<&=LHmg*T@4Hn-Hd zI$aNK+rs7=hpGCV`C@L&>Y0?CG+P35vgVn=IJX?EHSdda7#}9ByJCBJI~+j3Z93vu z(oR5_(7P;1T~AG|s@OVTxQG~lxEr6+G7JEe6Ygsm{8GSl`IvY2Db>6^E6~ciezulU zH1-6Si&mdIvN5eF69E9Ko-a4OkVcepcxuZt#T5mHwf2~zF}$tO6UiGH;H#wFfD{>f zoPUJsEK#cDJRBLs-SxedMP<_4NcTYMv`cB_?d>>+k>dauN!_vDsX3YY!h%w2-c^;@ zbBsgxRvaaf3Q8kq_2SVo^Gydx*cM(q+Qr@OMK&?BIoxtK3O;K3_IUAV^_dH?52l^n zq=Nnd&ta-E4CLK8NB2dIBTBY0jWXs9p7(g2uD-qGH7i`&MHL8|$aXxUx`zhSJOH4L z{OD@Up{ub2YLHhJm*>MpMMYQ>&6cP^1i)owObhLvN<;j8XoY*?iMJh3RM6me zOWWh`2XoQ-CZ3ta@u67RgvFO!U41R8MAO9i8&^!(i3Umh*K(3j%^T2-C-Ng!KTG3A z@H0~S4+&69jjZrR^w-d*x5(onv&dxRAD$f4ojoW&G&aGjzcU^Eh+3<8Rj8_e*?-Xb z*z-V9Q`3e`wz?Bj&)XkX34?ra1prDPLh^UOr9r`6aWl(3U?Su}zMVAGJpk!Zg#r#6 zx9i2hkISdCS~hZ%`6+A9cTgp-ZCwjcACB^|#iPvLLWG^RyqqPJl-p(jyk%zsC8w2B zxkzz3hu|h=5ZI3n(jy%+y<~7Atjf#4g-b@(qiU+4KQKXc-fqXHs#vY=;+?F{xbA_Y zrdG*w!k;1kcpN9X4V;dz4W=AZ84}S6>y0cuKC(t~s#W4UdrTE9jzxaWVA6FEvHpYg zZ4fB;XGOc*MK4@Ut6(rqtftRR*SHTbj;5^u~9Kgd# zr<7HtxS-Pg(89X4Xs@6VMFqaH6Ud?pbWCMklsX)px0qmCoSI&c{Q1zD+mNF zp}TKC(XlgVp(!NXbDbLJrzfT5kWN5X$%MP=Wbg9~$|}o!PrNN(1s-bjtW>I4P1EqQ`)TIzDxUB(p(}@C-o=n`0{R$kpen6S%C5@tK&ce{(+5W`l=-=Cbe z)Ql%HJF@W2eH9X!7t##u*e}$6^IYpVQN&8X^z~UlzmW}G*hVh<17Ma-=i%iq@-fgS zU5Y_l5y+?Fd&m)s`*IS{O_Y$a7Dh~-%ciEH07?_GX#q#9b7X<}T(gKpGs>VgyI`vs zNqmHLjEF24rm$_TDthQ&=*p0ScI#MHre!o)P}=pr4u@HMk*22E8jz^laBeWL{W2=A zCH!j3!dsU_2nE`l^B=;NnjCHY7~0(P3WjZUKO4S-u8NiF6`doTtiMYMH9{p65vBV= z0#yA`i>uK#KQUe+?SEZw~24u`yC{CQH zfcWxWqsiz<712YeweP49009$cW(C^u!HOiN=07yG%+#|oK(iSbK+d;OTE~(IcUUIn zuy`5k@L5nD!jfZ?{nXdfa;7N}6h*dEn_?j$faKDj>FuQ>vjt#$Na<0`Z@ zzV{A1iT+}hVP+N+{b3J2PDfp?_JdJ!47|TM2rR>o*oYOJS5?=|4UfJaLm@CHgbNZ3 z5MyXrd^tRFa+&2OQs1dmx1hJ*#*bDXlVoFT-qh@3`DT`mfn`UYsfW64`NyPo3AYUG z$K70%94oY~rAU|4omkYPHI6MiG(1Hr@P0w6-RnwLCr`b&+n`p%k#lM_UZ3laGWXf? z(;<2c{MB?T(SxOR+p2N$TU-iT9C`#}DG(!z3YPQm|>G-=0Qd^3waaCi68Pp|NY3gG0RF5t)9` znwf>d1*)pnxf1z(qo_SHYy3vREM8Y8s7(YAMD*FQrvDs4-o+$0nu%UoeLfyEdO8|@ ztDc4{2}n|cj3$)dG_!Zjnz{Zh$ExttR*0!6&lK_Zrh z)m=+&Zp;4N$S1|$1XMY_eS!Ev9&fn@Ns~W)B3=MEhh@Tq(OF*uhQIwb!2Ay8V?V;Y z4T^!pC*jXeQp2J8;dCDqke@!i423J`<3pn|jm*+694J-b_!FBUhb3TiY9Z7uL(y!= zDAB}--E7fJDStRjeLX~FfQ)jo_Yqx5#rg_Os6YwO*ntlSX@#@1;f)f>W2L(wfn|Zr zM+W#T%*`9_g~*@hvp`y-Z#IeT)WOB5n@xX?QIEz@B`Wctk18hIIOQIu86-lRp8oHH z3FV!sH9;~+qmYIpq6`3){f1@%0EBW_<|GIaLr`H$%soPQGacg~z zF)o(&NX#_tGr=e_HPn>DJ_BOqFs57+dg_4|p|04^T=RGl3F4LfXBp7~Sa1x%O_ z(MKUz@&ZzTI0idzszDybyBldP^Zt1x^ML>g1s38{TTa8S!>RvFXBBTZj)U{BFIYb4 zJNeI3CDGcg5nJk}Cu~3`c-ux`IFBd!k1dn3L_>ep`vf-GbBO=Fcxs7Y}lfVL+vQ46Z7;DOaCg*>pA z*GbUe#80z1N~Hp%gD9iqqmEY_4Uh6cJ2$}U$?JG^DkBVN-e?c=k)u#SOH)82rBDbU(AM(c#O{_}R#1$y2<>f^-<=Cb$2x3QLF@Rf-J z{e9#!xPUR>^r&Zl3O*n3@hq5?7cIbz{cE~B8a5cAhN_g|;nn-Qg9A!Je_+dS&(dz= z^G)%3ypMQwb@e3r-=))Cwn~c^dxm@pCz?|eIv8QLn+9%`Y#1;@+QpurJCTCW)pK}e zQsy(Ca+o%<&X=JABn==}K=8zqQ}?Qs_DG6wZ1X+(FgTuD>9@|puh1+@3s{%Ssa&|x zNK;w$90{V3fVf%Q0I32P>Lx$(q^yy>EfB>sIHdR)Zs+|x(AtE+HP3QhMO4QcFT17~ zu!XG9ma|lka*5Lsucx*E06?-F#3#~Mtjpbh@(Wchkv$+*p%(qFGScVkVd!rGrmDJc zjXnLW5<9ln>u5ql7I(?Tknp|q&#_<(1``#P zTZ!xE6!Tot3SYgcFZ^f0vDQ?VCpYgI_{#lR=hxoWMUhsJrGeCM3|?tjm_W4s=WK|@z{Rqd+1_TFpGHRmTP z3E4oa@tnEL@W|KX*|2agoN2&%FNd7=9xB)8HKDEHn(r0li1^Up4EOd25FvdSY2wHd z|5jtL_YIbS>-+>3s+{#w)!dxj7ui6cuJM{F0AcuXzh)_z-TE2AqonRd zw#Ro+%^=Y0xWD;z9jYLjo~HqHKkA`BW07nu{LnvbcIT_vfvN(X2?NmE{p}^GD@?2q z1h>0(o#S1h{XWe+*^rONFWYDy3!Sfw+>*ZIfoJ@)2gsu_P_VfCJq!WqNyC z)*2RiLp@$q|HD3fv%q{}wa(k4Z#Jc`MhE?V?t-~yJTkma-~G6u0l?{ce?3Lxn`7BM zrq9R0D3v66>_-bW<{gdq^{D~SBuh@#=LhQURD_K6Xl!RYQhs|#`UK|0JXYcDI}^nf zqr1mC7w&qxVN=Ptl9GKoK>UFTK}if4Ek9m!PLA#P^*LoPKCj`uXyt2stc=FfOn80) z&f|={D#LtIWzRRr#(~R1vt>zoHQXg|(TYdsO-Y`V|mO3vBiBEfID!1@K zGDfzhgj`4`=CUxRJj;Euf8LM{-T)5cyhN&4!Kn@f6Le904K7-Y_(GFO^Q>)N)*P76 z>vvAh2CpzXp)4sOLp@iWiGJ~rx;LpP*m{vk6LB)pB14`jz$+wg-v0qM(2NHu9NtPabVy&O(N%FpoN^9Q2ehjIT z!iSjGSS!cb8P?N$RRH;<-yJB+r1_=C-Q_eD(nz&!+!W9SS`)rQ@T-}wGRdfZPj8}J z6nWO3kL5M{o;+6I71`~T0u2H$EFZ+E#uZxtWTJzJ58G9TJ(p0RyU9Vt2@s?+(W@X| zjN}q{OTl(*MP7XR*<-D4;gPIy&~i>pTpNoZPQi%0-z~U&6#XiEx*pI}m0;dK6cfRe zzgCp?vU65pl`P6f?j$PXu|q8a`h_|Co$BBj0U(IohMDGBUC3%6=hKd0-f#(%?=oSVua z@57?KsZaE44CGy{0)_C18pBRFMB$Ma)8!6`@84Ww~&^MV0iey?OJBqjDGxny6&+FL!b- zgBW)qKgp9)y~9ZKF4-S zXdx=`kZ};=T0kJ#-`CgN)b#ts=LtC=ICyD(-jNCu9o@jf0&x`f-u%Od4@gKzrk|5P zCPC~-AX3{9fhzA)3eA-3J7?};hwrElavU4|CH%aNy2dQok%R}7H+-Q6HUfJ~NG_9P z1HVuX1~SR*Tr!k3kq&aeL}~laKi<#it?s4}L~KDEhp;I=zO%!}VkbdE2oT{z)xYw`_chJkP#Oy3TIfJe95TM8x+rIMyOZee2?WSu^;Kw*H#FgL{6%*MB=7^dg$R8% zD=~rIvy1=+`aVHu{D4no&qM`Hq52&6s)kx@wh|{(kJN)(ltMn@*_P<>)o{wY=Z9a; zdkEPHn>))-T$_1SW zh;X4GC+bDD_WZ=VShsk#xMH?CUX;CZGg`asv4)`Y;5oS z?M*Ro;FVSz3YDarf|6n+bAUp#vMz9YX||aKP--Ghg*dGII%xoYWREA4Ufn63w{QuS z?>nw3pR2o!b2zghw8{}vRZ^Of3vAt_bO-5aLN`E|giA(qnJ>Wmw2(%=EyLf(2 zM~n8hCx&g%*4BzRk_%yB9%N;jMBl-*xo=ijrRg^D79R6Of%(8o1)^WBcQ_@|ZVd70 zr6cWh8MytB;Xou=EVY(q8>0Q$eaa%83jTHBjE{vlUi>GSsD@OWD2-(cL*J!NfVF@u0HrDbEJtdLd-AOg!I;ug0&%Ltk6*4#*{LVvMumF^$Udw$O}@Bt;IOZp<(8UMJm2_s?h$OH`Q>PsM3n7My4X(sF7`jy4_W^E zF*sN*M&-Z*1|a1lW##MR>XU(Qjivl#?YsqeyWMn97HVI&XL!8u%zkVe?_O>>yC)Nw zJ0=D?32#J6PGCAIrS+O#E5H9kB9StNei|Yb}Vwf9|2FSd(=In8#KMpb4hlpByT}ACg7>8$?*2@th1ir@ob( zT2*&Kyd({$)5BmJA{*Dd&H91bdlG>`qa*DM$}J$ABIEM>cJb{D$w^?6SrT-nFeFFD zI>l<2&w~!@^!JK}j7sKuv1XtIA*q1U#!PJg4$=R0N%z$IERO{cUb?*$q8iOla#CYd zr|aX+Kp8i*ORB1XFsM+LSdoHks!)Jm)0tMnJY>f*&H`5VN&rGz+?J0*TzjDje$ab7zVwKtw+ zr)ugF{QAB*5lmDI#_ezsSc-o^eV0g~E#f zp7QHf|@Q7xG7)B@^?+P z;~-Sv&zj<0=)QA#t7@;qlaa7DK3}JtlU)xxVVqz9{^}$yQBD@d^QB|OLfg~Vr4M5( z%xad(WJeP1Us~qcKQGyKW|{E-XgqF>k2L67u)j5!h6m54(gZ*>z`)j}1Qp=hXae2S_77dJ%Bvy)JjVphQkSysJ@o7(IWe9G4}{ z5*%<&!}D~HCwv#ca<~9=JCEL6h_zxYsf<$|;SHXTj#;;XyJRFKA%Xfc20hiNX=n(O z3KFkDZ4|6nGcY5v3inY98wkFT692ck)$_B4B*Zeh7HX^IC^;RqgD?#r9x%^pL3%um ziB;EQ6@j84byfc8+!m(c>e?6{E)%Q|F>tG|udgg2S=$7)G&TzI2ogtmhyM8S1LgVt z|2B6*+aAW@!|z8#L^Mj>TA1f)kS=<*wZ7th#jA)3gS9Wl4dPqgwZ6*G4{duH9XmRC zLgm=|EcRsPdfP#`YF46Hepf{5Dltyw4~q)H>tM*I=8b_AFZBj1ObTkc%&^uJ)}ND| zgO{w`CGlJs9Bg`F6ci97^NaB2Js207-0V>UBt z&9l=XYI#ko{)Ckj8X6v#R|wG|a6E9`adpvFL}t6K0Y`r_A^g{QGKj)0G=BRw;AxF0*wgdlK@~72Cao z9b2&*uYwt;f@ze7D{RJ4oKN+reU5ZL-s|;p;m3G$o&!qrs1T$KNNb7;8O-#l)p8wt zCf5TEYyERuQxnk^pPq@&(-`i}xLk=3ftTG&e5N>eu%MEssI7kLKTgcEtL_a0vAMhHK zwhU^2x0=W<-eMSWeqIJK?;RY+FSY}_7ZGrW@9f{vXz=kqd7*NDRz__9 z(0H|up+M<%Q9Yw-QZt`_+x?VtpY13#c7jamzRi7wdMO)KCH09U8{G^^oGA_ov} z*BQokEp6AbgA3`aZ8JeOoUN9*EiJK4VxatEA3P7&OF=w7?fBv#9n`a(z1XI2+xK!R z;g{a3V9T^vCsfuJYF{qwPFe$KOq9wA#l6Z}%iyxcm@WuYy7fA*qax+4xRifhiOpfv zr8O6d2gamXbKm_v6#MBL%gl;ZHv|Y3LrH{nK%^70*8hhKpcPKjgs;xfldDbomTGfL zlxU~ZXV>rVG-k%}w5;J`q=I&456PkO*xI}^)7fi{iDPT5+r?gmRQku71~KE~X*gAS zeuLgrzEkVA?D`EixXmEwx|Es6^Y(bys71Tz8%9)&RO02nS-mfq6aId7;r&}&_Mu28 z)AzRs3V57ZL{3lLd*oM0@)F62u|)iX?AYwHI)o9GXO+9xT;GR&tn|F5c{xob1uEr! z$!9NzzQ}-G!TWIcxrt|^?REZrhowX0)!9_Y&WF{KV0BvIjAP~AD@Iv+&BoE^GH;@H zvg=4{9tU#pZ;bRF!r8WrL0pD6rcF3Pey#mPstKYzZK)UwjcbI%ygXKSgon+UiA(H~ z7>q75iM$ssD_9+xlteFUr=b#&ihIda2o}|Al!%44F8tfH40Gc!QQmwBq{9FO!CZvA zr#GU%cLrEYY5xwWkksmC<>_hL8vd}&SvpUbg7{n`_}IT<$k5%DY6SV5d1{V*(&#|# z`NL5oaLEUF}pz6Ul(TqG{{}4nyi^LMW>M-P*QhgWDDobEY%yUQYs2~PK zT>0pBLxo|KP=m|W6iJfimw6e~tvXUE`_5ZER4Ur02H?0cjaVbbW4u%t4UlM?tJZ~& z(`~_=^NAW16|$3D4nC%Viq5yP%3*|m#DIQwLl7OoAc}45kyRyLz=4oa&|nZYCh8av z;~hK^`X7~E!1MV*d1ohOocl@_4GDopM8_rbucm|y2HcR4@uY+{O+ab$uJQc^H7VoO z?=Lm;$ObPiHTdEPRL}wRHc6ZjZ=pij<){_L8n-s0Z9eJre+hz*pi|>;A0&ugV`vvF zno|1vk%HV=aH)M!BrtB#F;zS9;|FXBqJt$}9DtI?H5tb##B2@m0_9^=BBHWUv0rxA z2lYKDDsAnbt(lFLND4-U*)eS5`-jDuja)fTohy3LHeJpho8%bdX=m5R<-`q9r8b!p zs|i9lGEx)>$`SAGTH!)+N_YKG6@9aF1r@$ot$Ia5imBO*DWfIA7n;mC*rjid7ur&M zo00~7PHb=w&5v-UFlg5_W?D-u32a)8cvGzdJ0p^&9L$7Y|Z`9Xl{7 z)jQ?(8Xk4zM1qjig9W*vl73j@m^6Diay0v0CswPOjU>&WKWZG-;2_28pn@-G<-TCP z<#Ah*xB;*KL@xK?hnUV!#QY@^YbfB>vU&#Q6-D>`Bi0- zlv`fe3Uf63ur0>&HL%~w)|Rwcv^v$Fy>*m#uR5ie1=rMqshR{Au7&3LOLpx~EuUHA z;myrS{NTDGZ%^Zd&E5ILL-*2+%5%VDHyk%#dg*R0 zqi|W%;f2?>Ssmb{T)mZT)s9SAAiefT-1KuvUNzD7q(LG~cpm3H+!u%va{3 zjk}(Z6h<*`hO)g2^RQUmHrXP7*=5zcD~heBRDOcHwXC^7ULOvnT;9mRU#;AtOtr@m z9bR|E@8AXH&(G)Y<zqU-F}Z-~5EEeQ!qlC3uOYfsXeF1>YFpsD=(Lxnac=T)hbY29_`QKb7Ea4C80c zQI{X-WFlUTUyF$i-Mil(Su zIXnUFGRo?jJ>h)Zz|6LgayZTI@!3c3gyc{Cl1eQkw2mjX7TPid=)nppr+e>G=5)JI z%9b1i_IT3L(Y9CDco)Bfl@}HkZ!x_@7KAf?-2C#&^?OE3Q6?n6hvlS$=}vKKI2Mnk zyyE<`ilWL)Eq3j$v+UJ~uyFId{T*t&+u6?wkLJnQ`GEmTEkSmQD(*i|un_U3wEO6m z_LNpxt+HBkeQe~f>m`R1R7P@ueAIt8-)9~yi7i1P$-NYqEvx3ul_HEo6WlTx01J4ULvDwD?#J51}fzYHY( zaF=+O+3S+KBaHn9yoRd1bh468-F96!uW?H{yDa|Y?l$f^ls|xLd%cY|OkJ-eD2aJt zF@DR1QsedIe3zRNmO43j`#V4nh5v4S);u=y(WDW_f^{aGK-}i}d)vWcxzI<>eeR=8}}r?*>u_#VjYn*D<=bBNR)l<%9tU%VR{9JG(!-B8rgjHlN^r;Fv;~e0Ot?W zOPXJJ4q4f_xFM>LNLeiBSZ`zV)q-zz&a+7 z^!5D*c|&*IlYw8MF6zpTxCfvjzF*rvju^c{L6%5ar0ee)=niIQ)nCqoHP=dXP<3C7 zXHMS>i)@?oba21AJU+&VrC$*j1f!#uKVUv>uwUQg!vA)V*$%AZI*Wy+;JeulD0)c; z>WoRZGATfqG6=CR`1^Lk9(#ELl-P)C@FN5*dB*DVHw$pYW-hu3+D-E>_#}eXW{XB+VC`$|#geY`T9T~+9K6)R zT!%~LW1A|T`_Sz;B?-yz-rl^x_mkje4ZhTPFOwkdPtwaLhmL9{-uoBS6kP!ZioxY2 zIv6+WSfs+hzQ!_AxHa^ZXeJPE&H%#bj@1ehK=A2{I|{Y_Dy4-9aejgDj20CS$1wxMw9EXn4*76r~Wa zbIm&qo*$y7N?mAp@hz|hdYzBG{x@+uA*wl-DQRvJ-;K!g1k>_nL(=FFl0-lL%I)zU z*;PBDGE)bCBqjaY>Q3_eFkuQ^+KdViKgBVIWRKi*;nw#J2mt&xUo5`Z9io!Iy}pod zf@qZ8*plKxo09f7mTC|sP~aOaow`UJbL}LwkDxsB#B^`FF%(k)d`>nN3>4&r`DevZ zt*TgTna`CQ#45ZGdcQyc9Jlyy0SK$!EydM82Gzq8=L>^>S7J;>axI6`X`2uI%B*)7 zt&<|M^1iodEXRl5#>XtjCRmS!FsFRJw_clVOrEhC!~By9{cH#+pnKZeE?XQ{i_@u8D^+Jv6s0#kZqqmLH$2PO$Wn^SI zyWdAZUqd{?s)SudOD(&wpkQ%-BF6Ei&bzZ03Bp#)-ruiEUMx4rL=3$|WCk=+tImZV zO=;_DYN~=djT}CA)aPTutLb@FWw*C$#HzRlaR>C-_vA~_6cDh43PGA_yJZ!YMeacZ zS2MBhX>QcWiIXT94%*k#-)3#H?bW&Y@ZOCyB0UHf59NoAn#vs`+&GF?bgZ@pNS@3A zuaYmz3|gm1T*!n$fU2!$FXu4LzdkeXscG-J;EEd?eNmoaC z`mHj#ijWNP`i?Oc2Ln2S151rBcgj6|NB?ePS4?e;9=TuH?@c2w2Gcs%i#JLb9415D zHKwb4w-u_{0%TrK=cg0ND4+VXA%%+Cc6N#t-^r^xj0;)k#4$C~64KPCA$%l|y3e3q zmReuP!jv%E?8<#qQd&~R+x75ECowUnQ7IDGPc;&f2}-gl6Q9(P{^W54(3D(u zb>C7Geb9W7ikLtB5|sbvzo587-SMCuN_N7x$WO9?Km%7>Z0)Cle4!tY5ISqw1`#kS zT9HQcD|7YA=1FX2tRkg#8)k~O0;r5$((7d|=z_LfX&vT`6yots_duUo5ha7y2MFlH zbTYV8Ad#nqB>!uAfhK%HQY>0_ibWK37?Mxg=NQS;dT%dDAEDePP;;-;ymGhku(l;w z3sYt|WX{qDqCV)X5XTeg&HvJ4_|`kKn0`+DP&C?r%bu!}R)+{RG@g(v-jv%@sbN5o za`OlP=z3ZbXDs00UU40)$-x5)j64&b^8J4mk)1aen|Cs?PyG^y(s{Z3E=bm)uxgTO z)-%y*46E}HBs1c(74|YNv#n2Vx{Dk%FHg_s}6(oys zQf`yKv-(J}mwA0(Zg{Bq$I- zP0cu$Yfn#6?ed?xElVOFt^bLou^Ac!>YZaMmrMS(99#_StlW+FHG z`Hq3V8gh$U2=_spK)bhFv-p&J_4(0L+ii@Y0X}!#N>+8hn1Dy0niTyBmf=ut(w!hB zk@Q8Rsvdfs{3#|ikJmU%^BxLn4ZboHXO)+Uh~i^ybPo)XM-S$^1esE5JOZDh+c9s;37;w9CmuOJ^Ouk~>k@kQybKy@rmUVmn+UKF=!?h1 zGgRS=j(XgGnC%s!!@#)l4X&0U`|&4y{K*NvEIEeX-44rH!T^ZQ_$OEAlZW@-GG{?6 z^Ro$vT&sD3O2g@2;Q$Dm9E)zP$+w$_pIBk_WK^CgeUs9BdE@QO6SpuAgQWV67ibd% z*4X>@>?=}i>Uln(H*jfK6=wji2E7sL^^OuoFTkmqrC~6Pd zwyNtKfBbqh)ii;oN)9|~Ijd}b@@FDY~$kQ|3+l!Vj?gU46YzIC(xK$&T zmM77me%`@P-m9aR>AH(6Nz%Dx0%xXmu$rFW4HOqPUPjl}6%FU}f;XohC7>F}2hcU) z$K$`_FUf7v-8VQsxcsycxBwXne*E;!KX`)^04;o;ZGE17uA5`!>G5Z>?csZI0>P=b z*L-vDZnNK9oe&L3Ny4Xv*hIp~xV+w2WBnM-{~tgjLFu=sK{6qQZ^w@#l8_vXfrSY% zst*(OwrS(SCD7pnhfGlaR=vqxZ6QvoDqFjatOaM7R~<5(c3r1$Dtq$pV?fBBk^ERO zTN`^hAw$V+bw>oAPk{%aZ-yUisSt!!*z8;;vG_#DZc}UAf{^{CbC+bmb&SBrdWRJM z!7*0Mmf|b`8s{50^@JbQf67>z@Fu7ciobuhKS@mwkt3C~rM@gvjvME$ia)l$<1B)P zQs^Z8dJhjHN<^vbit|tU@lQC_hSgV9nEw9@B5KuR&b|#4p%G(XEFRPUoX#is->CO6 zfUKVjn%sl;T(BSCkdEH2WggPq5-7lg0X?oz6LZYTu+ImuZKcHOEgdLBc z=N7cK88nl=TeSFl#(#U{eXvl0W6t83!1EPt^8a3bT;QmuH{>5B9zy70 zK^pPWVCQ7nH_&roj|#gHMF_i8->tu zC6;UMKnbvrbipr5fv}+{eDl=r(>3t7mpY>4C_comr&;TfX>a4!4iM(c-k3_6r>RN( zFIoq}Hc{|=pd%kXF6a1cT23FuhmfLs9Jf43GF-;aCaeFy5-WXvmqzgnG_$cFQ}>Zpd_VRxEUrtvJW=C2-^TJZeCe|CK69FNB>Hx#-MfIaHdya)2Kc z^gIs5o~yJFF7hW7_8tWS>18d*=84S$F`bOLgokKTq6@Q|MJ>i#O$O!*pqaT1bk0i3JFUe%tH772eo2IdYVK{k%6 zNRbwSfQ0`X)eAqCiszA@8mC3vufgHP7N1~_y^`D;K%g; z&t9@W%G=RTtu*0|yN%6kmnabMS@dO5W_3#*WtMIZt^KR27i0>J5AaEVLCXL1Mm%eNJ33yhRM|qayv*}0b{>}EV_^RI@Nb2pcV9;! zcVA6ndeDfJ0C~pjV<>NTr`}x*>HEMBI#SbGi2u71#EGM6Kxfib)Ea*pH)keHLaB0p zz6wMeVpD31h8!=JvJT_Vd6->eH*PQYH&f7Jh~cMlj7v(1MSQBrw-LDX7P`m=Q#B0U zKMI{kRg@v%D2V7hwk^g8uJj)=(g-cfV`xU!)a@9X224?`W#BsLrdlv}q*Sr+-&s zVY)t-;KeCW{?fCpPRYV70ZSv-s->X&_vK~%EA^o^B`#Zz+$2abIcyWMX*0X{%LDIP znvG`bZ~~DN_c?(~-1(i-fQd95Bq!JvcJ?$`u+|6OmGaMF8K!x+wzk0RXU}+NhQZL5 zK6$YNnU2G@ z{A}Zp87sD=(da_l!&~F5hPM_MFdkKDFtTk?dc*jRrsix^T=r*@BN;(#49Zt?z99N# z53fgg^1Ba|2-kc6rg3Q#&@r;tciL{ZR?X76eNYygS_W?VMH|E5m?Xe_ivCJARjXwz z=lGGVT@L*#9U8epp%P7;WL}g!4B9|A5fxdjm;%HsbL#j2NL^%i*3O$%;Rdm2?f?ZD zusUVG86!jBRua@;csbIRdK1NkRc=LaR#=fwTrj|X!eiAR?!UGFReY3ec&e@$oKeMb z-KDh|sOutjj@KdjBi!nJUGR@k2^;IY+ImN0l{H`Hyjs8fmB)mIXDVu&wHW~9TZf^e zxxBU2_~xaxBeFB~SgrT!azv_~pU*^T;K*)=RcBsg3~HHJHNSIM2eF3z95Mr^FfX>! z94PvteHMjHf7x#JTxzrqHN+UkS;BPmaHHW=u;(V;M@?n*NKNoh|8O1l7bo~91~@*y z&5jRC5n3F~qeap2`Vgzp^<1nV3E5qYdA78Wo4H;k7X zA7V<3^mE5e!{0_+($oFM-h^oJ?CPj7GqmZx$o`0r#d6!#P3KVo97M!X&=lX1GshKIf{a!uOVW#qvB@rn%ySDY>tMhGD7XBA>+#F~; zP;bLm)wvXpgf#_Cug{~HDr}l)CXXKL=9Do5xcJ5v7HCQMa5~?Vf+S87Iu^3#oYU47 z+CXvi;@JmC$a>{mPhsS5zq8G-`Q#Ul*JArqQB77J7IS9>IO4y|ll&!S{*9|o!^BK! z`8GU{#1v(@pU!$!uJ&h0v9xLX-$RE&XI1u+*x;kT`v>?!Ui0CAIAva(t+w%VP4Pvcp$IAL6m;r;aI>{ZZB_Ac z$@J;b+J9YWIcuai1w*ZajF=7K5lD_nG^2L}(G-G0vp2g!G~nxHwUm#{OJv}oKex1HK?nZ4c}IFdRNd43NK^~~%+L_zVArt{RiJ*bPg zT!--8^x!KFGQ3)(0fzuh3C7&V)fW}L*tH*PtkglF#qX3< zJIqYcpYsoqMU-Wds13Nhj0o#oN`L-Ds#1GOYPkH?g=}_~;hmAe+CGay5`ZSWpR>8o z9iGPKxwR1+vatPK8%Vg_I)dr1@Ql8?KbMrWL*v;lxdoInhG&qIi$n%^{(cJSc>Umf zJy!4I`;O%ue(_+8x*bsA!IJOU=+VplnA7{hF2ldu@keuG+ar2l?}5RHETmvylf$N@ z#{CL00-OgVUJX`FD;h{0G6YR zSjk~1=g@%q>zzjLoZE8Xa)u4gNHAOgj5E06)otrnTox3`w^#}1yHu+-<;T;JS5Yif z0XwHM;@G*yLKJ?rnd~^66!&6D9XCHTVFZ%t>(5!|*O6fj8DSu*V$9HDhclviPcoU| z-qByZO!%J{uWmAi=X4~!=|5S75fME(iy(O$+JY!9xWz(y^{X0Bos36LyHPt!bKXih z`&#|vxhGZe>=tOVzw+lUY_8suPahsiGzp2pTaf_C0b9h`bZKE>Cn+?fm0LyGj_e10nQ(vOq# z8yAsbmvY|oyXo}UE~pxl#)Bg^rt6fex~1VCd{s6^Y(5J18afQZCY`tQw8LfSbCI?m z3QGO z;sCUV<S=n3L~th8MyjHwLcSF1C1k{6No@K)05Afl{;3Bi_%#N_6tdsoX`rLOpO(<0vv2c?W7vt?K4FH->GKVQpfAmId zEFKe+ofNz)|1GvnF4e`(DJs@CzqmL)da2N9E{qCL$jz_Oucz*Z4d{tXaM5>Ye)%N~ z?L%eli{ZVwkZepoJ`=JbLO%-s{6SZOBgICJqQXw$M!VYSi?<7hxD-0xt5HH|d+uzZ*baL7}Lmq`Ui1yn%%C!ZuU!3tqk<3)}B5-ftK(DvFk_-%vZ84Vt9*i;Uq` z0M*puogA7LtJ>_cRfe&21hBX6j=DE5_d1%EQy?tD7k_?_^k4CO_k(oqvoS6pU5q}R z0UW1w^O3Y3o|Msu@U%wCuo!KE(P^+Qkem9|$>{e95q){E?EK|Vn259dDMTJx@C!9R z8$`BsfJ`K4+Hf>_Q1i>r`Tis)>PIKBzJsVmE1{h3sju>OXIsg@=P#JBN~ht8suW+; z=WISs3Fd2eC@j~>q2{^dP%`|`*=MzFSe2WL7$;G)lDVCVJ_6+M3L2c3BqG`lRK zGGi}68t-a%Lgbt1%HVURx{;&uWnN(lV<2ZXq(S68gp5vc&CMoLi?*JQgpXl`_iKKe zGa_Ty-j~NmCdQORJhA-&Awo z{}iUP>a3?~6F;gD*_6J~@)>FJVDUZS9~X;+5=4W!Sc^oK znSj~K@YeH(>r}0U^gv-2X6bxFxwOzWK?FVC*Y}B6G63R^(#q0ezly=wj6@n5Dg`#S z9my_?`jDpgH8Za1S!E^KL^V#Cj=ys(t54YV@fE(gZbx7_`_)=VU@;Qv)N|p@^YW`=*;aq!%FbCyHdQx)^Kj~NMv(cG8?{rz*i5Pij!m1rrUKoluy4ov`P!Dx7TY* zkF3ys-g4hB-lm;s3VH#SDTmY>g3kodRGI$ifhU~l87=#Jr@zrX5c$DDyKOWufb@KZ z;88O+X8(c$#aK11H=R&`Ov!grhbH3a_^=U;*?OmZ%IXUDzlCU%;?l|CkTC&K>Nx7P zB^T-aoMuV z?M>~4NMEm5FOFTDsnxa)tOR;GH|Iwc%Wv?nV;XVPs2OiZJ)z5{)oL5_TVwR0ML>g7 z`E<=alc1^V=dy%y(O3;s~{`eg32Pvd&m?SKi{s3GcX{^eP9+K9qpHfJM;hy1DfdOXZL+5LGNoX0b{ z+y|G$3MKfvEYf3UVpKfN{f1qisjQVR;C+fLg2%0$F~?xVcP{6(8QT_g(xIZ4ahe3g3q+Mu+I~06sJxNy^=Q4Cfyqa0*Ip?Fx}&UYTFSpMO&$_ljDkWl@~bcU0zTCK~og%nv=deYVBjT z`^ATHsCL=oT2#wG;fz5qIg{pn0cx@v-U9I#=H37(;x_L5(OTrIv(aNKaIm1R%;+Sj zJNzn>KX()5T?#r^8IeuPkExS>_&q~1i&@eZH*wUN5sghNrm~pv+RG$D46g2M{%=YL z3;oL2HzQL^5wHMRAn!s4{>f^?V9hxhIX23IU0!#W&jqj`I0Kc)+z0QqBW%xNwKZ=j zwjxc=%Jr*nV*ZVopsA+InIxY~o6CV7WZeRq9-CMd6dQ9ndCNw9AoOM9hU+5+25y%f z%GxyXi;l4ZrS?ko2!3>Xte}wWl7^x9-;ocYZqJnvyBOE}B&V#dYcbX(XH9ee=ol7& zsz}(;kZOQgdmuTU-?x_V*>T>}@a`n~Y?8k46=XcvUEF7MOo*o#wi>tH&_dj1Hi-Fq zNmY7fHUF@-t)1r?>~a=EZ;7zkxLU$kP;RYd{fSSV)w27gMD|*jocz-^5JUS)x!Xqa z%`IlE#~N_Ra*_=WMx87gfx+^(}5dgh&L zyg$A&4prEE`4gUFYf~B8J&78CCMfl44_{;CuBaZ^K;_%Z%B;WYr7kbByE6{Aa&OsW z)h+(%Psm0fxrWsPD1Xyhl$E+)Y<&yz|Kq zn8|AjjQcpQ9H<@`=R}5#RGoaB4MeOeyRNV=1UlF zeRR>bL^x5@zn@9#D*N(Rr?Q@*t1IigjGDRLJ3M-k;@r|b33X5kMK@b0zp`M3{zMMe z1=)p;qkeeecYAKrb2|JRsDa|;4kC)ya&q7A)DGb-&DgX6AHU8;nxo(0=+qxYT55C| zhf%^6SMv%I6dG%Nbf$Vl$+@aTM}H>`o90>lb9=KGsnd0VvhyZ=doSN4btxHj3qZsw z-Znbi=9C{lek?92QC3pg&Mhi0SCN;GsyPjJk6?1Q!4V%`&TD9rx(dXNKjn}Aw%F;g zPq0qBQ|8O}!CR3kG$7K=)U!Wd#3>DUe$&Fw1`mYCzf* zc_R$n@;LX}YBw}A?t@k|c&Na&Sk|gJyJnPkbIIzveQ0$MYvf=#mZ?OGyqy|(> zPjq0pjt7AgixH4x#`kgffYE^Tp{v>dU)!AgPB?$LuUw(E6N6Z)|2^u1cV5~`2DtVN z6Bq59Kuf#AR1-K{G>LNWQO$m)4#xR8K6RL!T*?MigC^ZVSNa<6-qb5H^9t5)_S$^# zA-WxfBzwQ9OdPRTgV&5eC;{$?=2R~0EwUlf=um>sPtI}tdPkJtvy~EYN{jwZI{^zTBXWAFKhtDWt`$$zq}D#M8JEFXoadDle0mv6+-m=y zw_oMfs(A!ed7rG38!+UwmBUR=c)(vJ=^@Iqn2%RqRY}W(@+nk7txL-e73V?x|GEp$ ziYNOoeWWi&*KLG19ssdbOf8wbSQ$&EKT&|9KuUmCu(pFjLg ze6N7&U0=!%4hJW8uBN||spMqov6ziPe~$P$P6km!s=~6zTx&hdk!fw_2U$#u zK0of|WAi2`{A-@w+S1g_`7AoWE`eUpxvFk?)N*j$^Gaq$+P zi6GpPVrglqqXU3}{LkQrhxZ?!C7hV;eOJFTo4Z3Gitl>R&9cP|%Mcg)*fhdJVo)sV z{q?3YkKF4ZV|ibJQx?cSs^$0W-J`DuE4pE%Cc(5~9AM^cj@t+jJ3}hshd#X1SDLVq zt2qlmuweK2i}vV@zmKo@IYTD20t+I~@`rKUj|Z{d8kLS4N2<2pkUQPV;E z)k8bP<&*%BX}CRu2KWNdaY(9nt&U+w=rEkbpJTiK3qS{2lB&wx4Ak&7p#s+KukBLn zZxl(k4L=qvOimJVw8x)sjE~}{R2okK>j(hNBw--pMst;KU1oS_=o*?2AIPYs!3&}* z{R`Vumb`Nn+N8YBmGG2Q%tuDXlj$O*&ED{CzrV-}_*^Rlns8hkjof_%{L)tWuA)3) zrdM2;DLOM9OZz%_;p2|@@NAHA@>_{ zcpthDLlxB&SNDZ47;bP!Yke%1n;8s$>tgViB!g8~=IZwi3Z28k(Pj z`u!`6&B-^X<87EI+7K-*jR5BsSJqs`MFc$0t)2ITfSc z6=mSU`;hF{&rOo8f;SB)-GT-<*5=w|#tIgv#R*ov5!;>9%TBS%&WU^FN%u$4YFLlC zU9laZE6HaT%zN~VY(X%K76J%(9=HI5v)w8%7y6=1imNSyjSl~XsGcLTwcMc(zV_3s zmd09E^WXbx=~r7p8rol-AO2bTAA`<#y+5C6O+diomk-0O)xzn4*QuRK2+h!b`Qd6} z_DSgV=&6J?zN<$0!Wz&%h2f^hc(kw`>RKQ;x&-H~w`sj;pk#IX=a-V~utjwzkB- ziW1O)k_=^efQ|76b1Fd0dy8TwQO7 z@v`>TKPIUQ{y+>EStmZ~gKxWM;B3ECh7`d)dXJZJ%q`cl+;Lt)%S`ZYS5(FE)b|_b{}P%7HuD`n$?y+yuQ=(E6`eVS~7m+>ek3L z#(N*{`Dk)-2%xfirVU=^`f*mpN`1oeOVPrzYgF>7T%{N43f&p?!xhbAHNY{<0KVHb zq5E8IOW3@xM-tM<{%6w#+0y~C{febpOw8f($*q;$8(b*2+p~`D*uE2bNa9P&X3W~6 zvl~h@Vs=sjPq(cWdz5`xjoSI?O83|TAA3G1rMly63HWQZ)*x){h&JEKTFGHi3!L_J z-{LfY%P!vWUl?}5P0{Wq$xY9QU1PR%A(Q|5+syZ-6?cIj2~j|m8bg&EEhoWlm%;il zrFyoC@{6C{PDZs;kNyf*iS3u36>$gUs0;fglXNN=8K0jr*P$^3o$&^ft9#_Vaw<(W zw#5tgW9DyGK)1HD3qu+XNrHx?_)Hc#8yms*RH@T6#}@bkR)^f1iE#{v_1MxZS5OAN z>Vc7O;qER*lBYjS*U?pX)K~@}OH^`^^$U&{KQh;j{OGYH_}(mG^mP;dSva*>#oerU zEv+re#%5ZQux~QOcq7OA!gpOn;zyKk^KVid5h{_kyFuuS^+V=1ML`#naFh zHeQrKe-csC{1cYnz<>qlpDyHUC^afeIs9#ipi$7bTv%7eT$7F#-MaQb_%P9e`_Q%8SL#fbC@8qvh+urZq zu}XzXDa*>#zFV!-u`ug*_Ay8OGf{s+U~V8eEs$J>Q0dd^3x`YC&uX{%XszR+IZdLo z^Z^cTWqA7zz&*qjxD}Do-H&)Ao5kE*mJF5F4a7W<2@ZslKrH8 zJEj?ri`|-;)^H=M!(3KcJRu`l&YZ{vrX>>Wdrf;r=02AaZW;KT!%y|7i2ceMpC& z^*u#pi`U~AVL>S>8d6m9At{{i|10TrTcyn=Z)mY!v}i5=`f&nr*GrZ8pG#+reRX?$ zYJCaLePl}>zfNzNm{f_oy%CF|K3GZ97pak#AE)5A8u&Ln`kW49?Q*QJpn}J)`s3gF zF#6x)hNxN0!m_h z<6wBD>{#|FsVZ-(-H-A`f4zS;!v{$PAoz$NFo)T=Sbd zu2uTR(#XQ7>)?Rur23~;R_k%-@8pB9RC;au8aq4rXc2ATNQWtX=1~5*Pni@|07!{ zN;V!8b-CYP8PX?Nj3LK!tJrW8FZ{67-_;x*<3{~P^J(N-K5K1%ZTtsCs@ zf(Kl5oOUfDLmZr8k=9hMci3}yetw=^d$80u|7oMt!gG4(I1{=AE|&Gb4)WC@r^`QO7HR|xAV z`yA0GY7fp}sNEoWe30XeMWeRtj^Xxe(u$j^x^f8T1tzuUMY5Hh!-+yqKpstC;C^&= z(kpT3uoL~K=c}>y92zzLuu^|99;DK%CBlF;(|z0d)JWxzaZPUfziXgFqXHv? z1B1hjEyc8i@AM7p?<4U%YXrDTVWBC8(E&1iKIwWlI2Mu(>`sw3UqeN$D) z&X@9+fTV;p@F65h|F0IHWK4oOro5>1xurCr4>Q8K_=&;eY zgO)w_z^no0|xa?0WX{s=80A(JbBU3 zh+#)b-)f{^UPO?*176iM_!Kt}c&`kbDn_x;CE7BW<)*2Vm{b&Gm1jZfSvh`;?dTAr z?!NuA3GCWQEVp}UQ(#h3P{<^H&YGEi{rYvA>lO5}EcPPsE(DZw7+!|am+JoO93Q|g zr?x<%>i5|(!a?D#V&NVE+a@J8I3xt_u4=}n=I-8FQ^SIeCybQE_|y#LuP3uV6_Wyg7rYT<2K z*M66wFyxaTbX{dt<9X+5^OU#E(idL*o;p9@qvKpZ1%dTP`ae4}{4S}}Zye6g9nPWE z;_2h>DygkHJ}$rb=ZislL_j5a{_nPSq?rNp>5l6pERWcxtYnyXuQZ8xXJ=2 zg&uQ7eT}!>C{_M0Zhp9nIdG^IxJ0!`6J30=Tzi| z;J3Ats#B=OUvJX{Pom6C?ens0X+z>2e+;xbP+>~@EK&bB%XiQ}ip@*V)ZP@PvDX<* z2UgulrBPWvd4&GB|7nQ0DLvCXvRdaQgyHZUAliiImE3;bQI;?hn!lPQV4XClq(N8L z(Hw?CMcU6m;mbp+Z`aHawn{kM9sc5P)RN_h2wBQu%!rSlg+m@LBDtvmB6Q=2+cS8! zJn47QT!xdD*L80iVxPp0NBf83#8>%uYgxDr5!y5b&j4m8!~$bT_&fRIymQ;42M%~v zePFEvvDHW2N-`jZz^6%134=KH=_d9|0%aUNz*2&@g*_Y^j!3L-xz z{(-H9X=bE15Jt-7U)N7}H+NiKE){hmq(LCiQzDZ-IuWN}GzH*u(lC>L@9x1tL%h7R zVMNXZ_qbWUNxen}&tc(m*(A!PZL@K@g9N-Fs{2FIK&CwdQPlDu%W!`{B5 zm(|k%Q?X^S_u%~2!rl4rpBFI>!5Aa=18}MvI-gE-w{dRo@w{QJo`r)00~t9qH1xT5 zX6Ac4y9;&$y&Fv%Qw>3Q4Z!<(Gwx{Oz^wdosV}(INgtwqy#fRZbtnX7L`dL8B1`c) zO7fllFlP5IH07-*Dx*w#D-s_Ue=vU_{oFjh!&~*N@EdCLq%{0ZxT?_!Wtshx8)nS# z)^riigRoyy1DZd#XYv|F+*=M%zR+bWP;y`!iBo%@uJ+FiJA3fz^0hvvL={M?UR~j0 zXT86CA-i$GSpRqc=l_(Il^-!IhlDmVj6O{;&L5f%xyG&Efx`@6vDrK5-6}|52(|xKodgIbfKf6Q`_$!uVzNUWSzxG} z@ZUK9mTsB1ry->#?J72g&Az7_obRG>HmyA4JPWdm%$*X@GT!GH99HLlD_ zD(bNKA!EnPpRA06+jPXv(o{}sV52(sEb_sZVl@Ry{bP@n836_~?)y_!w~f11$wyzR z{l1KpY}m7z5R~k8V(u%c1o}Bo0<+;)narMqY-NJwI5S=DyY- zI-#q-TCsOs=YtEnoCkh8)7XvSn=YvRuZaz~%%$wRv&IK{0uZbfN2aBxVGvhZZS?{| z6@D?FG>f8_&h~n@PJ(!laE5|u>FPcR?&z0k$^h_2zus)nde>gJ_o4o0bPByHel3Tw zf`~(_WPvRe+u`slez5qh`%-CHGjsAFD**`!4=>Tb!Q_!@OOpWO+BuM(SejPbk{hJo zxA17$^i7w?r3V|4?Nyc;;kiel+F?e4Z4o=-#s7r%15qtjYGYvTF~17IH$?Qb6;}CI zsv`3YF_62{M1UZOvzDdzqs4{2swI1+10Svj&*@B6;fuH4(NmSLwQ!S>U*!1p{K}hZ zrqFI*v1P6;J=`czjFPmv0AVmIfB3$9tSc>XPI*u!+f&a)@NfL}4o6X*LvC(%wJ9qj~6ZvTIR*>sop8gyeNhGKM*d9Cl z4+Gx>b*F? zVSa?fn7|d&S0e?Nb&oRg1KN*Ba56qV1Na~+U+}T2@s&3MKrjwFUg4_e*h;#pI_6)l z!K`9&#QpyNBF$^bf^HYmPj2|jviCT~$W@MI>@Y|S`gPRpZ8DEV!Je`R!6*zCk?tQ4 zLN1Zx^>2V^4LnR;jC9TLRVH8dRP}g(&=}@gP>F7$=rTBRpL8NX7;egA)a=%^sK#@G zGdm$T6KA~4Wy95kzMDKqGhSc&_7jUYLwk*-b?R1#JF2WD{RbYl962k;_@m0G*#@UT z0apZo!BbIL(9{=ziFpSrPQD>9)a z7(4%>=PVf2V&BE-LuwmCFW96i@ynoVdhAuJDYItIzk?mVA8FolyWDZ>mPY&o<&h*m z!$ISeL{b2q-St;Y(0rpxR9^2BozMl6H}^nf)$nz(hT%~~V3mCf#{U>`*F;xH(05d0Ipdr0JJl2L?^itEp z6ZyFx%>zCe#WRJyk9|d2+7%c21}glEk=^;+FH+^75Fjg(XiP#vqTTZms$JjVYn?qd zV}6v&?h=j?^d8B#Q>Pk7xyd)8{3)hg0J_CSFDY1vzIkvx}ccZsA&vw6s&N`h$9ecW4J+ph8K%M*g9ryj39j4&rS_?y~H_+vqKKDe~%X;2{-V3YYnQ6A# zm$Q5lW!wpr(LkNMD8*(o`l1V}w4%6nD8Snt)EQI4fKQwM9cgF9IYbj^)~R?L{SwTls%LK)jD@nN2D z00=GJyn}aZFHx=N?d?Sl=!%?7hD$4)Qdg+%?R*F7>}{%9zLk3tc-fqsE3RmYL>Rye z5=t2^p8?h^4+ja`cK8BoCi;& zBH-f`W;<dRuargyX=q2A+r3yf=Q*%A1m42BSN1ce zSDoo8VQYs2EhUI2Ua_jt4v>UnYJr~`m_Rf@cJ9b#e(D6!o|^CG?yMsCakJndU2;GT z-GY9}b87afYEb(MA=2;6OQ0tWuFV-YCLWukrKaX`I@bL9brNy={J+UxzB-)3?snR4 zjkyAf3c59w*Dd!mw8tW8vQowx3eK}ZXZr^E1x48%Dhk_b&4^xJWCc(Dve7bCV_n+9 zZS+l2p=P~&?Oe%a{m@&^gU z?n*mYQVU6|nT?eAQ(JS`u|G>4z+kj~mB?2I*+>)Xxw5U>lDz<;PxA)}$)Q@eQ;Z3& zs~i5^4Z;KQo62#;^-7$XS~SaMw1o!+y1HN7rqni@mP@z{o2a*bdg?QBK3Ml^)b+Q5 zbkHtUzwe@h`}Yabx2Fl#7??5FhZq-ilPX^ocAU_m{I+4*$BaYQhODntWN^cJ_Bx!< z2q2vU&gX~W6q_3Y1TiRhcQMUIG+hG+7Xcw zhAa&dsdBy$JH}G{eT%LsHd~_e$2z@t08tyTW4&1`r)vrIKDU7*!Hv`L_z)8_O8VI& zbYgYkncU8E5U9y+ZA0I*4gk0;;c553tY%~X%*tB7yVZ89$Atzk*xy;@ol}ndEr|1x zpMjl_)8z{lkg`6z8C2JIT7*!x$XO8DX;Af@P7YD1A%tABA8&v_@0ap>zp~82zm9%g zCO~2;6pW2MkIGd7N4cxNiGpbk&yExfe3F`Y^S!PddY}Kr3Z?{u>w=;WV}VITqD59HX{eMwa@65VqIp z7&ki3wzn<)?wLs|3`Ptj_d@=G3M2DLi5~F_EjQ z9-kP;UZa^aO(-YJDE-r(%I44Rh8vaJ`;i3?Ht9UK)7aUE?A5By~|KT7NHjb*W|NCH$Waya@3mwF*rw&tJ5$^IGGpF&`!HKY-fv zV@7tuW8nMn{!7mW52MV6pp=W@8teZd0+1O9%jw4>jCDkMvUkENRp0FDP6;z~? zCLb7EcWkO%Clka?R4PhFCM*(Jv87KA9>%r?mrEj!@mez*Yl+80*C_eSJYfvDfzMeQ zqRcC#o5&u?-o6LA>fcv~oi)(FwM;nk&ai0^s8NO!U_$S_1^t_Z#6$XR5eG;={#ba(`#$Z5b&U z1&+>bYf|j;130Y6>8I>k=SY(DE4G@ruWj@;x;-{g-}C65SB4w222M z9WV|AQ!kf%WpQ%kC?H!~xm4+3)=8--03gsPL03uKVM-Su(yk#N^YanRu;ReHV2D zmnr(CZKQ?3hP#g}GxBW=gB!H;OS_%%5%j8q)%GwqIX+gC%AD&7O$<&TC*3EGHQ*r! zz-vt%9UWCvRBWSPH@d4z_e~C}wv3XlRbua8pgc;{RmswaC!I#SYiNEKdR8$&B{S3n zA)(j9ift^fFJCMg)IDA8a#KD2Hp)6>vg^>d5M}JS-#fTPr9RT8oP?k8f#h5DiB2Fs z=ZcCp2-Fd+=3$y_2?KJ$?PTpJ-61gznd28hyC`{%eS5}%2Mh~^!s!}uw z*Y6o_vpzeH^`NSEZ>EH6w9W(Aj77Rg=e%t*POdG9a-@To%`g$1K(`)4MJKM|&KgQ0 z2wAz7CT2%QmN?Zv+I(oR0P46OTHV#mq%N)NXIoTlcQTqACBqnkljqH6$F$A_ZislB zAs8AFPke4o2w4FiZW8t8Sq*F6a}qgt!QLod#IDxNkm-jxd^5m`unJWAu& zJ2Z$Rq$)@rDD3ik3CNz$X$T}~yz_Ip>bZLsBZ2ngM!S~p*jPyNn+fb?$>{ANVX=_H z!rPc2%Ws-QHZcDf^`11e&AxD;F;UHA0A<_vlRAkV-pj@d<-@3nlNG2wl7XXC|MWr2 zW&cMGCARbJB+5>f`~V)!B;yhH3cqhV^~5K_FBa7NncmJpB~~=8rE^7x@wu5|N$*vI zGbKd~F8i6b8(yZ+^lC|^Tjj}s24tn)(qh7+Q~{{@jc!Heg6FG@hq&bFl1b+Ai76{B zCTWRCX#slb0zpFW!F&DK5p9d+@_l7u0iBW6fN~2!=HQT)4|?R%52wp%`?*S5VSvJJ zJKOr4CvqyuP_}iDBE7JjZ&`NFi}%_@D^3lYrEcKMaeaVyeqInQ;1{6dkkxeIc2x6~ zV1f;KD!V8@btdl%(jSHPgn0YqJpcfoHEEFATY2P97+86ueiG9B9B}W2Noy;-jlmuD zgFz|l+f~ZQzXdIPsc=CHVD~bSaMl{^ixnc>Qdpz5F**I)n9E&)oDHFm0Zo;=4fNEB z0svrZ#;5U_$TGA1wx7Y<8%b{pRHg2~;s>@B>n%Nu5FK5OB z*W-f-pUmu*y;`pz_-Q*sA?SWie2W|1QA-K1JN{|TE@c^(_7lgzrs^UM*pG(jvN&R7 zZ^JeI;frx$udo?xp_SUqY`Y zre=EEtKoqge|V%z^{@dmkJB-oKq4Z*4)hwZm4Fkkto#tRD9Wf*^93NRm{2g$iq}=j zB8}*XTS#LY%Ux)Kv8W;VOjbp8ruDvNY~RGX``P<%Gc!nlH?yzz=3c(E{`7v@;wU@` zkZG~0!w|Arc%HgUgN%fx!GrJ$@T2sQry9_|vHYM?v8=Sczy;Ucv#CPn_x5*pcM%VV zDSXO3lHx^dT}OZ%qms0+%TP%nPrk!&d(>q-%}>#eUPVXLQMD{X>+v7axFfhexiEjz zAMcvJxVHHu?fzBpE%&3}ef*Qdt|u`72`fT$`|2IvckMxju6^dGl+|V#z?=U!$y07A z&AwCYC>CC1wX!ial6#fyuCL6*%*$zVuBmeDz0wCCd2ALsX7`vlO11Bb zutGjG^+-{*C`qLuMqYoOQh1L)XoLWf-+$OJ((Kl+U3IABa#1VoV??h~GJHcbs~_)S zXbb6YaxXS~F`q5*0$x{Kie1Bv&*{jd7_Ax8qIIbwhBxbFBQw2aCM2n-cAZY-T{<6z&AO9 zp@I@vhE4}~k8%-)Ei-&e&%qg3UrvGg0Xq&GUKAGFbfHR$7SGEsQ}CCzwfJ9ctNE0? z7wN{_%xZ7%>}aPGu(fbUw)^c@xZd^5-BZqIcOYJ)g-2wtn)O_t*}lfLAY zefZtHv?^3`9l?@r)&T84!9OW27aoR{X*aEc@GPR_9JR5VO<=Q$?P;fKft{kVuJ+Ly2i^aOm~1{))g^iUb9Yph>3ao305Ix- zF5@{saj@na6F_NBuzefB1t0Y}z(mTn`S&<0EButKMYp@6p>T%uCx=*Sta%lz>mEE1 z%@@gFz7~gCE;VQ4gI=tc_F=+;j#ATsEYf?%9h1Je!rdH=?Wfc0^Y5J9Ag3WT;EBhk zNx2>T#dUMH#(%W{&Cw}V|7i0Jv{*l*$^OjDt@Iph8*U8loLOi0H%1O6uC1fQNcmIt zNJh`2Wv1Ua!<(5fL(TPer3D?-03H~~wzhcR1n9uVf4v&s)gB2DU^43CZ+po&_7Hbk zFZugoA8xG2k#_I;r5-V`I-ViYdTXuW2V|dtBY{BxD1}hT?drB?oXYpKTV}9bd~ojE zoGgV#PTk5rwmP0k8N)9?74j_6724Wdnh;=#0)r=}B)ph7;^ZmhVxI>wgl+;S=QO_EK`&mDFeKri9KFh=$o2iV@WOwk)R5crX;R#?el!v znwmkL-8~1BLj(~u>4d(`z1PD;h@69rpjzERfi7KDHEC5~(=isf z${=!sd>J-5J$(qzl2_YmkkVzOXC$erd|KNdA>gfR9iWFozi4&Lr0lZnpN_+{ujHTEeLZ$*DW`fIl=#f6MUQl`)`gDFp9Xu&%a`kek1Hg>u? zQ-F(lADQz^`$_AJFJ)Z?5?CV(+x6_kA7^x(;;xQsbA{sJX(bO)OJ&CHeS zr9X|Tbdrf$KXZ`MV{U<{C1=fHW;Y&Eav9A6)%{?4r%&oxR08e{kW&Qla6gBJr8Nq> zynCv=B~D4$=NST^f4P)s+-CN%Az@&DGp`~$Qq}}yGi2pb^P_}5tvGU*2%X4nd`U1w zX#0d@i%6{DP-p19f;cXX08iu#hmU|?E(`}mtKMF1?Vp{f@X(mq!?3%fTl2yl84-6z8ow>><`;@}zT3hdT?Iv@NfVpt7y|=kl zkE$L3Xk)GV8zCyYeYx$6Uy0;azVWP2{s+L6>sGE+3p>NI{>>DpF^R_as7KE0yg+N~ zuw`?q>X&UT8n!qy_Lr>K_zv)utABdL!%f^(3=EuTI(+CoU6vDZZ~4A&E<6ykxfE$= z;%LXN%fx+2x~hM4BVcv80<8;rTd=WLq};wbiNd|yCdn!m1(&%1sz1V>K<$_v6w|>k zzeW9gzQm3$tC}$rj^Kr3e|O#084?)%sCsE2(y=Q*9+OY+@N2<)pSIf0!8WPQ@i5@m zuZd7|5FvO;JO~(<_Tz5t`bAJ0Vc>u#1<7AsN7TP5#b4bnW(ZWQDskL4sI71+w69O( zR+iV->$ZPLBzjq2>s!2inHQ5elVzoX(y3#^Nw*=eTxJkIKZxFQu#ubLW(D4>B1WK( zqk%>6{-~R@O|5%gnI;i=wA+5vSJO6!wzfm`q^oK+x6rP^o_kN2Lpha1Z*kW`oBreznS(c#$GH|Xujgy#f%2a~Liob+w+ z7o^Z;^>_R5)e_(hm2~9aLrEU9UTJn%s<+IO-;uUNhO-c4=MFYx2}2%@{l9L+-!vg9|&#yzbLwMjSaGsF_|g((i+%^9$O;mR_LDgofGcH$gfn3g5)po_G6Gk}uZT)~ z$kR4eMi$?u(d)b>cTRG>xZD=?Vcm#T?yMjbW?e;!f3FNo$Dv<#A|yz zr<@V57e+yy;LAw0lkizIpA~^FB{dokPeWJrP1~)KNl7VFrBsXi9vbZ=|EM=w|+oi2!u4 ziyHn*vfK#j+8e&)%y@TW^P0>;aWF{$v5u8voa3|gLB@jRX0_)#Y_g5vS_=m%NFb5$ zfO!$F)}6V58;`!F<&+A)#`)5tgR`21n6OFC+a-)K_K?JxPGO0u%DYUoJKz)g^^HQ| z4^~q?U-bm*spg>PVe~*@{LZ!B%PP2v?;Q722C8+;E|)BdJZjN4AJby~*1pnLE>q`Mc!+O50#318 zs^Lik={-_BHBj2vk5bLLDgEc{UB}}Y_QH5&97b9!v7s-lhz+G;_7iGc+z{WHnC@Zl zU7n9rt-n%Nf92t%%px#4F}l;fmzOUjL&i?Z{|wHeAcO7#+s3jMTNzWnUr*s zkz%_o`7d;b4vBGiSu$;Hhu)`fpT8#S3iFiBr#%c&n+=sfy5DzPBSnGnBW|@r8kgdbLyr`rk&$o&k#X8d%#^B+e-F+l?P`1EM@p9<-4LfrClv7ZWYce}Z z=i*{9N0=2OJAac>*m%TNZkscN8FT7Dg;h7=OI>fLE)t;vowWhv?(EGEA=6xu?Dk*Xf9)r(%TNw&R&G zOpW(v`n5%u*SDKK9TRY%+ERek>uMa1hozPOlNd`k2(-ms>orhS;7 z1OPb4Glf5X_x4IDDeLI0&5c2}4Gg>pS;N!70Rux6{;@k3{%>Tt(ypxT^9H(6tcVv{ zJvNI+)|;v==T_Q2H$}LGXA{<_-}cTsSnC(5+e5a>$*aapVrzDcvtSjLvKKxbq;r(vymDr!B05BLqesnPS%b?+qj_1~{|$j6U`b>-vRQA?H2f#ygbY24e~L98*>3)Ok> zDw*fc|2|7W;LhE|WEY-4<##LtG9gmZk&kpaQQRbOp2H=-Cg~%s_=*dY+0rqxP1s_J zu@(ho3#2y3*W2mow%9#v=Ph4VaPkZ$mx~OCaB<%e{S2`Vg%7>zYG$(B!a}5pzdr&{ znBfj8EZp7b34`lkagYNhD;%D5Z_g{y#IiTk@luZFD zyPsHdI>qvqgAwPdo`0If9{=PxMM+kgo#T&*%N5dOvrSp5xY}2S! z*zIV4kNTDN{h%wfZRSKEKge}p1}!D$9B#$*j*1DNGrz?w&oc8&>Wx&V~|xYS}exV)M~hna>(ekg8Om>%WfKzdPMLv z%wP;R{5^KyO|V4J-|aCSfT2yVQx!hJ8!X7k$i!AZ5b92xS6)F#1LvA6g_&3FLMsR) zSDEJKV1lpu9EZ0YL*t??Li6|bv0SAJHet9Jrd^c&DmH1YH1Bn;vOU9#`ytdvoh{^y zMDsYpi^ub}0T?9~9zq{){KbZ2?#npGbpzbR80I98g z`1zP;kVYkAMt|`zm~;>zm6rdretlLUQ8%%<;dhNSq+DE5jef4HH(4GD-V$E)t+4-d zvOtx`4tKY|FXvr+amOb~$&@1Q?kXlOF3#tA`I&_!#uMiy=)uCN9eu~Dj=}w;P)H<$ zx{cMOi;0Liul*RYkNno1gv??hEP>Mh7Y7DranrB1OHrPoFNymFJxZD+kvF5iT}%C7qSqGk`YK zTuxF_Qd>J?X#2xEc*-Kd{Ygn>=i)9RB7&Qno3tf6ynco?f$5yL2|m46Oo?0S4J|<# zV^beh zuBfOed`-%S8^YMy+UoIgz2Wy89+pYYCnhGobLY>7-_1NcfyvCm5*{A@78wAzg)g@^ z$14YwDu{Lsy4MJt*uaA>C(hY+aTKqzjhE?tP}Vc36D+=g5D%M$VfU!r800bHv4VBh z+)$#1zC^%gVH^-j(+brZh%Ao(O6Zwyz$vcmk!89#G9s&@QlFbE`UyK8I1NyMcl`0R zw6=~kAOV1oiHXztB1y^NHs}gB?oTLV%*5-TzYGSP#^ij058_Fg^nBCdhM+MYU3>xp zg5S>opbc%Z7x3=p`-x*EpJEO#3q%pKysfS6H(Z7P46l9Wj}2LVA_>Fq>2b;7UB_?? zv5{0(zA$38@i=@O%Q3EJW>x6AbN}n)Td0X)pUtzNC!zNMehNv=y?mbAAG#j118}HP zxMVC(VwL*@Ytyl$Lo55zE=O3oXQ|y;-6Ys9; z4@!a}M))}kZB9B+hm+uT%HE7=W8^PRyY(*opk_4Ge;p+zyK0;_=^nd6HnM7+-2nNO zXZPBky#^^?olq#8 zY(2cD0X2G&9e5cmI{~UsyT=Aa1vHH0C8gGL9y^_b8G!YsDsH0U=jy#|nYObGKhbU< z)t9))WdsfqdJ}>NjDvCVR-EKu(*jSe--6{);orvl48+3rw^poA8HbQNF8S=|LE{os zk>9ak%A~Fm)Qhg+yL!|b;Hyxv4Ocpq_Ha)xX5<%Sl6UZji`WMgho;F4C)1Ww>VX9* z+xln@rZ|=DM46_q6qvXWFyEmxDG{H^-BAT0IY<%$v*ag^ON1Mz{BSLQYMMZZUx8*y zJY1)wW8);a*jQzU2p{;gg$q2Ged2AmNoWNB;JB-3pwDn?_4r!qT;JVV7g;J0??lD=(DpWfWV2C>^4a?Bd+&MBcgzKcH=kc}?++^?F-mJXJzxt~r3dtFLKpL8yMs;+zy zNQ?D?Hw+XP7y9aHvp3eF&zwyc-4eHDMY-4hjc4^8eti;eeVWX98PChT6rMs(I?%mi zD`oi)6|)+s?m!a(pXzTMVEWN`|MIfy+UVuvS-hvK93Cy23s;?Z8YFFqfzUe1`0;*` zu#kqPn1BmST?N`3FUNdxdjJgq0#lROn5#ThpW2A(0{#zgZygp#vuzKPkOUH(KnNZn zKyY_U(BKZigS)#8kPzJ63GNWwhv3fOHn_XnpuZ;XIqy05-gEEw-&fB(4?ROqPgQkw z)!u8bTD!6NhfiE#Py| zBoF0!H+1gIzao)2Vk;{<60&S=8>dzJ29O#h?1u9&(Bf~0!)s#mSTj64LySg~x&U}L z%9CcJ_9HN3sfk!bfsnwhd(7?^ghnN}V%c2X=4RK7< zt{%2@MAS}SC4-d}9&|`TtllRo>C+fJjnyjwHkB&dMkhB_S?vxifCLBkksnR&P-1i_ zrGaYLeEgRW$eI{3(2iggOF@*$gMjwF_T<2rdbj>;m=&LkaYfURrT07ygj!F~DqM-D}vsO+?25}69^Buj1K?9QwSLn2P?w_3uGfxGe(SP;kW zq7cKrvaz^vn^q_BonHMZNo3kVY?SNpod~eCtiy~;BViR~`Cve+Q3auDdXgdKqLZuC zNxT0gS}1Ea;6zC_-ZR~t&W?S{GZu@pz-#1``WUbV`tALs5vDkl)9eP@8b69c@$|QF z`@+8POjT&?#WStYhP$Qf!yuk+I@BVwre^Lv{o<^W((LWJ551-r1`xBu^=>0Vs8bNs z-9a`KtqdVDdp^v|aI#L`l$#+;=dgA!=W?bBhe6vwpsC3=zuJN>JPJ#5&T+`d^K5Jr zSJkLzkAPRN`*m)i#FcW_`&%iAmY)F$jcCr7(W_gI7Xq87=}dy52mZy1qU!qkMIMXV7brxAJ+o!tM^V`GbqKFcV4k+6K7YmC(b@Of@ya z#zJfe-zaZrvyk-?_v-^MJ%2F9qJYzf1*?jOuSG9d#b%t=+D0hk5oGx3rDK5F;UKfzC#%Yg7Xh-3_*!fgagPvZ$-Gw#A+ziBjw?PI|{$* zgzeh!8(6KCA@fS3|K)-ezbEWhR}iaM&P-j-Ykbicgwj-m*0(BIxeWzlzBUd#PNs3r zyDCQ5tI`FV*ZI(Ld0jCTDPSJdZkY|{dyjT$*;vftAl3LHwsK09K_~KsL{N^-TdZ`* z>&^FF6uhqF8|;jBHWpu?v>sNg@E89f=G#z;mRgPknfpY8(^_Hf~8vGIHeO+I#wXF*82)FxSu2Grtf` zGVE^S^rH}cf2oElB=wRcCNs!R&6Ox!%=fA8p!;QYd_1o-1hW(2%%Z%yI59-!0%Pt%h{rdnXAhz#W9yL{D#wO;vpce6lC`O z!Es>nD$;XFjO2>5i~b5k8!Sj51U?b zHJ1_20qb!RTu7G=kM5#qSiVLcktir^GE?bdN%Y%Le!i@zM^5cQr^Kq9d!&j3&$KSDT;?DSs5yChdQ!a-0`dv%ut8z!C|)B7pPHe|uafl!az4~sUuDS2EedIB zOG`>hDxO<1%OaB8ZY&5PGaT@E3K&@DD|j8U+gUsRM(m%o1BFhGPof*-#>+Cr8}N!# zCUL8uU&*_b;S*SDS>on#WsEQxS}nS}7)#&Ox(at{2~phHs?S*Hh|jJ9`AqX}^Mzc? zcg&0Ivji#*b~gE?Hq6}*IbZF}&d#cvp)BBAhmm=NLJs&rmmQ_(>#bzGYXU}1rn@Gu zM$^|~!fVgEO@$>@8^cyZ=_JGfA~=FIy(Ln5}^@wwwO0ldQlX6jVh1Jrkx06`w!^4~n z=W2I22Rl23?^}HQaAJY9_T_i9Ko&HV_0x=u48Q>|Jl!Eae)pmGjy&wPRu*yP2#Xbu z`#jBa$%=0Kp`VX${X>xXnzM*+E#3kY!c4qn>8w9r#}*%ofMPmCbHkdSU!;IbRlufm zI#j(gvAA(T@vyYUL8};nzSXiCx%!S_>>4WR-h%%h(eIAJ#t$+JjUK9P=6-Zd#8n1U z(JFThAQ!9h+1Z`x56S;PxdkTAPfvKSzv~p@iUcWyb08gJTuiB;YJghDyQj)MnhMPF zZ>&ID%yoGr z8iwR-UA}bGF4C-cYPScwJvE=JD^E{P4?)f)ehT-SBMt&=($;EnIo_El63me6 zQ|4d(B{EHrqxyLaE~7oMOXEj6)-sDhk$4*R`xX%;t7MGgC^#lmD;i zyt*S7^^}|4Qt6W)=8YOVI~?0B$t-%1uo0Bqy?iw5P;ROTMj_akLwA!vmPb5|eL5JA41R69Pah{@g%0zo?lQotBYvXjL zKjo(T%vSz~qAkw5xaDg7!LQOma)q987DpktV{^GbBpZ)$@ExnXaCj4)+M)AlTR)3( zcN?09jUP&xC>+>g$FW|Ao!7;-^gPVhh$C@8F8Dtcmdaq~HmZ&YSFf8^9wW#=MtKjQ zN?AS?GGn0rwhHp}w=~D8KbzI=C@x1txzUJ0PFUD^GO306`2li3wy({PfOh-;0QFn$ zHp}(9`<(F#L__grrl-f%+s`V|%?OkI^CAIk7H|W>j58iP*r}8azDS*CUUZt1A~AocKbWe!zXK1=Y#f(~jWX9Iw*Z z#R0OrEdrd}N~<>n))w~#kyiMrg7>LkgKqLcZ`~a98$n8VhFVPp+sTU}0ceM1$+^B>Efl#H7;$&%4W+uL1k^Twec z@2^r42bosW3wd~SIhpm4`zloJ?s7QpjE|(P*Ggjg4yC(nRhug6&v2MxBzHmhuT#i7 zIdB{fSS_KQlql*bL^Cb8lvEDwR~Onv)CB10{|*VBR4+A3dsWIPKW` zB#;imQKPvA;S(_Uzcp)DV0BKJa4|GR2%$k@S9Dz=RwP2&KMqib3_5DVQ$N2M zn{D<(+h;L9jsT`k6YQzpqNh()7MGwwfA6( zv{fUxJ}e#lv>7&N(PoHbRlMkSXDJA&PH1>I>ssHfk#eNgL4x0EeBZ=aQl7DDZQA^h zv`-&y^YJ`}ccJm~eJPnMp=b;*zg^RhFb;+4G?>Bf23Xpw04kt4aO26>DU3tQHWn5Z z0|NuuRJX@y-$;GsG(G)M2OaAO)Udx(lzRHzxFj9DBq6X*f0_Ca!i!zw{@{6|N*Ucr zu==E(7aP%4O`4BaV@jnDOII?zu@mvR;D(4>m${!Db!hUV?+4BaeIEZlX3c;XyQzQE zvKZ$3E2vKbi$wSXy56lv`qe)C0Uyd$D|?VWOw#4e0@RJd{CMGqfFpr*Dn}l+g(xF{ zOu;QB4{nBrgzW9_o2t*gz9)Wo_dyUb()#A+_-9(I6^5kgCDEdnRZmSq>VwAb_ks0s z-#yiP(FIL_)#g`-uPzOt+q>+uk1j4%TH{9AEKIZd%wo3 z)iy@v>v4u%=sRUGUdLXPr%gpsQR0t6?@o%f=(wY>xTO<57lb%#6S~;xG<396_B`S- zyia`YdJlzYLTjZz6dBIw-d>4#g;@8IJp;VTD_bgR>fG$?gyiH?n1?Vt9Qcde7lJ_@pQVSJ2YD{l+0TW*8~cj6z;R&;yj;T?R2rZ^ZIAjC>z& z$r6Y_d8bEaFOiD?X1?GTK|~{>C%~5jRv?$MTzFC3*(LE-1?JCMRvS^O+#bQo;dzllup&G>R9y~&7cCzN17nM$xu`fTk( zQy|=txTdBiFsQH8Nl8in8r*IP*6GQ~?i&M%fE*5YG0mG`5mF42_cS!-i(pUWcHrt( z(3<`8-B;02R~h^JdLjUrcD>ue(x4|1u4x}V>Uk{YJWVL3ZEK7nYY8DCTcT@E1iiI#+PN<-b6i`<11x~|VpRh)8haSpXL*^I#5?SxwW zlozjCV@rG*6uYHsIl-XrSQK#cdZ>OJm&%@1YgTr=o8`5$c{WWlvFlg&p4R7g=>;7+ zDcQ@s1{QhW=!}WQvG%W#FBzApYniZ=p-eLYIb@rJE}6^Bb~38^>;n7R21<4{YxwnC zB!9K=mKWxswm^#o1e@4RM*$6Yg`^YGNRyk3{hVHp0t7T7biq1JE5I7dwy4@_%ayJT z4)ADPbS}dy6bVcTT4`dZv_j*AH8whbA0@3it`p*ztmj*t90|uVy9)jfu;tOQThvyBr}>y~5Sj>VAQRgI(?$HO9zVZC6o2 zz;FJ;hZI5oA9oKd!w>m;O$10;udjlts;XX~66BYaF=!F1&yaV3-hoX~-Zy+g*`<(v*4pmdw`QA83=d+#g9%w2Np zM5Hkyf`9oKs`i$h!Bteq$alVZP1_%}V&Mx+Y%mWxAfEYWg)Brm5%|0j8xwPTdka`> zk&*I%?n{D^sj?6}u=uH(+}teaXs!20n_@tEVib=*!joj5?S`(Lx+=}!Xs(0!>Qd#H zi$jY!xekCmCnm~TTJ^6OT6p=5*ZNp~NR;FqBpw=)zHTvEs?z5&RF-Fz#t{4>+V-p3 zDa3fYk;iDdYY&h{%MNJClV0@lyenKC;|ZS<5=7H^7Tu6xUnIHU9ELjfI{_Z<>Z!sQ z3-DUJAIox->;RTQaG-~_vU0Uye;g3nSBNWPPAogs-&}{vzO{A-wv1Qr(_Fl4{L+KX z@9x2|q9>ZCFMr?*+oIh(UKHX@cVg|YcQ}g+SW!bcw_T3TKT!pEArcSWLBVz_La4s$ z$|j#wWOYI*)F3kSZ`-+YW*m-4)6IA&f^H`)1&iy8QWMjtqf<`40bo=^5-(=ab=L;M zxp`C5NT5c)y7JAlPrdElsHIb4ivp~|>;277bigBM>e=J-6m(3LX5LH)a7Ts-fcT6c zb?zB(i*&fsH~$%g94%95>E#7X1ulkHd_~PmkbUE@GPN%Q%9E@nYr_+b%_P$N{OR%A ztcMT^)rUD-vS{Ny_LcC#dwM(JvkPU3>ca{;3|IT_q#QD7HsyC)pwy783jq*5@>GGO zXOZKqproHRj zH8l`ylJHlkI>+ne^^Gl38KP;WKRVRBfvVpsfM?+yJ_@e08`vj?DWLJ(e8)`yJb{5ueQsJtcfiCl*8o(R+Ob$6cx4=g z(D7!kSKqv#(5?efH(f`EXRf)t+$STWyuM^JrIGgSDTcLS>7VE0a~_LP4rTq zrOYgJt@QH4O&%?PNXXPDe^f$=Ly!)d@x~MWu%oUYXA96F?ZAL~MhzyDKAov&9*`XW z+?k$wm`*bx4o)+)+dKPt=uR#5qPe@0*<^Ij`H*d8Q@jY0ges0miszg;6jmf}o7`-G zh@mBrK4ZPR?Zu$k@@sr;eCwtAXd+th`9MiwO#}O^Wa-LspftGs;I>7 zj3aM}XM(zddQmxQLXOJVuZ7^Vfd}QNdE=Cq$a)}w2?*GK-dGM^<$_7s$Y;G=-g0p= zNg~EcKi9pW66dd2OJFGvnx@S z15iq?9CUOKle<@8S63eTfoV67Ht$lH=V1eJvV4Hw9+N%xyFGj@NPBJ z>P~r_;^o4l1wX6a0>HTTG92)yq!+*|dp+aY(SHPWniZE=g~sXHRoWXOhp_f*FTYKC z8(U+ouGJj_$n1nFD`PN)t!G=}Kc}gYHRGU*HXd<0l6p|%lQLukY{o)TbVNggD_?Xj zH8sGVhXeU~5G^H3oKWq|k0Ei*Hq0{1WC?{|n>BmwURJ<1v2mEU!^b+ZsUDd=?kQbn z4Q8X+`FejLx$E7StkrDKrbg{?^*+89e2*(T8kqb2jh1J(FSbTZLm_pq+S#?Gd)Z>Z zI|i%8kk(bBL~i1X$&S>MCvbh)xyCVRJ`Bx9V4%z1p8_{JaTxK*?OZw>wxcpN8F}@Y zonzR<@5mwBBBT9)p*O#LF`A^BU9asjfA+C;_PWO(O1KRE`f>R^ZqIGBP)GF+jbCPB zQsq*#-=@Uvytcl%SAY|S(vS82+4Z5z8fQ;`jG|@tg0=ikVc|RRdMpnvrWRikW{D(j zYG#0c=8MkG;Bneky~$#G#|v2evJfe0$Oq{SxvaYn*?e%GVfmOP1RZz5;{a`f|z{exXv8J?Gj;3yqU0nF;exjbb{!m;0cNcQ z2mgO!JLW-d&L~*@6*Dt4)7`*|?euT_$#+1M2w3RGTSfyfAKfqy{yO4El;mUcvB^B< zC*TO^)kW&Cb%tfNt-m;e9wPtb4n49AfHNM;-wxDA!#WTV9LNa+0|W8V%6SYf!d<0} zUr!r9zVo(zy#f7)2le=$zY6dhf0ch-@R4fyr~HSr{&w5o{^wa&YBm^8;jR*a-uid< z=<&i!S@l5w0X|bTKmh{&!pU*`UoH8UD+p9i08M;Ff@8kbA4x#-k+J)S2BT3{!i1~Q zxP37f*$K+M{>zty@&4wZ_O!>b?EX={a`MboQWYguRFOV5rdiX*At7U?qp~x77CGmD z-Ly9$4kaH_g?p~tvZm{uci?@;V57WQ>^cSfD*@z0+>5+8x~=abE|TWxHsmgR^8 z@gurAjQigm3QWvRbx!ESx7R6?imdfjgV-&U9zZI0AoZfZ01CK!Z$0mAP4?~tL2ltYBpnmL?gjbjQ zQ-=`$`1hp_W9RBshN6q8MD&A6oEP`23NqU;8{M7WdcM7o^H91}H^?IRr{cEe^=06w zAn4T0sMy+Id)#Ou zcrI4)uW%tqJyJ#E=jIDiTKZ;$VyyQ9=)uB(H6XqWR@i3KXlv~y(BuI`V?E(s_g zr_6C#b!IZ4ma~b{>oHiVWYiiNPpO)W8hf91s+dbsNgibHWM%D`GxGiM(ESRb2|65B_#3iuGDh!s>u0WvVqVk6q+n215N?BRIH2)>_lO zkp@E)0Yt!;94FfgX-5lDuw1o@u07oOZrm_6s&O@YN>x8uD%#(!uWj3|x27I$(M9IV z_|K^L3`_TLN5C3?zit2(iSOjFLRo~05g7^tp>n^s;xlKMsY?y%v#Yf>6{5Zcy^p81T# zU(s|L*Hc!FuIvmeX|dhx1vA$v-Mck}eZH2S_S5Ty=qMr$?gF{DYJl>Uys|uiVCiyX zeyPcI4=?;c!)C4*YV!o{cU~5>*7A_e;lRjmSLKPZ=i3oR=Tp8edSnC^ci&p7CYm1zy-C?#*{(Df`onK5$R^w>xxDstL z??X`2d}j=(2sYU4|5kg>`5M%-AeVE$V7bOv446npW+o9yY4Y|!Je-M*`6KYrPtZwf zvoQm~BJUd?Z{pWevxCZfPW=t$FDx}#0id}yFj;ZI$2+=SdR|M33NQ=R&v&ft-J`v1 zPVnQXJ|mtj9{1Qr#8c(%yfPekVa4A(dtGH+ro&*sqHvjMd?*@;AMa;`7_hd!PgfMi zUs6Rq)mIcQvKD4(E8>eTKAAY!8g5pUrq5=RZ9iA2#*dq4u~%M9gl<${nHr6;hSl8pqkvzo?otGT3pKysIrp{2)r5NWZ= zW*;V{DS!qC=*kIeDaU5!H*GSQ(dXtCW)|lM0Qc|X-P$R)hainQ3Hs6Z6=)+@|Jnw1 zm6c*#Q6Fam*Bc`N>#dDU*?41UG`us)2Tka_f@+KS!+Z*cyHki&PXP%J$5#2qxXRS- zs=EwNEXn-oT%C08p8Dp+R~2)`tS-Vge7lT4x#BlGhM(1zFAlL?EbD7&@i^^stp|y0 z&N4{nN&6jga|@9fL=`21(`;AS7bNdJHUIPWsrSABorptx_X{x#Jp9;##+b==ZPMf} zOR?oesuIHCr_hDCui701*Y1bs1dr1YFxaG!&lSg5%=x)w<&}g|Qh+QW*Fyg(AV_9* z^xXHyj~OU*N}ZO1qN}xa`DT`N`FsX-f#IQ{Hm7p$a&+|pWIgdPvX{^dKkn5Oyt%r% zs->xU6bSDvd$x1FtKobwp((1URT5~Jh4w~NSa^DNRsv?&T|wK%vNWB%oD=#k}Rlm8Y37pcVt-5H5A<$He4?qk-Y|dCPQ#~Qz zBbd3n1;f6_i(Q$u9hD&#DMynZ}A_Odo$0U0$7R1tC-`j_Loaar{*2Vu(w5otvXx z$W=*;Q-aDqs=G`+2sHEKvF8AZ4d!=Z*ZU8abcK%Lxm$5PDxdCuqEj=SvQAI+d3=>i z%5F-yT8>N0by@}OX5}a)Rvh$Gwz8tdip7U_ z8ts(*8&B_?c!A|PVCldwP_p7h@k9TEoSV#_a($6zhqvI*Ecp=IkdrJ$=Z|tSG_*J8 zZfTVKgVI`{*Mp$mTB7}7!|7Q4jh4~^f=F!U*N4z!!ELv<45d!OROe`g`jme<7ckKw z9le@4lJ+H=KibYS!p-S!DJ&q7#wDAj=WHP;vpUNu`5)-kILeH=u0`WyJl~`a#*Ek8 zHcK5Fp4CwC5e%F=o`n>r+&mLTdP%a9hZFDGsE)g{gU5F9ww#;SAJ8p*^cJ+rL^O=f z_Lr7Niv#rm9`*V!VHeYb-`>6}N3hbty*&bd1Vct&Pe=33@q-Ja>jpO?RBih(ep*=m z#3Hau(Ba<*(>kARCkTrg+GEY)cw4|ub?*B5@IpfR_8Jf_W1S{vQgBe3(v)V7z*hqL z_Fh-O+PTmN&9~B8P zVPPp03y<|>)+oLFHM|k3TeIuPJ+f#6 zk%~a(7Pr&iw|<(Fl`S__UXhGkFu)8xO=r{3m)v}a*G)?kI%CZKkp5dygh=SdnUH&! zdi|rEfw;r-Y>-90z-7>zuJ`Wc%lZIdl z>Gy%j9{&5Q;R3b-EUQDU8RQzxVwPS?PK+O2Rt4P-Ese{BJ2VqY-m{??dmzbR$?Tyx7q|~_TtHXeeV#@gSHH<(uVPYOEYmOPOU&`=FSr$BY%O=tJ@RY>y z6cxPx-B3@E=-rGYoTAO6#WyS)BI6yL95Z%uwLNi3`P?@_v;3FM?~ksa)or$C^8+~n zvKn+6wR(_)6Hx!^#b8o$&&2evmx1U$cMR4dfMX>bzq&OlaEU1rpb7nZ>oluk37@BGL1M zy3kjh)ksPTN=WMB(lp}uB>wmb2qkzFBXU?GUurC9IR6d7On)npt=`=Cl+8JWzM!<7 zc%0UFWVd#|8ASH2sm_z-MR>B|j>oh{bYUswXtz(C>e%S$is#AipV+L9=jZ)9y229c z2>6_D_GfnhQF?-#;8aCe%F_!Nj0|US8dhJZxV8?(ThlVS-#K9R>YaIFVaZnv5>6a- z+=}Y`0NY<_3@`il@E=)nIQq#py)<)&D9!P@0mpMN8fEqRtJl`nr zX`uRKM<1hJUqcfEU`09_+1qT>jXn+ze(RaVDK6W);z5qe=f2p@9&a(CDgIXv<2t-7 zsDU~*GD@9$F!_J+7!*pizwdCXSo$xPsYTgQUD@e@UJ4n+usSLkm?Y(z?evOuFP|>g zCY)@(8@Y%io6`L3rcFvc6edvK<320Et@tLK(Y-|=M&)oZ?`?`2c0${@tMKw`U_0BN zNu@A0<=m(v7aD)CA+DS>cw_ueJ%HJDBI!gze)$uQ9D`4coVP_*3!${ET4^xD`7T34L@LRnFED?Fs# zSlHAN1ra5!n2^29KQtq(eD$X?S`zHRen*w^hlB`Ms3-$L?!^wa#wErN2<2m=J;oQz zl$2sVzYhuxJwHD$sdfNh*v3Yl%ojQz|0^fYjGo0n3v*c_AFoWtNKLRK+Tce7ZuL$lmlu^kP={)VfFMCGwoK;-22-O*C_RJV9mc=U^v zKcB$~V5a;N8vWZ`eq0Lv`tQF$&%ce^|8Umdfb73u%zS)cKes@WzPxK|B*S}T4Ix}q z>2rIP{nczAz?B5bZ|5hQo6Fre1h5pFPEA~K6ailv)G&{*FMs_q03BNY@Fl@gK9?+f z#Vf{wEr=+B@$yu>gz=vss6;)%Uv-4>e$+auKO=@O*|@BhQ(l^IlUiz(;BYj&^SQB) zh*u37{HN)fUI4^Y2hnzl3bG$dab||`@|^oc214h+*jF8zQ=d`Bv9mYCq84sn{Z|rejrX^X?2zP#WDWm7Xe5$V%h*B0AyH{7b z?}Tu4s9lv1UY|zoBgN||ZmG1JQ-`j0JB(kyQ2ArT!MPG?TRlnJxPwC1-cW(~u6_>v z2yUOUlsr5+hA5_FON)h$3&xhJ|^0BNW`J>Ngtxi*mT9HW*E9oI~wluj->cO=IQ?o=Sl z8?u%{iChQIsK{_DJ-k=r%)RO3Xh%$Y;TM2 zT!9reuVJew1632c#AnA*xLdfhH(^(1s}O=BKB3RSzItQ?1hx!6BbtUJ?zmZ`r=Ky*+eKo=h)8 z?9d!IDX=DTxL;AyY#aQ3Ds`{sC7*MCN3Fzhf3?+pTi$3zNlrc=%zw1{mci36AXtmZ z@Z`mIa-((Ld!0qz42$)SZLfvRDpeWRi{bAXMPVsnA@`o2yOLDJ=*9Q%b`x&^J@3uQ z794{?%=9|Ybx#gghL>np9(l?G8>8DnM`!$+dOvPTJ{WJOh;qN)q`$EQ0MS!uRe&CKb=_Gv+$GH3uh{_{*+rsQ>Brvb$ebTSA{|@yv(>{>&gfr$CaV zNgR~3%2bZ=vC%Kr2XJUCLdT`SrXw$(JC^oP9)59FnsfH>O3dy|cuC0OT*{;JQ8>Gy z*&IsupoS!7Cq=$*N5jO0tR)8XGOo zam%=Z^KR6{KkLn}H=|u|?$2PCj4OoYnr(gItCk)U+*CQGGViWAJG0o>n_d3CyDxBe z_dRS~mXC4g_V|S3$}2n(TT8+-w6WO=62iOw=bkPpim_OT>U|?hD1=3MHKwybilh>w{qADK@BmJ)ebC8w z``yKtRrx6w97k5`RO}~K`}8B*k`T~YkfJd$SEZ$lxoxM;moI7xDxxyy(nS@_cDRy> zovT*Z?#=hGt0)2RbVSFloKWa$o^I?P3)aQMAc)>OzPpPB*wDN&r1HX00<;Zwrk@}1Ybv64)pCRtNJ;s5$dV~Z_1KzpQa=S} zoIVh6r?1V7;4ct!=$E=LO_opAFvAkFY12}^kgi0%j_R3R^dlE7q*UhfV9guC;iWBB zIS$eUB+`Dx61ztXMenZeQB_peP9VALFNIODOKC}$eDR);L#dGxIuFo&i}~!6bzU^I-8}8bQfDyRe5X#8 z=8C*bF!dRc+$;shkl+NwZ+7cUyOXNyhScYpnG_S5TN$>#Ukr{nw^Bd1PBrT{r@feo zc1k%N{IZ@tmV4)LCS#RY!MZwoz(5Ih|7|rirI@T-hNjQ5H^wD%6Yn>_iq8u=a((9g z@NEmD{EO!OQ_rW5&&#mzoHR{Z!^+Na@(ec}odNNeTG1wet~~~oIEKO z6Xa=B2J1Z>$DeOF$7M7a>V0!J8?SSixqVmoJbn)PFgPufCKD!;#`h){SrhD%9YSK; zucm7*hI7Z;)4xzYk>4V$I8_1~6cX-8K!bUR_e{)uN)>cN16>+aYJ<%figoAn%I2?2 zEe=CIa`1>jev1pF^{xdtx;yTNT^imPIhk*4E$xgsuGBv8=dVinJ$6ajy7vr=r4y?4 z#@ZUcg`r+~L#{GX`$W7k8`cd0BRhN?;T(TIyGQHN4^EU@c2PTrjL(~Hzh9!pyMl1$I8pgE9OcS*lz=A2_hoU&+vHRmzS48Adn-y z6YRv$%gbxOKjdK@HIPem_k82q$81c?l(DCL0E?O-sn2Wg*{3Dfv`yErRp5X~zCekf z+j604rmx4l|;Nbp2k6lK#6Ezr>L1i-N&vFz3t$@Hu+T(@2agxAbkZYRpTT%39 zz^UH3C^)+RFtb_t6Vm-f4^P(nxBg5tk6$s7y1ly_`7`sv9bvYeU;Ou){D;c@UCaNU z{`dFK{C)7Rj`|sTHI&Lj9s7##v5~{mhDJur$ciwrPw2?V$isASaMJ7$C=^N)+t=16 zc=jmu^fAlG(o%~Ja>}ctsTl%voJpZg^Iv*E0GHrzj>f;}^Sr-b%Xe9(j8y*!t`ytq zdv;HS<$OGbN+{5HtHU3m;JT4jqt()UFO}vBLryxS-BoE(j)_FNg$D<;wTt}edRL;Q z#3d{G12eG=3RX>KfY}YI4y^Zs5U+jCOddR@Jpp(?d_ChczWgsu#Fax zS(ZImI8;@mjjxG=46Y|v{rxqPAnX!k>dgA-u-c0dNRJgq>Zth_ljdSyjfSh#OZNGE)MuB~^d zweqwh$G8G^n`-Tp=$`#yC3tBP+#c6$M_$X`1T70KYHl{)1>4_))dbgZY7vHRbz2kC zKHayT%F>u&XHpR$ado#4&X-g-W~B;M%4C80le%6zf3zct7lbL;kkjB@Y zy>_;lT)VSao}2_cRGZ(7;MOOxPg46-T_z;0PwYKMu`b*`L&=)&w(7$UP*TNlsRv+EiRZlT?L{CsvCY+M^_C*u5~>n$IPgP?Z|JjOawql3SQn9{vez>Kzm zlvB61TRus_h%qD3nr=q|CcCZtjGDaK+vvXN>$dZ2P>WkdaCepT2#2+{8q3hd$RS~H z5(?pgtI_5%uTMb!UfU4--p|MY;&=>f7(ypky%Y}-dV9dA28%P z-rgiz4~tVJEBz24$?2R?tRGQZcYw+edS$kAS-P?^)NNuvJzGPunR>XzaymF{r`A0Gfy-pL81D z&6+Dkz_)(%j+Qr>wlAF9C`(-wy%x-4mB-h-sN<0%a8UAm}^AfxploO z4YJre*`S;G9uJy@bb1FAYdBVbs(x7<@v!jpz86jvyR=X7cs%R<`~71@i>QW*^+*k; z>}Ozs9(jn{G-Lc??SV`R_gLtdQr+xqJu2=&vqN|5p8RS_KdBSJFmcm@Y#}%lGy!?P zwVY?09#5fNphp!$?O-rY&ms31sWR>9nlG^su>rpzF;X8otETR*E14LZ@1e`*S-`BC zQN1M!@Op;}1#e-aF%^NOJ1k(qcAD0qvP?LS zeKM^(BP>g1W)U(t>I;^8JN>P z0gX%$9ygapxq6phc6uqa4TBes*XI=KCE&;c%TUnU*qL&k_O4N>tHgx+DZUB&MDJGX z?jar%1oqC&u!PnCis0)EJJqCQOqP?*4zjDmSvWztbwCt9{Qm#d^%Y=IeE<4uBBCNK zt%N8kCEX>Bbfa`5&5|PB(p}QIbeD85T}w#!A}mWS@gMa2{oVWAd;jzJ;O@*kXU{ov zX66&`=Y3o4LmHK(%OVbBur&JUD-_3+*Qfz^K+4X)K1@bN^q4axsCW|phyTuoO(lL# zOT+HOdvext+KZx6gNmTQY{dd84QA;<0z6zq_uONw*%=L^*Hm=91HaH4AirleJhpSF z5shp&DS;n!-!Ltrx3!2MemWAI7s6`oXdUJ-@OBiN0YKE}alxw0l9IIEa zPwqb`=+;q67V0T2F*q#|NHBwemZ4lTXomUGYP zQjdpEQ#};$M}%cWI~(M#&EKQ6TIGI19-Wj2|BD6i9gaY3Zz%NisLWkwJ#BSrY|e0F zMWcayPu#V^vlv2{rv=a$?!g?|?FK^?oMDfhtX|6=D3!TM-_I-k@(~ePd9iqtT@oGL zvsG4Qu4Pb+3VYP#b`%BsotZ{4WL5l8IF(P;09@@R6c5arZY5)?j5IZ=k9%il0-BR8 zgVMRk-cx>;~u@~Cw< zCH0PvN8iE$eSIAYh7`eu;L;Caxw45YIm0`Q9{;abU?3a%hJz2I`PRT6 znIT>B;4lA<^Wm42-Kx!e-^vIzV4o(=*nGNS^hMvxZp4+8nW zY~>ri%VXx-h80{~IJp73RY_4Xu~&cW+cs9erN9Ru)6oA|z=Eqjf8ivQ_Tm6{Wk%hh)30|@3;()jgLo1NAK_LrKF^c z01n#-s70hZp8Jx9z+G;4d4+Po13nmSigK5?=Qe%kii)}~^Z_8{k&+S)034-zoG9nR3YQBof7>{~l9@bD(FH*x z-)eY9&`34Ie>@hIymTj^e?+S^)XKK#i`UV;aW;Gk`Jfbnf%Nj~pQ zIb@oLhIVlcNAZPq5;BS`|(KTTn&6+Ht1|2^1V zxa52Bo;KWz*LXH;Oer0}qwK<#Cy{-V2eSF{AKj1og~DG+>yxp^hM?->ujpFmR||DG zbc<^KcX+?4hOfPg5xs`|{K_BfdyTSNLMi$3sM=3uIX7QDFv^=+?^z>x!?3wJFot><-f`S8% zzPx39j)i4lzGjfg>B)vvkQu$=RY58xw-0UIg~5kz4mwoR&mIS0W-o07`c`;3cLjtL z3nWfD4Z+A>74DIr8s=eS9~jOTXKYQ0PzZtPA}il3&C4jDQ)ScO;&CQbeV>4+S|Y;t zsnsaT+%nL$%0B)4_5ee7jmVC~#M-(P0@1tf2@QQB)Fwa*B=6<})i;p3j8@t*LA~wj zERE@C=*Q#ND8C$}YhcC7{Al*)qGzeRZs%J!GE>m=<c!l~-Ka`xmAZ`W~(^|B$dfxQ=cyen?+Dq21aE{-qxK0|V{aCmB=S8cpXY$_#Lg~O8N4_h zX_!yi=$nyB1E($vC}GFdhzQR?^2S{!Ma8k^t$PCDhhsglR|gR>%&LAEA0}Wmr9yFy@W5x9Y;+7^OjL|?HxB+kzox~>De5Di>TWYu%Jzi~ z;=B-9ovNrHmZZ(B+A>bFHKobwJX=u|a-Lk~3d9iBq&kib+}e(A(=}SxmH565MDO$m zzRr?|ml*{G)-}RZ(+`s>T^iD3eW|8&7Eu{qi)lKe)i#fxqvR5>EW5Co@pYDxX6W?? zu9efCxCewEY5Df1`u5lGn}cH426>mqctMfFv>&IInv`6j(L=Xv`P`s2m!omJhw z#g?~|&D@5-uzyg|7)s_dgsdsxwFUEUme5^>HrJYNn*yBNLMJlF4Q6xvKf z?=n>49x>g_^rAqtxW9$igRVf3`n{d`^x_a`>5&3qT3D#7gL9(5kjW%kNy}cT*TI@k ztA70vmWjFYVaLnRgxK#HYxgtN&lRYuJ#j}gSPMdx!Cj)E6Fn++Of7XU>)$L+WqYvV z1WdFy0@N{MIVIXu$RW@QYaZs_)fdi_r)`MGh`zo)QCy&;YX5dijgB@jF_|tKQ&dz8 z>>V8~|5=omn`^Go_VZ`vPd`9GfbytJw3?2^LzD&uBvK4tkGTyCOmX;qHu}73aPG#@7tBThIB_|tom6vu-E+mFgQ!ui>l?7YPeh;UkyY{DB zuWNZw&17$2R5SIXhv_XHUo_3EkC*3}`FV?U&;#B9Mai0q^ET||QQ`Nh>(vtt=7*Z{FA;O56FDo|Y*(*WJ|B0KXZR7Cn$vL?#L(W!9}6rxmrP z`Wy5e#r5QuKD;h+nIS2%d8tB+dl&2Gm|Ms`s~^5y##1<66YNu@)I~I9-4$w73t~*`F9-W$Rqigq-5i)HI2ghLQZQcI8 zJ?yWW1RFsg3Y5D$JFCnmcO={0jfia2cNq1gm9ixOSv{8mOWtUbUuJMiBZb_xcp&Y* zk~SRniGl}B>%1Ioo44LP@HkXizR>l|)H9XIMg7flEFdZKKk_%&vvaVW2Te|2dT@#N zdw#l)`H13GW8q-MpS}E81~--s`fR_*J!8BO9>SOMM4jJp^7)OGO0vesjBeR4MEB@A zzRziG?&#qXK8(PKm0NT<^E&c6ee9!p!ZKPn8jNdUMHihe*}u{k1YBXRS3$*BR%yot zkLAm8*w}-ot(=u%1#_y)N;pcKEI3$L@lgrFQwznjw3Cx8cA8I8Z#GBHsi5JDzpv{E z?HBIV%2jpyMGFcab}U3n)yCzL#bFyL0_FOSjPh&iFYzKT@_d60H*~BjuK5zDbJP8r z6-JrOBM@jGDR#jXD02)Ut&rPil^c=>hVp6uW^ zTDIn_#t=>RV*i4Ig4oY3DKf94KTtiTD=|-ymz8Bm&$m&}cK-535SV@tH4Qz_7lFJF zhp6SVwUmlHmEvBDiI}z-z0GUSS0ZxXSOnmE>zzA63TvY^cwWoB=Xbq7#CjS|P932# zyB0G$v{Lk%X&Zb4>#D9=ZCdrxHk*57FhX^?osl_D>IIv41+Lo{amvl%>1qpCsK#oJ z$KcGZlM9>a*A8S{ZIN%^zM(2I);)PhkA6;|TH2a_lCQlft4yYstfld;?{sBdUKbZ@ z`#~u2Tb_!Q)TL)hPsj;QQ4>Gef^>oU=pceGKnd-1=z96rj8Hh~I+v!0`Pl1K6 zlyx6?(^R|XSmCJ*HXKYZF=G2h@gx(Jw2*V!eWffC38{1IsZ9?Ydb=tKotPWejxf?N z1m~YQNQUD1H99SUH}fo_dq+{rUk<=Qe0JK@ej0hX2pK%y8-tfd#L;v_2AcRk%v(u!1(3km0Rj$w(jMwS$X^j zu=1Jm8qKMa6lJr~yWkmQ2h?!BAR!%fUQ`O)>M zvCVp|x-BbiqN4igvlgEHX$bLJKI58PV_m+BYJw$d3jGCLokpMYosh(ZmJhW0Pv~{D z(B!pd@+3;0N{hTk2A{vF>k4}^{ND5;>Beo+4-b93CDDF6>&_i7o|)t%w%y4ty&oqM z=?)8`MmY3ngK72qsmnvEv^k^#7)yu#7_gBafq_(3-JvIEM#~Q%V1cvUFI7y|Ty&OJ z+w)9l;Gwsl=#x%UYOIkKWE58MpskwKG+i1~)0kfA+J%q%$KT^rvR~ndl(sIFfMfaO z+!q+IrQrKF8$MuW!W^piPCK0D=TVU?_g!C7=pR3EJ9RuL*@+tph@&#VUq|K$s>pI5>&LNGerYLQKrh*Y}fNJL_{Y zGWh1^sd6xF`uCfQU5MWI+{rWnuZGXp1#7?i^|3bYfOJW|z5ES$s=Ph6-(G%+$XBKf zUwv=0IA38jP$;jAcmEY7rAWL%lhmqLy@ zFR~til0wVM-VH+U@hVlXo+?Q$B*~GCL=TOP?|2~?c?-z1DX*pFz5;YCv)XuN8j*gKkx_qpNif8 z;K}~8>pvgT?(r^>5!C{IxdY&~vVnnA;B8ZaX#u&fsi^L!0`17E|MibS<{ke@gN0#k z{L?5=dJ1;%kg=UqzJi=Er45FN;SUK_|21ly;wR-ck^h{Ol%GH!EM?@IJ4WK2FDUoG zE*NTXNpj!DV(;_cv>gy^plQse7$p9nQIPOCF?ZyR?n^(ZH!8nB7K9Fd_->Y(LvVX_ zC|OyRG8NdoYov1&iHV7|w6y#SmRdyrWcWZJQyI9SnlCsgkg+GbJ7+Cl**(iTQhm^s zTk{+|8y&--^4qzBFfpVi1QT#Y0VM|ycXxnCO})le055#=JOGn?vBg8{`F%Gxlxs=I zCQz_*yRp62=n@rGWVT%mIqjlh4} zj1vD2q`yuAaVUj19W$pgOHx{j@$9~k>0MUDWE9uHW8vm>o4|iFqa%-?cQgJLsem%D z%-WQlqAhX%P1dz3buHbL7fIesYTRrGp^mZ)!q7VIyxn@ow`;Vj!zq8du*FRY^mRsZ>{q|7hgs5=*g}Iw7`;|$8M-L zM0KCbp0)lfhpi>eh<^)tOdnxj2KaUCp}l7`BIz0 zJz-^xAz3ot>sn=hP1V^M9P=>`JDwNzPH!n8#qpDBt*+kuZ?KJlp|G`Qci6q9r;|K& zhoV9_b%x~stlM8XG|XhPLxZZK)Nd2hZCrjM7k$r($$Y8pI;FTD%%1J4XhdP1JJ=;o z&-R9@rSQd_4anB7%$hhXx`YbH($`Np8WFuc|Sox>?y%na_ zZyqEiGGVe-&3cK=%(%xiEzO#a`k^?J4G*h< zl62nttJciP+U1yUL6Xsk`!8QY_6*o;E|IH06$XOcfS$v@S5}$>@j$JQT zwLOv&N)rri`RJyVYbVL)40FDE`b5P@0+agERxQ)D9M;uE#ve6fd3GizKDlJ_f&yFg z*%kh^Jtgw9(A=yIuY41`(QJu?0O*Z?$2;5Oi}6S`0}6h24c67&FI-q&HxcFcS|ztz zcchG$JB}@2Hw2a)*yOFo?QLSSls7GjItlh3Dhd-RSbDnO1+u38hQC0drakq0kys*B z`F6qNP;7hZes}M{&$3U*Xe3kzrGli!$jRgs51|D$4e~|^uEbeG1Cx^X=R{{=DPs%c z!V#atcmsygN3TzUDrfN?Nb|^h(aZz`j?(G&5+kZV7B{W2*>;`q0MpB(HMyCr;{!u; z16o5!{fumDK<(wPJPw|IDys7Blhz2dP52Cc&ZRuD3OcmoFPDJJ>|u^}xuBxBrBUZd zRzO9_6Kdlpk!=KV{BrO@VX@N8iSF5r=$7_V2{PG@*0RmF#g@feqOSPz!_|}?vkR$u zOlM}!hL<9`RM^3lxVo7U!^ZD&H;mWm-eDK`;@bJO(=>nuBKYY}_YN>_V zZH#g~4<|nRO}LQ!@8bR%pGsS~rHPJ3d1PS$SLWZRi+YGk(qy5E!P6UZAyJ4mOI#uw zlvQBCw{{}O{LVh@_N;o+gH~&8GB0AFStprN+B{Cs{j!iF7jCcq<(ILrqVVOFy`EFl z_Zoe%6S_r04$bAt9F=K4p(KTgBqy4Wr&a9*s~szaeJ5th6G) zIg%O(X3>|sW@mDkisNm`&iHOPq{U5CLA54!S+mh}f`$sx40mJLIvI2J4EhisoiW&G zPs@^qb1vh;`o?@TWr-|I#wEn6Xp56nzQ$}Xqz{xbdD7=f1EuEE6s@C|| z(E_21m8?T1?ydN)vhG>(*o_C;4L@tinCq+2hjoCZu=SFI5s7Gz`nf-JwU5-~WJwW5 zzU04|m`qtMFo#Do$@E=#GTp!hlT~X}$)9}of~8}r9PfF8O8J#$Ly>Lkc@cmb>i%ig zRcUY(R!SxqPhyqtdNPb9d{L`COAtEofV;gt~laalT58-FY$QeR^(R z&IW)z)~M!b8(Kxmq9r^?mpMgomIpGI*&+51H=OTX?}`IAk{~5Da__1zKv1-kkMr8u zw`zK(R1VL- zD}j4b!r=F5RrDmx>9%DW>HGT~|<@!rg z3&Kfd?chcP@fsHqd+?Y%<8t%5VqzNTg46(=>Ti7mV$9YIL3w*D_Ut#e=j)isk;>Y` z0eR^-yWF8h<%u{ZxfUWUFwc7Cw^3H-qwR^V>7QQA015NUs8J(kdFb#0)BU2pL}GUuK(>@%L~>wPgeZrm1R|;y^#dh$lxAfs{@k6NUkb{DtegF1stoN)N%_Cf_S?#Qzo+%W{_+=Iq}Rd6 zd&N0N$8-`AB=wdo^lkps6#NY3ZO#g&Wp_k`KM%fg3{jD`ziY5HpQ)#&rBtBs+zYO7 z*0-ygxljMXT=1i4XAU(%HSxRbBL3J;QW%)K-`3&#y=1S|tx@$=#(S^XI0)=)(s^Ch z5)5bBRC6PuS#~GtAvPPsZ0XApj2>#S1x2yn?Gbw_erj93Qycoa8ZpUGwb_=ocq%b6 z{#1%x-u#e8X6dFHzey|Q-d0r!K03Mkyl{N}tCa46nF&X+61Y^5tkXV+c4%a7L7 zSCmkBuQy}7X<}ypy&MRHh1EzU?5zu6vyQ8cCo6p7Wzvn1#mz}t1NL^o50;mkVFepj zJhfF*CPD0F7SqGkdq1!Cj);G%TR`52KYW5^rc)fHzA@VVQyH*hW+qBJq>Gv+LM1T8 zi)?@in{%x$pEe16AwpwPRFRUR?+tBq=IAMu&D+4o_K(!8e)5~SugR@d5OuDJtkxH$ zr;FJz*~F)HQProfeDC3at){TiO|s<1J-r_*q_YsFL1BealxNRJ?i_MLs@6zn&SbE> zzci-U|Gl%l$R|Q_ZsAN{x3+Xj6ZUYAQ>R;mPm^}7rz<-d2INluH8co zzsKI6Kd5vkH@Jm>X^!GVFkDLkXJKKS?CEomY7CTxtw-la(Qd4@UXl%&%9 z>d?q?W~KA7Kq+Y{FlnQvl9eoR&8h<-CepM(K~bB6g_&L7fe;E}zw5s50y&Wdq}rc! zDrdjceJM{<1UpQW&DBYhQ*BZh72H2QKDM*BH)7FA|u@00D{qD5*K&dzN3tip#SS6ZuuX_6%pABhNw zcI?f>a_$ncic;a?;YWH`Pn}y0RbwZ+Ic#l@de>F#@t8bI4}3=ogG#3dsyBvTEhvSP z^1a!a%=2mHH`AW^RWMO`BpVrshZ})ikfHEq$C*g;4I?dfZ`4~a4Vj0}9u{|(ZtN<- z9>O_?`1D%iSp3EPwe5t01YbY;H1gY0k8+t3dXMe%lsGV6KPl6tcDd)ibulEdg|_L3 zcp)0{5=AErd$_cjP2P^jU#kIX;VK9Ol9OX(;FZ7tMF2j+=;-Lw)D#lV;r;@Yu}!|A z=~7eG2uAKP3^3}x_ot^}8kD0Ov3FuIanvf_p{kZDcV~hb(}!* z>607^e>Zm*CKiiDkBqgwpIK-z3#bRL08s7gY87CPkH8;6f}#wD!tP{Bg})^GFWh(>EVoDQ6Ln!^E1>5* zPJ3nks%Uk0U~w_+a{`@OY47^c>k%hDK0d%df^>UeK)%=gt;NfA4;@V6+B9Kt2vM4C`3J+HHjZfWU3i?fu^y>VDNE#S=Bw)$+UEy3QGq4^eZU zTNDkv!~q+2B64%|Ha89mqi!zpkgd+$(uflSA|XJq1lakNfNfDtY{#?uS@V6+i0|@W z^+s8m$>|Sgz|p@xGn499$YpG9A_yRZfRn@UI}{&Z8FL28a`6v_wf}S-tclXT}LPb7ns8V4wKcU19>eq{J{X10C;>Z@>j`-HsKjs3y zszf}qDAsDBz*2b)ptI>j__+x|zh*bjiI&#bDLjnIAnsv*#y%2A>0!hPNm?7&{8G3m zrgy#6Pu@`E%9wGo#tXy@+U)xf<_GCxQ9FObHbl9MxpwtB0gY(emAu@g%`9O`JFY}9{745rV?BL z@iYKCLUwn`MF(jLITF7(vXqao&W1cWQMuWH*1P@*XnpNY+9~44hV1A~o^@prVfGar)}e?b$s)->zqtItW4zLOC}Ofd(Tt38 z|MNKk4Yk#;kR2;TtkSW{5+rFkat)a0@5+$%BUIr5@X`Q&m+j({-gys^yg;ePvd8-R zX*I%qe;Pt7dNLzCvg|BLQ$aT~AI#sqkYS1jP?yTLh)u!fjm84FmvIzKlqH zw`20wPaW)kZf4+sASDGq*nzzCA4OS^skZu``xZF#U!eBO&Cad6rhDxj9seNyfoH`? z!Wn>X!nr*U^o!becmHo74@C4ijhtnFfRtHm>tBAEZUE+d6n0~9P5$3^`E;MyM3M)D z|7qbiI0_V~f6fXEJkwpW@!T>Z#fkL=;Eq&WT<2$p ztH9GkGme>=d3&}pFFG2hVRw6uFtPc{ova5#GY+eKuvai-`3{T2ADEQjJ;bH+xF%s? z%+@1QeYq4)W``{W2?+^?0ifu1Z?@88j7mHGD8@=4U0Ppm&{RwOxhd*g`_HNcP}l}x zF^~PQ!DLBE-@e`5|C|;`LQ0D9`0>uiH@Dyx&-p2nBUE@&O;^v&RFCIbgXQuAxO+H_ zxJW|nyC?@!V>!_$A|yBDmW|BEP^EmUE48&~wP#i272L9I@waPOaJ&zp)9AE6ih+m* zP2w)iAGc!ZG?A8+Sf(b|Vh~;r`@evxQv$J)b8%|R|C@$A>Q52=GQzi5<)`Y6$OCS z000@Dl)M-7$-+3F7tGa2L0U;n^|HD$??^A^SLa`pk?qND6&WKVix0vXaTL7U@cM)8 z`N7lLQ2HnGrLeSjCsrIMIa}%RhJUCr+s4~}V1Uejjb}lOU7w`!7ng*2i!KfRY=q@= zJah}9y;hCAJlO2GTClXzo_mVgap~GCr$x@J1T8eB?(gfkH^^TdD!-N&6}yqK$GoJ~ z6ca79SaPVT+BsArkr3?kemG6c8e#% zygG_Fl{kizO_Ztx^mHgD*4cQP@~BA=K)x>Pkx3Oab*=>k{NY`C3BA{pkp4KJt8dlSyn6y4Zlj-u6v%$iLCz zvb{(@$-$`TzGs;Qk$(f*cE(kbs7m1w8U8sb_o@iICFHAlBi2<;Y zhqoM0Q_-k))D$W#oULY&BYNNssWCAQOc!kt22ID4+F}`@oKY-x>x*6y;v_n2Cr}HU z66uwo`;iNDh+6Hs=qMuRHP#5FgJE^74y?$XDJIA;@2LCetQ&gmGcRM0FXQV+Z-)Lq zU?9?kH~NXwZuM2R%+wSZ27P;;WK<*ar~`ty!X0&`UasdS@{*_MSr27ita{jtUm)<9 zlm0Id5^@r$)n)BK!rij#Q=$cl*TcwYsJ4=pX{*D6Q#>7lRAb~1t4?c*DF|S*g*}(u zVYQOZ73fYl&3)@@QB^Dlqa?Gg?6M#^hlMbn zT5UvX^_P@dW;zxNp8b&Nc?ynwa2s<)=_>{xnvp!PnaYK?w0^~Pr?#E)@%bQY-pZT< zCQA|Ou_rsM@M1btnL^cQDXb+{IRl%RtJ>ngI3xFY`GGItPgQy>gHdEj&=5tOISRMjz?FF+K8C)q)5;X>nQ|;Tl0A*_K`Vjb4KyQU|(dW!E3DUTRf)X~OWx zk^NI=+?`4RlFtL?MQb>iYPV0o+Z5uRz+xV`3-|T3@#&RlILY-O&rZl8`96c!1|eN# zWUQCv3y*sqioJMufl}d|%{6_ULo;ly#(D)+*VppJ(zVvlKGHyq(gnaJj?fm5hT1xp zBYjoTGnLa{r6=6(Cli)Mn$*q4rJ9SapB4sn0X@wH8jtEzZ*8kre{e7Z7OGAM=@8w0 zSb^g}9Dm8&v4*>b1`q^zo}LYdM<9@IV$0z|);@bG)(4MaN;Zk0-!Z6>$$ZI%6UapKO zu^!L!?m1ph=?|hpi8E#@&mGWX#Vr?AW=t+YbpC;CY^}z8J4@!WltQbIM(Z|rdF)=` z*jEN;QbbCTJsq&b;oukuZhm`PEM2W~^v{!q*FxXn&e!*f7E8=F&rps%EyR-Zf&~}9 zjs7=QM4cj1{)5_8qJ%23M1!xp{=UMPO3ltMO`~j$kz@wZYD&V6?=L5Ig|;6u_z&OM zZ@EXANZ7b|&4<>*y|rjGrxQM`N0U(%=7%K&)^(x3Y z;3U8Q z+t%IMVr_^3NrJCQXQB55+*^)DCeH@-{VF)uk8;;};96Cu&f^Xz(tCUk%DY8$_|~mj z^uHf)wBwhyEPb}jZww4P=Jvghzpvdgo?*d3qdLKx9ior0al=b(tc6^;SrymEK8SW_ z(k->;tN&k^4)&i)j;99)Q;Tob{C>c8TXm90z-u6hTp&qNoCKaFE~8r0Q?I|)KNnkD zi4*Z>7ie`K{b|T$d#-k)-auK+3w4V~#DCH30N;@&wDWcWdtUlA)95?q=SShhk=CUv zWuIMrakmSXix{EfuD5p6L`B>*zp$;D_X|m0`Vx5Iw)zw(uK!e&*LqR2nq({Uzyn5=eS(uD2aGu^naC51JaF>$;?@NKf-mt5V23S zt{goM8-jeq-5%K?Dk>uq{}zY!BM43@v08SV*t|j0s$}D^J7v=Lor^~6*n-K^_3w*H z*LO|v9EJG5%c7s^dR$!~0sT-w?Lae5Qc@DIpP|{3(MgsxcIDEp4z0Yq@Z8bvr|Mc* zhXOZ2=K}K=S$cek`7=HE_XL9~-DIXmqO_ykTnz6f06#Jg2z~&elps-x$PbCUeX)`4?#G zG)KS1t0qU*b{2lvb4l&GHl|xnR5PR1)KXev~%n=k9ivh_>a>DSbzWh>tFZfpE%IJwc!6& zL;qXy@lOu^Zwv+`*gAx$UF18cUZ`ffeQbfge(6Wp@L4XLCku@Ib?w^ULTQ%1?B?gw z68-W11Uc8w3&zvt?ZzZ1|NQ!+Jlr*Zr|!<{qZAK^Pe_eYWG(C`S7nl`hO2?gaGV$gz)p6`*W_K%Q`sdFTUrw6F3e3 z@6JC_u>XwyZ=~qoxEJW+tL~dS=?BD@`U^m1`1YTg50FR7=I;B!tKbD4vZRoD$&Sjs69gv_F{sJL&&4{7=RGzmxtyX8GT*{~$L0o%GW!GoZ3O zq9>2H@uYXO|FzghHidBd0THyW>mHr@?%vW?e^r(0nwqI?hYNT9rxSp*m|3-^)%#>B z$;=73U42q=vd_l9HYtAS+8wKtMCF>_L?D<4sstSXWn9VIiRI<-oPLZdYAZHDmcc zYxD)2OF=~?qG#2C+wVDkh#wdYl)*X-#1NjEV<0MYDfQ<1U7Lpuxiu$o`+qewG&D6e z0ZM6KFdc;-X~f}RV*_$XJ3BkVgiB*%`qi4UucII0J5o!sB+953Rp;c~Hg`Kc_r%^k zpO8rqAlUZt{yzNb)V2BW@KCdmkDq^W7wON!^8C?@FmZ-SYc`^L-XH`JfduCA;bTV- zK~7=eLse5KDnHIh<*B0-yHma6*7}p*K(n{gtQpjz8G6SM0E^wOC{unY=KPN{MuUu& z%|z!vZ3sTe$PbUH$T1jwryrYIA=oz1V056!w72?8>QvY`5=LUp0{# zyxhN6Z^Iu`Yw0xnL$c=3=_*kktM47Mw5fLUncJ$dJwV_5!R&n7%f)o2-;1~+qYc;5 zDC7daT(5x1eU(6fEH;|N;GHP7QA7&&?cH{@5-<#%`1!MapDfnZDuK| zJc$L}at#C9uoiVXIyq@4T)Hg#(H*PkwC>z~42s?qub9 zN9D&v8?8Te^-)&ZF?}U=_s=pu{+M>uN`Mw_s zvw0O#QzRfViqT8Cdv#i(=WWXZ5AC%}?{4FYm?P^6ir>rZ+HU(N`>vP$K|Z~7Ri7oa z(d-0+Sg)C8`5SRDT460?lIr)gPw#1rLz_;|Bh2vtUSN68qcJ{87WzYUbbPnr)6LdR zMZf35R%b^@w4U|3mBI3wCUnF!3DTkVL|1;sdyXZ5=bVSq?uQQ0f0LWkIS13-Im}ah zuj|8bQgTZGaa8KVPKIQG@ieVXMMW%vZxjqrtavtVCa7iO>gh#9Gwerc9*cU@Swq5M zL^G$!k*tAD9kRElG zEC!IS&gPE5@)qootyvF1f|-utB1OKRhN%ZITL9`uDmwSWuSa~ z4r98kuljU&aL|Gp>XoQfVS69bjQYAcX~ue8N%iI~nl5moLY8_mxOsIvW@qDQW;BwPniv;LIPG3sT-ssuP-@|D z>gRL>vDZMh)?-ZIQ20 zUPLYNIKgLIH`n(ZPlt3j6lMU{3|D68_+8M*CtyX;Z5c%~Y662#*?T_ot>pTl$|K45 z$#ViyhRq~zMJ;4kYx=*ANr*WzozT&wBHPX7;VTBrU$$)MPCaa{F-|v=jdU)5qs0#n zU8A&irF;|(4Mp3)*;^S|%o!1VbtesbZ(eIqROakPgTbUV(hde?$zIP! zBQYAzcut|N2mhVB_Jjqgi_SOlP+~N2jCZpaa!y&JkpceN6&jjIqtMEt`r~1r_L!qLEG>dv8d_fHeSIsjVVRM zYj+X7E8Q%7zle0Q#e-=vDt+4cj1ujpF7xmKYXJ$H0m5PkEe{;$I;ld6nvaLQBApyJXIT4sy`?hv`n25Q*yPAP zU+FCktfb*2pdI`p?tv>v@L)8e;l>2)RyXfP_J#o*5w7PqQ{t z5zC%9`CVmRMd!NiMG;l`Qmft^_${g| zM=fSt4Zo&gsy0ler*GPyo5)JO>#v|k*SQ`H5GP;&A4AipT~sn%9kDiLxXO^e+)W=MWa#$@oiKprs*oR7W?F9(5|6E<&6lXuY5bQSS8;JiHPTCdmILJ+p4E;W4PiXb&?>FZJcknp7#XXt zno7lu)@Bx-G6c`q?|Kq1^HxJB1dtOoY?xW%2@74rAGpL`5D0aSR6Cq1$%q zW@cspg?mKqTCNDJrorx@j+vDrdq4Fp5>>Nj-eTS#mgo;}_I)0*g92mX1NoqeFV}}p zS%=hI7NHvD`eH&tLV#kEsHm?l#0CXB5zHIkM!GI&RM6L6#TscuQQZMOk}rnd`})w# zP6MI_NjDL8+xBauiy%>A@y{hT#R7PRTvGsZ_$$5vNGucbmZoK<3YOVz6wx%*y$s}> znj<%iuuXbmWsjpG8UbmyCpL&p@HNn>lPw4C^y$2uV0Ybg zIf5~0D&dod@dG(Ib2^OiKcA1C14Jy9Z$O~CjFO^4%C60etB0lqP7ys>)4PeMHc6X2 zlYpct>J9L8UQ z1Yw7+Kd53-?WB zub&Aa{0~9CdTHc*Cf6~Re7Eh52&Nri>)ZwHubs~)=i;jO0oh{Eve&2SJCc9}-fx{Q z4tzIVZ7XGHc5Y!#tLtQ%x%1cA+(JWhN}bw#AfSK-N}AuV_3)6sbp+YIZ$gdELKg8N zlrce?KjMuvR8($V$_#H{0(UpX0vcx#bU?qWd0X|n9?#t#N#up<90F5uO^%3VjXAYl SVFlU&Ns7sdmI{CR_WuCPryREc diff --git a/assets/server_owkin.png b/assets/server_owkin.png index b05ac142ad2be71b1cc70cf95c7b8f56a2e604f4..60d2e83a3c87f2a20553014d3cb6b265dd4e1235 100644 GIT binary patch literal 148796 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�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

    cpW{G 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 literal 0 HcmV?d00001 diff --git a/fixtures/owkin/datasamples/test/0024901/LABEL_0024901.csv b/fixtures/owkin/datasamples/test/0024901/LABEL_0024901.csv new file mode 100644 index 000000000..ff746af51 --- /dev/null +++ b/fixtures/owkin/datasamples/test/0024901/LABEL_0024901.csv @@ -0,0 +1 @@ +0.0,1.0,0.0,0.0,0.0,0.0,0.0 diff --git a/fixtures/owkin/datasamples/test/0024902/IMG_0024902.jpg b/fixtures/owkin/datasamples/test/0024902/IMG_0024902.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5d11774c6c6b3d9db938fe81d1d569ff40001d90 GIT binary patch literal 249153 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

  2. {^t#z+bf(i^M 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