/* * AuditStorageCommand.actor.cpp * * This source file is part of the FoundationDB open source project * * Copyright 2013-2026 Apple Inc. and the FoundationDB project authors * * 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. */ /* * ============================================================================ * AUDIT STORAGE COMMANDS * ============================================================================ * * This file implements CLI commands for various storage audit operations: * - audit_storage ha : Validate high availability * - audit_storage replica : Validate replica consistency * - audit_storage locationmetadata : Validate location metadata * - audit_storage ssshard : Validate storage server shards * - audit_storage validate_restore : Validate restored backup data * * ============================================================================ * RESTORE VALIDATION (validate_restore) - Quick Reference * ============================================================================ * * USAGE: audit_storage validate_restore * * Validates that restored backup data matches original source data. * * EXAMPLE WORKFLOW: * 1. Backup: fdbbackup start -d file:///backup -z * 2. Stop: fdbbackup discontinue -C * 3. Lock: fdb> lock (save the returned UID) * 4. Restore: fdbrestore start -r file:///backup --add-prefix "\xff\x02/rlog/" * 5. Validate: fdb> audit_storage validate_restore "" "\xff" * 6. Check: fdb> get_audit_status validate_restore id * 7. Unlock: fdb> unlock * 8. Cleanup: fdb> clearrange "\xff\x02/rlog/" "\xff\x02/rlog0" * * NOTE: Steps 2-3 (stop backup and lock) prevent writes during validation, avoiding * false positive audit errors. The --add-prefix parameter in step 4 allows the restore * to run on a non-empty database, enabling validation by comparing restored data * against the source. Both restore and audit use LOCK_AWARE transactions, so they * work on a locked database. * * See fdbserver/storageserver.actor.cpp for detailed implementation docs. * ============================================================================ */ #include "fdbcli/fdbcli.actor.h" #include "fdbclient/IClientApi.h" #include "fdbclient/ManagementAPI.actor.h" #include "fdbclient/Audit.h" #include "flow/Arena.h" #include "flow/FastRef.h" #include "flow/ThreadHelper.actor.h" #include "flow/actorcompiler.h" // This must be the last #include. namespace fdb_cli { ACTOR Future auditStorageCommandActor(Reference clusterFile, std::vector tokens) { if (tokens.size() < 2) { printUsage(tokens[0]); return UID(); } state UID resAuditId; if (tokencmp(tokens[1], "cancel")) { if (tokens.size() != 4) { printUsage(tokens[0]); return UID(); } AuditType type = AuditType::Invalid; if (tokencmp(tokens[2], "ha")) { type = AuditType::ValidateHA; } else if (tokencmp(tokens[2], "replica")) { type = AuditType::ValidateReplica; } else if (tokencmp(tokens[2], "locationmetadata")) { type = AuditType::ValidateLocationMetadata; } else if (tokencmp(tokens[2], "ssshard")) { type = AuditType::ValidateStorageServerShard; } else if (tokencmp(tokens[2], "validate_restore")) { type = AuditType::ValidateRestore; } else { printUsage(tokens[0]); return UID(); } const UID auditId = UID::fromString(tokens[3].toString()); UID cancelledAuditId = wait(cancelAuditStorage(clusterFile, type, auditId, /*timeoutSeconds=*/60)); resAuditId = cancelledAuditId; } else { AuditType type = AuditType::Invalid; if (tokencmp(tokens[1], "ha")) { type = AuditType::ValidateHA; } else if (tokencmp(tokens[1], "replica")) { type = AuditType::ValidateReplica; } else if (tokencmp(tokens[1], "locationmetadata")) { type = AuditType::ValidateLocationMetadata; } else if (tokencmp(tokens[1], "ssshard")) { type = AuditType::ValidateStorageServerShard; } else if (tokencmp(tokens[1], "validate_restore")) { type = AuditType::ValidateRestore; } else { printUsage(tokens[0]); return UID(); } Key begin = allKeys.begin, end = allKeys.end; if (tokens.size() == 3) { begin = tokens[2]; } else if (tokens.size() == 4 || tokens.size() == 5) { begin = tokens[2]; end = tokens[3]; } else { printUsage(tokens[0]); return UID(); } if (end > allKeys.end) { printUsage(tokens[0]); return UID(); } if (begin >= end) { printUsage(tokens[0]); return UID(); } KeyValueStoreType engineType = KeyValueStoreType::END; if (tokens.size() == 5 && (type == AuditType::ValidateHA || type == AuditType::ValidateReplica)) { engineType = KeyValueStoreType::fromString(tokens[4].toString()); if (engineType != KeyValueStoreType::SSD_BTREE_V2 && engineType != KeyValueStoreType::SSD_ROCKSDB_V1 && engineType != KeyValueStoreType::SSD_SHARDED_ROCKSDB) { printUsage(tokens[0]); return UID(); } } // For KeyValueStoreType::END: do not specify any storage engine // Every storage engine will be audited UID startedAuditId = wait(auditStorage(clusterFile, KeyRangeRef(begin, end), type, engineType, /*timeoutSeconds=*/60)); resAuditId = startedAuditId; } return resAuditId; } CommandFactory auditStorageFactory( "audit_storage", CommandHelp("audit_storage [BeginKey EndKey] ", "Start an audit storage", "Specify audit `Type' (only `ha' and `replica' and `locationmetadata' and " "`ssshard' and `validate_restore' `Type' are supported currently), and\n" "optionally a sub-range with `BeginKey' and `EndKey'.\n" "Specify audit `EngineType' when auditType is `ha' or `replica'\n" "(only `ssd-rocksdb-v1' and `ssd-sharded-rocksdb' and `ssd-2' are supported).\n" "If no EngineType is specified, every storage engine will be audited.\n" "For example, to audit the full key range: `audit_storage ha'\n" "To audit a sub-range only: `audit_storage ha \\xa \\xb'\n" "Returns an audit `ID'. See also `get_audit_status' command.\n" "Note that BeginKey should not equal to EndKey and EndKey is at most \\xff.\n" "To cancel an audit: audit_storage cancel [ID]")); } // namespace fdb_cli