def test_list_instance_index_fail():
    """Test if ObjectRecoveryValidator skips processing successfully if listing instance index fails"""
    index_api_mock = Mock(spec=CORTXS3IndexApi)
    object_api_mock = Mock(spec=CORTXS3ObjectApi)

    index_api_mock.list.return_value = False, {}

    config = CORTXS3Config()
    probable_delete_records = {'Key': 'TAcGAQAAAAA=-AwAAAAAAhEs=', \
        'Value':'{"motr_process_fid":"<0x7200000000000000:0>","create_timestamp":"2020-03-16T16:24:04.000Z", \
        "force_delete":"false","global_instance_id":"TAifBwAAAAA=-AAAAAAAA2lk=","is_multipart":"false", \
        "object_key_in_index":"object_1","object_layout_id":9, "pv_id":"AQAAAAAAAHYKAAAAAAAAAA==","object_list_index_oid":"TAifBwAAAHg=-AQAAAAAA2lk=", \
        "objects_version_list_index_oid":"TAifBwAAAHg=-AwAAAAAA2lk=","old_oid":"AAAAAAAAAAA=-AAAAAAAAAAA=", \
        "version_key_in_index":"object_1/18446742489333709430"}'                                                                }

    validator = ObjectRecoveryValidator(config,
                                        probable_delete_records,
                                        objectapi=object_api_mock,
                                        indexapi=index_api_mock)
    inst_id = json.loads(probable_delete_records['Value'])

    ret = validator.check_instance_is_nonactive(inst_id['global_instance_id'])

    # Assert that object oid delete is skipped if instance id listing fails.
    object_api_mock.assert_not_called
    assert ret == False, "value was True, should be False"
def test_object_metadata_not_exists():
    """Test to check if ObjectRecoveryValidator attempts delete for object oid """
    index_api_mock = Mock(spec=CORTXS3IndexApi)
    kv_api_mock = Mock(spec=CORTXS3KVApi)
    object_api_mock = Mock(spec=CORTXS3ObjectApi)

    ol_res_val = {
        'ACL': '',
        'Bucket-Name': 'mybucket',
        'Object-Name': 'test_object',
        'Object-URI': 'mybucket\\test_object',
        'create_timestamp': '2020-03-17T11:02:13.000Z',
        'layout_id': 9,
        'motr_oid': 'Tgj8AgAAAAA=-dQAAAAAABCY='
    }

    index_content = {
        'Delimiter': '',
        'Index-Id': 'AAAAAAAAAHg=-BAAQAAAAAAA=',
        'IsTruncated': 'false',
        'Keys': [{
            'Key': 'test_object',
            'Value': ol_res_val
        }],
        'Marker': '',
        'MaxKeys': '1000',
        'NextMarker': '',
        'Prefix': ''
    }
    index_response = CORTXS3ListIndexResponse(
        json.dumps(index_content).encode())
    error_response = CORTXS3ErrorResponse(404, "Not found", "Not found")

    index_api_mock.list.return_value = True, index_response
    kv_api_mock.get.return_value = False, error_response
    object_api_mock.delete.return_value = True, {}

    config = CORTXS3Config()
    probable_delete_records = {'Key': 'TAcGAQAAAAA=-AwAAAAAAhEs=', \
        'Value':'{"motr_process_fid":"<0x7200000000000000:0>","create_timestamp":"2020-03-16T16:24:04.000Z", \
        "force_delete":"false","global_instance_id":"TAifBwAAAAA=-AAAAAAAA2lk=","is_multipart":"false", \
        "object_key_in_index":"object_1","object_layout_id":9,"pv_id":"AQAAAAAAAHYKAAAAAAAAAA==","object_list_index_oid":"TAifBwAAAHg=-AQAAAAAA2lk=", \
        "objects_version_list_index_oid":"TAifBwAAAHg=-AwAAAAAA2lk=","old_oid":"Tgj8AgAAAAA=-kwAAAAAABCY=", \
        "version_key_in_index":"object_1/18446742489333709430"}\n'                                                                  }

    validator = ObjectRecoveryValidator(config,
                                        probable_delete_records,
                                        objectapi=object_api_mock,
                                        kvapi=kv_api_mock,
                                        indexapi=index_api_mock)
    #Mock call to 'process_probable_delete_record'
    validator.process_probable_delete_record = MagicMock(return_value=True)

    validator.process_results()

    # Assert that object oid delete and leak index entry delete
    # is triggered if metadata doesn't exists.
    validator.process_probable_delete_record.assert_called_with(True, True)
        def callback(channel, method, properties, body):
            """Process the result and send acknowledge."""
            try:
                self.logger.info("Received " + body.decode("utf-8") +
                                 "at consumer end")
                probable_delete_records = json.loads(body.decode("utf-8"))
                if (probable_delete_records is not None):
                    self.logger.info(
                        "Processing following records in consumer " +
                        str(probable_delete_records))
                    validator = ObjectRecoveryValidator(
                        self.config, probable_delete_records, self.logger)
                    validator.process_results()
                channel.basic_ack(delivery_tag=method.delivery_tag)

            except BaseException:
                self.logger.error("msg_queue callback failed." +
                                  traceback.format_exc())
