Пример #1
0
 def test_generate_fixity(self):
     test_mock = mock.MagicMock()
     result = "916f0027a575074ce72a331777c3478d6513f786a591bd892da1a577bf2335f9"
     with mock.patch("builtins.open", test_mock):
         manager = test_mock.return_value.__enter__.return_value
         reads = ['test data', '']
         manager.read.side_effect = lambda x: reads.pop(0).encode()
         with open("test.rar") as f:
             self.assertEquals(result, generate_fixity("testPath"), 
                 "The actual hash differs from the expected")
Пример #2
0
def create_registry_entry(correlation_id):
    """
    Creates an entry in the local registry when transfer
    process is completed

    :param correlation_id: String of the correlation_id used in IngestAction

    """
    try:
        ingest = IngestAction.objects.get(
            correlation_id=correlation_id
        )
    except IngestAction.DoesNotExist as err:
        raise err

    replicating_nodes = ingest.sendfileaction_set.filter(
        chosen_to_transfer=True,
        step=COMPLETE,
        state=SUCCESS
    )

    if replicating_nodes.count() > 0:
        local_bag_path = os.path.join(DPN_INGEST_DIR_OUT, "%s.%s" % (
        ingest.object_id, DPN_BAGS_FILE_EXT))
        fixity_value = generate_fixity(local_bag_path)
        now = datetime.now()

        # attributes to update in registry entry
        attributes = dict(
            first_node_name=DPN_NODE_NAME,
            version_number=1,
            fixity_algorithm=DPN_FIXITY_CHOICES[0],
            fixity_value=fixity_value,
            last_fixity_date=now,
            creation_date=now,
            last_modified_date=now,
            bag_size=os.path.getsize(local_bag_path)
        )

        try:
            registry_entry = RegistryEntry.objects.get(
                dpn_object_id=ingest.object_id)

            # in case entry already exists, update its attributes
            for attr, value in attributes.iteritems():
                # this is to prevent modifying creation_date or last_fixity_date
                # just update last_modified_date
                if attr not in ['creation_date', 'last_fixity_date']:
                    setattr(registry_entry, attr, value)

            # set flag created to false
            created = False
        except RegistryEntry.DoesNotExist as err:
            attributes['dpn_object_id'] = ingest.object_id
            registry_entry = RegistryEntry(**attributes)
            created = True

        # validate and save
        registry_entry.full_clean()
        registry_entry.save()

        # now save replication nodes and own node
        for node in [a.node for a in replicating_nodes] + [DPN_NODE_NAME]:
            node, created = Node.objects.get_or_create(name=node)
            registry_entry.replicating_nodes.add(node)

        _status = "created" if created else "updated"
        logger.info(
            "Registry entry successfully %s for transaction with correlation_id: %s" %
            (_status, correlation_id))
        return registry_entry
    else:
        logger.info(
            "Registry entry not created. The bag was not transferred by any node.")
        return None
Пример #3
0
def verify_fixity_and_reply(req):
    """
    Generates fixity value for local bag and compare it 
    with fixity value of the transferred bag. Sends a Replication
    Verification Reply with ack or nak or retry according to 
    the fixities comparisons

    :param req: ReplicationTransferReply already validated
    """

    correlation_id = req.headers['correlation_id']

    headers = {
        'correlation_id': correlation_id,
        'sequence': 5,
        'date': dpn_strftime(datetime.now())
    }

    try:
        action = SendFileAction.objects.get(
            ingest__correlation_id=correlation_id,
            node=req.headers['from'],
            chosen_to_transfer=True
        )
    except SendFileAction.DoesNotExist as err:
        logger.error(
            "SendFileAction not found for correlation_id: %s. Exc msg: %s" % (
            correlation_id, err))
        raise DPNWorkflowError(err)

    local_bag_path = os.path.join(settings.DPN_INGEST_DIR_OUT,
                                  os.path.basename(action.location))
    local_fixity = generate_fixity(local_bag_path)

    if local_fixity == req.body['fixity_value']:
        message_att = 'ack'

        # save SendFileAction as complete and success
        action.step = COMPLETE
        action.state = SUCCESS
        action.save()

        print("Fixity value is correct. Correlation_id: %s" % correlation_id)
        print("Creating registry entry...")

    else:
        message_att = 'nak'

        # saving action status
        action.step = VERIFY
        action.state = FAILED
        action.note = "Wrong fixity value of transferred bag. Sending nak verification reply"
        action.save()

    # TODO: under which condition should we retry the transfer?
    # retry = {
    # 'message_att': 'retry',
    # }

    body = dict(message_att=message_att)
    rsp = ReplicationVerificationReply(headers, body)
    rsp.send(req.headers['reply_key'])

    # make sure to copy the bag to the settings.DPN_REPLICATION_ROOT folder
    # to have it accesible in case of recovery request
    ingested_bag = os.path.join(settings.DPN_REPLICATION_ROOT,
                                os.path.basename(action.location))
    if not os.path.isfile(ingested_bag):
        shutil.copy2(local_bag_path, settings.DPN_REPLICATION_ROOT)

    # This task will create or update a registry entry
    # for a given correlation_id. It is also linked with
    # the sending of a item creation message
    create_registry_entry.apply_async(
        (correlation_id, ),
        link=broadcast_item_creation.subtask()
    )