1 // Copyright (C) 2019-2020 Internet Systems Consortium, Inc. ("ISC") 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, v. 2.0. If a copy of the MPL was not distributed with this 5 // file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 #ifndef AUDIT_ENTRY_H 8 #define AUDIT_ENTRY_H 9 10 #include <boost/date_time/posix_time/posix_time.hpp> 11 #include <boost/multi_index/composite_key.hpp> 12 #include <boost/multi_index_container.hpp> 13 #include <boost/multi_index/hashed_index.hpp> 14 #include <boost/multi_index/mem_fun.hpp> 15 #include <boost/multi_index/ordered_index.hpp> 16 #include <boost/shared_ptr.hpp> 17 #include <cstdint> 18 #include <string> 19 20 namespace isc { 21 namespace db { 22 23 class AuditEntry; 24 25 /// @brief Pointer to the @c AuditEntry object. 26 typedef boost::shared_ptr<AuditEntry> AuditEntryPtr; 27 28 /// @brief Represents a single entry in the audit table. 29 /// 30 /// The audit tables are used in the databases to track incremental 31 /// changes, e.g. configuration changes applied via the configuration 32 /// backend. The backend can query for the entries in the audit table 33 /// to identify the SQL table in which the records were modified, the 34 /// identifiers of the modified objects, type of the modifications, 35 /// time of the modifications and optional log messages associated 36 /// with the modifications. 37 /// 38 /// The server should remember the most recent modification time out of 39 /// all audit entries it has fetched. During the next attempt to fetch 40 /// the most recent modifications in the database it will query for all 41 /// entries with later modification time than stored. That way the 42 /// server queries only for the audit entries it hasn't fetched yet. 43 /// In the case two (or more) successive audit entries have the same 44 /// modification time the strictly increasing modification id is used. 45 /// 46 /// When the modification type of the entry is set to 47 /// @c AuditEntry::ModificationType::DELETE, the corresponding 48 /// configuration entry is already gone from the database. For example: 49 /// when a subnet with ID of 123 is deleted from the dhcp4_subnet 50 /// table, the audit entry similar to this will be stored in the audit 51 /// table: 52 /// 53 /// - object_type: "dhcp4_subnet" 54 /// - object_id: 123 55 /// - modification_type: 3 (DELETE) 56 /// - modification_time: "2019-01-15 15:45:23" 57 /// - revision id: 234 58 /// - log_message: "DHCPv4 subnet 123 deleted" 59 /// 60 /// The subnet is instantly removed from the dhcp4_subnet table. When 61 /// the server finds such entry in the audit table, it removes the 62 /// subnet 123 from its (in-memory) configuration. There is no need 63 /// make additional queries to fetch updated data from the dhcp4_subnet 64 /// table, unless there are also audit entries indicating that some 65 /// new subnets have been added or some subnets have been updated. 66 class AuditEntry { 67 public: 68 69 /// @brief Types of the modifications. 70 /// 71 /// The numbers representing those modification types correspond 72 /// to the values representing them in the database. 73 enum class ModificationType : uint8_t { 74 CREATE = 0, 75 UPDATE = 1, 76 DELETE = 2 77 }; 78 79 /// @brief Constructor using explicit modification time and id. 80 /// 81 /// @param object_type name of the table where data was modified. 82 /// @param object_id identifier of the modified record in this table. 83 /// @param modification_type type of the modification, e.g. DELETE. 84 /// @param modification_time time of modification for that record. 85 /// @param revision_id identifier of the revision. 86 /// @param log_message optional log message associated with the 87 /// modification. 88 AuditEntry(const std::string& object_type, 89 const uint64_t object_id, 90 const ModificationType& modification_type, 91 const boost::posix_time::ptime& modification_time, 92 const uint64_t revision_id, 93 const std::string& log_message); 94 95 /// @brief Constructor using default modification time. 96 /// 97 /// @param object_type name of the table where data was modified. 98 /// @param object_id identifier of the modified record in this table. 99 /// @param modification_type type of the modification, e.g. DELETE. 100 /// @param revision_id identifier of the revision. 101 /// @param log_message optional log message associated with the 102 /// modification. 103 AuditEntry(const std::string& object_type, 104 const uint64_t object_id, 105 const ModificationType& modification_type, 106 const uint64_t revision_id, 107 const std::string& log_message); 108 109 /// @brief Factory function creating an instance of @c AuditEntry. 110 /// 111 /// This function should be used to create an instance of the audit 112 /// entry within a hooks library in cases when the library may be 113 /// unloaded before the object is destroyed. This ensures that the 114 /// ownership of the object by the Kea process is retained. 115 /// 116 /// @param object_type name of the table where data was modified. 117 /// @param object_id identifier of the modified record in this table. 118 /// @param modification_type type of the modification, e.g. DELETE. 119 /// @param modification_time time of modification for that record. 120 /// @param revision_id identifier of the revision. 121 /// @param log_message optional log message associated with the 122 /// modification. 123 /// 124 /// @return Pointer to the @c AuditEntry instance. 125 static AuditEntryPtr create(const std::string& object_type, 126 const uint64_t object_id, 127 const ModificationType& modification_type, 128 const boost::posix_time::ptime& modification_time, 129 const uint64_t revision_id, 130 const std::string& log_message); 131 132 /// @brief Factory function creating an instance of @c AuditEntry. 133 /// 134 /// This function should be used to create an instance of the audit 135 /// entry within a hooks library in cases when the library may be 136 /// unloaded before the object is destroyed. This ensures that the 137 /// ownership of the object by the Kea process is retained. 138 /// 139 /// @param object_type name of the table where data was modified. 140 /// @param object_id identifier of the modified record in this table. 141 /// @param modification_type type of the modification, e.g. DELETE. 142 /// @param revision_id identifier of the revision. 143 /// @param log_message optional log message associated with the 144 /// modification. 145 /// 146 /// @return Pointer to the @c AuditEntry instance. 147 static AuditEntryPtr create(const std::string& object_type, 148 const uint64_t object_id, 149 const ModificationType& modification_type, 150 const uint64_t revision_id, 151 const std::string& log_message); 152 153 /// @brief Returns object type. 154 /// 155 /// @return Name of the table in which the modification is present. getObjectType()156 std::string getObjectType() const { 157 return (object_type_); 158 } 159 160 /// @brief Returns object id. 161 /// 162 /// @return Identifier of the added, updated or deleted object. getObjectId()163 uint64_t getObjectId() const { 164 return (object_id_); 165 } 166 167 /// @brief Returns modification type. 168 /// 169 /// @return Type of the modification, e.g. DELETE. getModificationType()170 ModificationType getModificationType() const { 171 return (modification_type_); 172 } 173 174 /// @brief Returns modification time. 175 /// 176 /// @return Modification time of the corresponding record. getModificationTime()177 boost::posix_time::ptime getModificationTime() const { 178 return (modification_time_); 179 } 180 181 /// @brief Returns revision id. 182 /// 183 /// The revision id is used when two audit entries have the same 184 /// modification time. 185 /// 186 /// @return Identifier of the revision. getRevisionId()187 uint64_t getRevisionId() const { 188 return (revision_id_); 189 } 190 191 /// @brief Returns log message. 192 /// 193 /// @return Optional log message corresponding to the changes. getLogMessage()194 std::string getLogMessage() const { 195 return (log_message_); 196 } 197 198 private: 199 200 /// @brief Validates the values specified for the audit entry. 201 /// 202 /// @throw BadValue if the object type is empty or if the 203 /// modification time is not a date time value. 204 void validate() const; 205 206 /// @brief Object type. 207 std::string object_type_; 208 209 /// @brief Object id. 210 uint64_t object_id_; 211 212 /// @brief Modification type. 213 ModificationType modification_type_; 214 215 /// @brief Modification time. 216 boost::posix_time::ptime modification_time_; 217 218 /// @brief Revision id. 219 /// 220 /// The revision id is used when two audit entries have the same 221 /// modification time. 222 uint64_t revision_id_; 223 224 /// @brief Log message. 225 std::string log_message_; 226 }; 227 228 /// @brief Tag used to access index by object type. 229 struct AuditEntryObjectTypeTag { }; 230 231 /// @brief Tag used to access index by modification time. 232 struct AuditEntryModificationTimeIdTag { }; 233 234 /// @brief Tag used to access index by object id. 235 struct AuditEntryObjectIdTag { }; 236 237 /// @brief Multi index container holding @c AuditEntry instances. 238 /// 239 /// This container provides indexes to access the audit entries 240 /// by object type and modification time. 241 typedef boost::multi_index_container< 242 // The container holds pointers to @c AuditEntry objects. 243 AuditEntryPtr, 244 // First index allows for accessing by the object type. 245 boost::multi_index::indexed_by< 246 boost::multi_index::ordered_non_unique< 247 boost::multi_index::tag<AuditEntryObjectTypeTag>, 248 boost::multi_index::composite_key< 249 AuditEntry, 250 boost::multi_index::const_mem_fun< 251 AuditEntry, 252 std::string, 253 &AuditEntry::getObjectType 254 >, 255 boost::multi_index::const_mem_fun< 256 AuditEntry, 257 AuditEntry::ModificationType, 258 &AuditEntry::getModificationType 259 > 260 > 261 >, 262 263 // Second index allows for accessing by the modification time and id. 264 boost::multi_index::ordered_non_unique< 265 boost::multi_index::tag<AuditEntryModificationTimeIdTag>, 266 boost::multi_index::composite_key< 267 AuditEntry, 268 boost::multi_index::const_mem_fun< 269 AuditEntry, 270 boost::posix_time::ptime, 271 &AuditEntry::getModificationTime 272 >, 273 boost::multi_index::const_mem_fun< 274 AuditEntry, 275 uint64_t, 276 &AuditEntry::getRevisionId 277 > 278 > 279 >, 280 281 // Third index allows for accessing by the object id. 282 boost::multi_index::hashed_non_unique< 283 boost::multi_index::tag<AuditEntryObjectIdTag>, 284 boost::multi_index::const_mem_fun< 285 AuditEntry, 286 uint64_t, 287 &AuditEntry::getObjectId 288 > 289 > 290 > 291 > AuditEntryCollection; 292 293 //// @brief Pointer to the @c AuditEntryCollection object. 294 typedef boost::shared_ptr<AuditEntryCollection> AuditEntryCollectionPtr; 295 296 } // end of namespace isc::db 297 } // end of namespace isc 298 299 #endif 300