Exemple #4
0
    def __process_msg(self, msg):
        """Loads the json message and sends it to validation and processing."""
        self._logger.info(
            "Processing following records in consumer: " + msg)
        try:
            # msg: {"Key": "egZPBQAAAAA=-ZQIAAAAAJKc=",
            #       "Value": "{\\"index_id\\":\\"egZPBQAAAHg=-YwIAAAAAJKc=\\",
            #       \\"object_layout_id\\":1,
            #        \\"object_metadata_path\\":\\"object1\\"}\\n"}
            probable_delete_records = json.loads(msg)

            if probable_delete_records:
                validator = ObjectRecoveryValidator(
                    self._config, probable_delete_records, self._logger)
                validator.process_results()

        except (KeyError, ValueError) as ex:    # Bad formatted message. Will discard it
            self._logger.error("Failed to parse JSON data due to: " + str(ex))
            return True
        except Exception as ex:
            self._logger.error(str(ex))
            return False
        return True
def test_object_metadata_exists_and_matches():
    """Test if ObjectRecoveryValidator should attempt delete for old object oid """
    index_api_mock = Mock(spec=CORTXS3IndexApi)
    kv_api_mock = Mock(spec=CORTXS3KVApi)
    object_api_mock = Mock(spec=CORTXS3ObjectApi)

    ol_res_val = {
        'ACL': '',
        'Bucket-Name': 'mybucket',
        'Object-Name': 'test_object',
        'Object-URI': 'mybucket\\test_object',
        'create_timestamp': '2020-03-17T11:02:13.000Z',
        'layout_id': 9,
        'motr_oid': 'Tgj8AgAAAAA=-dQAAAAAABCY='
    }

    index_content = {
        'Delimiter': '',
        'Index-Id': 'AAAAAAAAAHg=-BAAQAAAAAAA=',
        'IsTruncated': 'false',
        'Keys': [{
            'Key': 'test_object',
            'Value': ol_res_val
        }],
        'Marker': '',
        'MaxKeys': '1000',
        'NextMarker': '',
        'Prefix': ''
    }

    index_response = CORTXS3ListIndexResponse(
        json.dumps(index_content).encode())
    object_key = ol_res_val["Object-Name"]
    # oid mismatches in object metadata
    object_metadata = ol_res_val

    kv_response = CORTXS3GetKVResponse(object_key,
                                       json.dumps(object_metadata).encode())

    index_api_mock.list.return_value = True, index_response
    kv_api_mock.get.return_value = True, kv_response
    object_api_mock.delete.return_value = True, {}

    config = CORTXS3Config()
    probable_delete_records = {'Key': 'Tgj8AgAAAAA=-dQAAAAAABCY=', \
        'Value':'{"motr_process_fid":"<0x7200000000000000:0>","create_timestamp":"2020-03-16T16:24:04.000Z", \
        "force_delete":"false","global_instance_id":"TAifBwAAAAA=-AAAAAAAA2lk=","is_multipart":"false", \
        "object_key_in_index":"object_1","object_layout_id":9,"pv_id":"AQAAAAAAAHYKAAAAAAAAAA==","object_list_index_oid":"TAifBwAAAHg=-AQAAAAAA2lk=", \
        "objects_version_list_index_oid":"TAifBwAAAHg=-AwAAAAAA2lk=","old_oid":"AAAAAAAAAAA=-AAAAAAAAAAA=", \
        "version_key_in_index":"object_1/18446742489333709430"}\n'                                                                  }
    validator = ObjectRecoveryValidator(config,
                                        probable_delete_records,
                                        objectapi=object_api_mock,
                                        kvapi=kv_api_mock,
                                        indexapi=index_api_mock)

    #Mock 'process_probable_delete_record'
    validator.process_probable_delete_record = MagicMock(return_value=True)
    validator.check_instance_is_nonactive = MagicMock(return_value=False)

    validator.process_results()

    # Assert following:
    kv_api_mock.assert_called_once
    validator.process_probable_delete_record.assert_called == False