datasrc_configurator.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef DATASRC_CONFIGURATOR_H
  15. #define DATASRC_CONFIGURATOR_H
  16. #include "auth_srv.h"
  17. #include <datasrc/client_list.h>
  18. #include <config/ccsession.h>
  19. #include <cc/data.h>
  20. #include <util/threads/lock.h>
  21. #include <set>
  22. /// \brief A class to configure the authoritative server's data source lists
  23. ///
  24. /// This will hook into the data_sources module configuration and it will
  25. /// keep the local copy of data source clients in the list in the authoritative
  26. /// server.
  27. ///
  28. /// The class is slightly unusual. Due to some technical limitations, the hook
  29. /// needs to be static method. Therefore it is not possible to create instances
  30. /// of the class.
  31. ///
  32. /// Also, the class is a template. This is simply because of easier testing.
  33. /// You don't need to pay attention to it, use the DataSourceConfigurator
  34. /// type alias instead.
  35. template<class Server, class List>
  36. class DataSourceConfiguratorGeneric {
  37. private:
  38. /// \brief Disallow creation of instances
  39. DataSourceConfiguratorGeneric();
  40. /// \brief Internal method to hook into the ModuleCCSession
  41. ///
  42. /// It simply calls reconfigure.
  43. static void reconfigureInternal(const std::string&,
  44. isc::data::ConstElementPtr config,
  45. const isc::config::ConfigData&)
  46. {
  47. if (config->contains("classes")) {
  48. reconfigure(config->get("classes"));
  49. }
  50. }
  51. static Server* server_;
  52. static isc::config::ModuleCCSession* session_;
  53. typedef boost::shared_ptr<List> ListPtr;
  54. public:
  55. /// \brief Initializes the class.
  56. ///
  57. /// This configures which session and server should be used.
  58. /// It hooks to the session now and downloads the configuration.
  59. /// It is synchronous (it may block for some time).
  60. ///
  61. /// Note that you need to call cleanup before the server or
  62. /// session dies, otherwise it might access them after they
  63. /// are destroyed.
  64. ///
  65. /// \param session The session to hook into and to access the configuration
  66. /// through.
  67. /// \param server It is the server to configure.
  68. /// \throw isc::InvalidOperation if this is called when already initialized.
  69. /// \throw isc::InvalidParameter if any of the parameters is NULL
  70. /// \throw isc::config::ModuleCCError if the remote configuration is not
  71. /// available for some reason.
  72. static void init(isc::config::ModuleCCSession* session,
  73. Server* server)
  74. {
  75. if (session == NULL) {
  76. isc_throw(isc::InvalidParameter, "The session must not be NULL");
  77. }
  78. if (server == NULL) {
  79. isc_throw(isc::InvalidParameter, "The server must not be NULL");
  80. }
  81. if (server_ != NULL) {
  82. isc_throw(isc::InvalidOperation,
  83. "The configurator is already initialized");
  84. }
  85. server_ = server;
  86. session_ = session;
  87. session->addRemoteConfig("data_sources", reconfigureInternal, false);
  88. }
  89. /// \brief Deinitializes the class.
  90. ///
  91. /// This detaches from the session and removes the server from internal
  92. /// storage. The current configuration in the server is preserved.
  93. ///
  94. /// This can be called even if it is not initialized currently. You
  95. /// can initialize it again after this.
  96. static void cleanup() {
  97. if (session_ != NULL) {
  98. session_->removeRemoteConfig("data_sources");
  99. }
  100. session_ = NULL;
  101. server_ = NULL;
  102. }
  103. /// \brief Reads new configuration and replaces the old one.
  104. ///
  105. /// It instructs the server to replace the lists with new ones as needed.
  106. /// You don't need to call it directly (but you could, though the benefit
  107. /// is unknown and it would be questionable at least). It is called
  108. /// automatically on normal updates.
  109. ///
  110. /// \param config The configuration value to parse. It is in the form
  111. /// as an update from the config manager.
  112. /// \throw InvalidOperation if it is called when not initialized.
  113. static void reconfigure(const isc::data::ConstElementPtr& config) {
  114. if (server_ == NULL) {
  115. isc_throw(isc::InvalidOperation,
  116. "Can't reconfigure while not initialized by init()");
  117. }
  118. // Lock the client lists, we're going to manipulate them.
  119. isc::util::thread::Mutex::Locker locker(server_->getClientListMutex());
  120. typedef std::map<std::string, isc::data::ConstElementPtr> Map;
  121. typedef std::pair<isc::dns::RRClass, ListPtr> RollbackPair;
  122. typedef std::pair<isc::dns::RRClass, isc::data::ConstElementPtr>
  123. RollbackConfiguration;
  124. // Some structures to be able to perform a rollback
  125. std::vector<RollbackPair> rollback_sets;
  126. std::vector<RollbackConfiguration> rollback_configurations;
  127. try {
  128. // Get the configuration and current state.
  129. const Map& map(config->mapValue());
  130. const std::vector<isc::dns::RRClass>
  131. activeVector(server_->getClientListClasses());
  132. std::set<isc::dns::RRClass> active(activeVector.begin(),
  133. activeVector.end());
  134. // Go through the configuration and change everything.
  135. for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
  136. isc::dns::RRClass rrclass(it->first);
  137. active.erase(rrclass);
  138. ListPtr list(server_->getClientList(rrclass));
  139. bool need_set(false);
  140. if (list) {
  141. rollback_configurations.
  142. push_back(RollbackConfiguration(rrclass,
  143. list->getConfiguration()));
  144. } else {
  145. list.reset(new List(rrclass));
  146. need_set = true;
  147. rollback_sets.push_back(RollbackPair(rrclass, ListPtr()));
  148. }
  149. list->configure(it->second, true);
  150. if (need_set) {
  151. server_->setClientList(rrclass, list);
  152. }
  153. }
  154. // Remove the ones that are not in the configuration.
  155. for (std::set<isc::dns::RRClass>::iterator it(active.begin());
  156. it != active.end(); ++it) {
  157. // There seems to be no way the setClientList could throw.
  158. // But this is just to make sure in case it did to restore
  159. // the original.
  160. rollback_sets.push_back(
  161. RollbackPair(*it, server_->getClientList(*it)));
  162. server_->setClientList(*it, ListPtr());
  163. }
  164. } catch (...) {
  165. // Perform a rollback of the changes. The old configuration should
  166. // work.
  167. for (typename std::vector<RollbackPair>::const_iterator
  168. it(rollback_sets.begin()); it != rollback_sets.end(); ++it) {
  169. server_->setClientList(it->first, it->second);
  170. }
  171. for (typename std::vector<RollbackConfiguration>::const_iterator
  172. it(rollback_configurations.begin());
  173. it != rollback_configurations.end(); ++it) {
  174. server_->getClientList(it->first)->configure(it->second, true);
  175. }
  176. throw;
  177. }
  178. }
  179. /// \brief Version of reconfigure for easier testing.
  180. ///
  181. /// This method can be used to reconfigure a server without first
  182. /// initializing the configurator. This does not need a session.
  183. /// Otherwise, it acts the same as reconfigure.
  184. ///
  185. /// This is not meant for production code. Do not use there.
  186. ///
  187. /// \param server The server to configure.
  188. /// \param config The config to use.
  189. /// \throw isc::InvalidOperation if the configurator is initialized.
  190. /// \throw anything that reconfigure does.
  191. static void testReconfigure(Server* server,
  192. const isc::data::ConstElementPtr& config)
  193. {
  194. if (server_ != NULL) {
  195. isc_throw(isc::InvalidOperation, "Currently initialized.");
  196. }
  197. try {
  198. server_ = server;
  199. reconfigure(config);
  200. server_ = NULL;
  201. } catch (...) {
  202. server_ = NULL;
  203. throw;
  204. }
  205. }
  206. };
  207. template<class Server, class List>
  208. isc::config::ModuleCCSession*
  209. DataSourceConfiguratorGeneric<Server, List>::session_(NULL);
  210. template<class Server, class List>
  211. Server* DataSourceConfiguratorGeneric<Server, List>::server_(NULL);
  212. /// \brief Concrete version of DataSourceConfiguratorGeneric for the
  213. /// use in authoritative server.
  214. typedef DataSourceConfiguratorGeneric<AuthSrv,
  215. isc::datasrc::ConfigurableClientList>
  216. DataSourceConfigurator;
  217. #endif