datasrc_configurator.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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 <set>
  21. /// \brief A class to configure the authoritative server's data source lists
  22. ///
  23. /// This will hook into the data_sources module configuration and it will
  24. /// keep the local copy of data source clients in the list in the authoritative
  25. /// server.
  26. ///
  27. /// The class is slightly unusual. Due to some technical limitations, the hook
  28. /// needs to be static method. Therefore it is not possible to create instances
  29. /// of the class.
  30. ///
  31. /// Also, the class is a template. This is simply because of easier testing.
  32. /// You don't need to pay attention to it, use the DataSourceConfigurator
  33. /// type alias instead.
  34. template<class Server, class List>
  35. class DataSourceConfiguratorGeneric {
  36. private:
  37. /// \brief Disallow creation of instances
  38. DataSourceConfiguratorGeneric();
  39. /// \brief Internal method to hook into the ModuleCCSession
  40. ///
  41. /// It simply calls reconfigure.
  42. static void reconfigureInternal(const std::string&,
  43. isc::data::ConstElementPtr config,
  44. const isc::config::ConfigData&)
  45. {
  46. if (config->contains("classes")) {
  47. reconfigure(config->get("classes"));
  48. }
  49. }
  50. static Server* server_;
  51. static isc::config::ModuleCCSession* session_;
  52. typedef boost::shared_ptr<List> ListPtr;
  53. public:
  54. /// \brief Initializes the class.
  55. ///
  56. /// This configures which session and server should be used.
  57. /// It hooks to the session now and downloads the configuration.
  58. /// It is synchronous (it may block for some time).
  59. ///
  60. /// Note that you need to call cleanup before the server or
  61. /// session dies, otherwise it might access them after they
  62. /// are destroyed.
  63. ///
  64. /// \param session The session to hook into and to access the configuration
  65. /// through.
  66. /// \param server It is the server to configure.
  67. /// \throw isc::InvalidOperation if this is called when already initialized.
  68. /// \throw isc::InvalidParameter if any of the parameters is NULL
  69. /// \throw isc::config::ModuleCCError if the remote configuration is not
  70. /// available for some reason.
  71. static void init(isc::config::ModuleCCSession *session,
  72. Server *server)
  73. {
  74. if (session == NULL) {
  75. isc_throw(isc::InvalidParameter, "The session must not be NULL");
  76. }
  77. if (server == NULL) {
  78. isc_throw(isc::InvalidParameter, "The server must not be NULL");
  79. }
  80. if (server_ != NULL) {
  81. isc_throw(isc::InvalidOperation,
  82. "The configurator is already initialized");
  83. }
  84. server_ = server;
  85. session_ = session;
  86. session->addRemoteConfig("data_sources", reconfigureInternal, false);
  87. }
  88. /// \brief Deinitializes the class.
  89. ///
  90. /// This detaches from the session and removes the server from internal
  91. /// storage. The current configuration in the server is preserved.
  92. ///
  93. /// This can be called even if it is not initialized currently. You
  94. /// can initialize it again after this.
  95. static void cleanup() {
  96. if (session_ != NULL) {
  97. session_->removeRemoteConfig("data_sources");
  98. }
  99. session_ = NULL;
  100. server_ = NULL;
  101. }
  102. /// \brief Reads new configuration and replaces the old one.
  103. ///
  104. /// It instructs the server to replace the lists with new ones as needed.
  105. /// You don't need to call it directly (but you could, though the benefit
  106. /// is unknown and it would be questionable at least). It is called
  107. /// automatically on normal updates.
  108. ///
  109. /// \param config The configuration value to parse. It is in the form
  110. /// as an update from the config manager.
  111. /// \throw InvalidOperation if it is called when not initialized.
  112. static void reconfigure(const isc::data::ConstElementPtr& config) {
  113. if (server_ == NULL) {
  114. isc_throw(isc::InvalidOperation,
  115. "Can't reconfigure while not initialized by init()");
  116. }
  117. typedef std::map<std::string, isc::data::ConstElementPtr> Map;
  118. typedef std::pair<isc::dns::RRClass, ListPtr> RollbackPair;
  119. typedef std::pair<isc::dns::RRClass, isc::data::ConstElementPtr>
  120. RollbackConfiguration;
  121. // Some structures to be able to perform a rollback
  122. std::vector<RollbackPair> rollback_sets;
  123. std::vector<RollbackConfiguration> rollback_configurations;
  124. try {
  125. // Get the configuration and current state.
  126. const Map& map(config->mapValue());
  127. const std::vector<isc::dns::RRClass>
  128. activeVector(server_->getClientListClasses());
  129. std::set<isc::dns::RRClass> active(activeVector.begin(),
  130. activeVector.end());
  131. // Go through the configuration and change everything.
  132. for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
  133. isc::dns::RRClass rrclass(it->first);
  134. active.erase(rrclass);
  135. ListPtr list(server_->getClientList(rrclass));
  136. bool need_set(false);
  137. if (list) {
  138. rollback_configurations.
  139. push_back(RollbackConfiguration(rrclass,
  140. list->getConfiguration()));
  141. } else {
  142. list.reset(new List(rrclass));
  143. need_set = true;
  144. rollback_sets.push_back(RollbackPair(rrclass, ListPtr()));
  145. }
  146. list->configure(it->second, true);
  147. if (need_set) {
  148. server_->setClientList(rrclass, list);
  149. }
  150. }
  151. // Remove the ones that are not in the configuration.
  152. for (std::set<isc::dns::RRClass>::iterator it(active.begin());
  153. it != active.end(); ++it) {
  154. // There seems to be no way the setClientList could throw.
  155. // But this is just to make sure in case it did to restore
  156. // the original.
  157. rollback_sets.push_back(
  158. RollbackPair(*it, server_->getClientList(*it)));
  159. server_->setClientList(*it, ListPtr());
  160. }
  161. } catch (...) {
  162. // Perform a rollback of the changes. The old configuration should
  163. // work.
  164. for (typename std::vector<RollbackPair>::const_iterator
  165. it(rollback_sets.begin()); it != rollback_sets.end(); ++it) {
  166. server_->setClientList(it->first, it->second);
  167. }
  168. for (typename std::vector<RollbackConfiguration>::const_iterator
  169. it(rollback_configurations.begin());
  170. it != rollback_configurations.end(); ++it) {
  171. server_->getClientList(it->first)->configure(it->second, true);
  172. }
  173. throw;
  174. }
  175. }
  176. /// \brief Version of reconfigure for easier testing.
  177. ///
  178. /// This method can be used to reconfigure a server without first
  179. /// initializing the configurator. This does not need a session.
  180. /// Otherwise, it acts the same as reconfigure.
  181. ///
  182. /// This is not meant for production code. Do not use there.
  183. ///
  184. /// \param server The server to configure.
  185. /// \param config The config to use.
  186. /// \throw isc::InvalidOperation if the configurator is initialized.
  187. /// \throw anything that reconfigure does.
  188. static void testReconfigure(Server* server,
  189. const isc::data::ConstElementPtr& config)
  190. {
  191. if (server_ != NULL) {
  192. isc_throw(isc::InvalidOperation, "Currently initialized.");
  193. }
  194. try {
  195. server_ = server;
  196. reconfigure(config);
  197. server_ = NULL;
  198. } catch (...) {
  199. server_ = NULL;
  200. throw;
  201. }
  202. }
  203. };
  204. template<class Server, class List>
  205. isc::config::ModuleCCSession*
  206. DataSourceConfiguratorGeneric<Server, List>::session_(NULL);
  207. template<class Server, class List>
  208. Server* DataSourceConfiguratorGeneric<Server, List>::server_(NULL);
  209. /// \brief Concrete version of DataSourceConfiguratorGeneric for the
  210. /// use in authoritative server.
  211. typedef DataSourceConfiguratorGeneric<AuthSrv,
  212. isc::datasrc::ConfigurableClientList>
  213. DataSourceConfigurator;
  214. #endif