dns.php

  1. 7.x-3.x dns/Provision/Service/dns.php
  2. 7.x-3.x dns/Provision/Config/Dns.php

The base Provision DNS service.

Classes

File

dns/Provision/Service/dns.php
View source
  1. <?php
  2. /**
  3. * @file
  4. * The base Provision DNS service.
  5. */
  6. class Provision_Service_dns extends Provision_Service {
  7. public $service = 'dns';
  8. public $slave = NULL;
  9. /**
  10. * Helper function to increment a zone's serial number.
  11. *
  12. * @param $serial
  13. * A serial in YYYYMMDDnn format. If NULL, a new serial based on
  14. * the date will be generated.
  15. *
  16. * @return
  17. * The serial, incremented based on current date and index
  18. */
  19. static public function increment_serial($serial = NULL) {
  20. $today = date('Ymd');
  21. if (is_null($serial)) {
  22. return $today . '00';
  23. }
  24. $date = substr($serial, 0, 8); # Get the YYYYMMDD part
  25. if ($date != $today) {
  26. return $today . '00';
  27. }
  28. else {
  29. $index = substr($serial, 8, 2); # Get the index part
  30. if ($index >= 99) {
  31. drush_set_error("serial number overflow");
  32. }
  33. else {
  34. $index++;
  35. }
  36. return $date . sprintf('%02d', $index);
  37. }
  38. }
  39. function parse_configs() {
  40. return $this->_each_server("parse_configs");
  41. }
  42. function init_server() {
  43. parent::init_server();
  44. // Path for storing data store config files.
  45. $this->server->dns_data_path = $this->server->aegir_root . '/config/dns.d';
  46. if (!is_null($this->application_name)) {
  47. $app_dir = "{$this->server->config_path}/{$this->application_name}";
  48. $this->server->dns_app_path = $app_dir;
  49. $this->server->dns_zoned_path = "{$app_dir}/zone.d";
  50. $this->server->dns_hostd_path = "{$app_dir}/host.d";
  51. }
  52. $this->server->setProperty('slave_servers', array());
  53. $this->server->setProperty('dns_default_mx', NULL); # XXX: until we get full zone management
  54. $this->server->setProperty('dns_ttl', 86400); # 24h
  55. $this->server->setProperty('dns_refresh', 21600); # 6h
  56. $this->server->setProperty('dns_retry', 3600); # 1h
  57. $this->server->setProperty('dns_expire', 604800); # 7d
  58. $this->server->setProperty('dns_negativettl', 86400); # 24h
  59. }
  60. function init_site() {
  61. parent::init_site();
  62. $this->context->setProperty('dns_zone', NULL);
  63. if (is_null($this->context->dns_zone)) {
  64. $this->context->dns_zone = $this->guess_zone($this->context->uri);
  65. }
  66. $this->context->dns_zone_subdomain = trim(str_replace($this->context->dns_zone, '', $this->context->uri), '.');
  67. }
  68. /**
  69. * Run a method on each slave server
  70. *
  71. * This function does a logical AND on the return status of each of the
  72. * methods, and returns TRUE only if they all returned something that
  73. * can be interpreted as TRUE.
  74. *
  75. * @todo this is a duplicate of the cluster function of the same name, they
  76. * need to be merged, but then the cluster_web_server parameter need to be
  77. * renamed...
  78. *
  79. * @see Provision_Service_http_cluster::_each_server()
  80. */
  81. function _each_server($method, $args = array()) {
  82. // Return True by default.
  83. $ret = TRUE;
  84. foreach ($this->server->slave_servers as $server) {
  85. // If any methods return false, return false for the whole operation.
  86. $result = call_user_func_array(array(d($server)->service($this->service, $this->context), $method), $args);
  87. $ret = $ret && $result;
  88. }
  89. return $ret;
  90. }
  91. function verify_server_cmd() {
  92. provision_file()->create_dir($this->server->dns_data_path, dt("DNS data store"), 0700);
  93. if (!is_null($this->application_name)) {
  94. // Ensure that the base DNS configuration folder is at least permissive
  95. // for users other than the owner, sub folders and files can further
  96. // restrict access normally.
  97. provision_file()->create_dir($this->server->dns_app_path, dt("DNS pre-configuration"), 0711);
  98. provision_file()->create_dir($this->server->dns_zoned_path, dt("DNS zone configuration"), 0755);
  99. $this->sync($this->server->dns_zoned_path, array(
  100. 'exclude' => $this->server->dns_zoned_path . '/*', // Make sure remote directory is created
  101. ));
  102. provision_file()->create_dir($this->server->dns_hostd_path , dt("DNS host configuration"), 0755);
  103. $this->sync($this->server->dns_hostd_path, array(
  104. 'exclude' => $this->server->dns_hostd_path . '/*', // Make sure remote directory is created
  105. ));
  106. // TODO: create a slave zone path too.
  107. $this->create_config('server');
  108. }
  109. }
  110. function config_data($config = NULL, $class = NULL) {
  111. $data = parent::config_data($config, $class);
  112. if (!is_null($this->application_name)) {
  113. $data['dns_data_path'] = $this->server->dns_zoned_path;
  114. $data['dns_zoned_path'] = $this->server->dns_zoned_path;
  115. $data['dns_hostd_path'] = $this->server->dns_hostd_path;
  116. }
  117. if ($config == 'host') {
  118. // get the IP explicitely allocate to this site
  119. $ips = drush_get_option('ip_address', array(), 'site');
  120. // .. or the server IPs if none is allocated
  121. if (count($ips) < 1) {
  122. $ips = $this->server->ip_addresses;
  123. }
  124. $data['ip_address'] = $ips;
  125. }
  126. return $data;
  127. }
  128. /**
  129. * Guess in which zone we should create the record
  130. *
  131. * This function will examine the existing zones to find to which
  132. * this host belongs to.
  133. *
  134. * @param $host the name of the record to add (e.g. www.example.com)
  135. *
  136. * @returns array the record and zone name to add the record to (e.g. www and example.com)
  137. */
  138. function guess_zone($host, $return = 'tld') {
  139. static $zone_cache;
  140. if (!isset($zone_cache[$host])) {
  141. $tld = $host;
  142. $zones = $this->config('server')->record_get();
  143. $parts = explode(".", $host);
  144. $subdomain = array();
  145. $found = FALSE;
  146. while (!$found && (count($parts) > 2)) {
  147. $tld = join(".", $parts);
  148. if (isset($zones[$tld])) {
  149. $found = TRUE;
  150. }
  151. else {
  152. $scrap = array_shift($parts);
  153. $subdomain[] = $scrap;
  154. drush_log("zone $tld not found, ditching $scrap, count: " . count($parts));
  155. $found = FALSE;
  156. }
  157. }
  158. // this is necessary if we hit the limit of two subdomains
  159. $tld = join(".", $parts);
  160. $subdomain = join(".", $subdomain);
  161. $zone_cache[$host] = array('tld' => $tld, 'subdomain' => $subdomain);
  162. }
  163. else {
  164. $tld = $zone_cache[$host]['tld'];
  165. $subdomain = $zone_cache[$host]['subdomain'];
  166. }
  167. drush_log("guess_zone guessed parts $tld, $subdomain");
  168. if ($return == 'subdomain') {
  169. if (empty($subdomain)) {
  170. return '@';
  171. }
  172. else {
  173. return $subdomain;
  174. }
  175. }
  176. return $tld;
  177. }
  178. /**
  179. * This creates a zone, which mostly consists of adding the SOA record.
  180. */
  181. function create_zone($zone = NULL) {
  182. if (is_null($zone) && ($this->context->type == 'site')) {
  183. $host = $this->context->uri;
  184. $zone = $this->context->dns_zone;
  185. $sub = $this->context->dns_zone_subdomain;
  186. }
  187. if (empty($zone)) {
  188. return drush_set_error('DRUSH_DNS_NO_ZONE', "Could not determine the zone to create");
  189. }
  190. drush_log(dt("creating zone %zone", array("%zone" => $zone)));
  191. $status = $this->config('zone', $zone)->write();
  192. if ($status) {
  193. drush_log(dt("recording zone in server configuration"));
  194. $status = $this->config('server')->record_set($zone, $zone)->write();
  195. }
  196. if ($status) {
  197. drush_log(dt("creating zone configuration on slaves"));
  198. $status = $this->_each_server("create_zone", array($zone));
  199. }
  200. return $status;
  201. }
  202. /**
  203. * This completely drops a zone, without any checks.
  204. */
  205. function delete_zone($zone) {
  206. $status = $this->config('zone', $zone)->unlink();
  207. $status = $status && $this->config('server')->record_del($zone, $zone)->write();
  208. if ($status) {
  209. drush_log(dt("deleting zone configuration from slaves"));
  210. $status = $this->_each_server("delete_zone", array($zone));
  211. }
  212. return $status;
  213. }
  214. /**
  215. * Create a host in DNS.
  216. *
  217. * This can do a lot of things, create a zonefile, add a record to a
  218. * zonefile, it's going to make its best guess doing the Right
  219. * Thing.
  220. *
  221. * @arg $host string the hostname to create. If NULL, we look in the
  222. * current context (should be a site) for a URI.
  223. */
  224. function create_host($host = NULL) {
  225. if (!is_null($host)) {
  226. $zone = $this->guess_zone($host);
  227. $sub = $this->guess_zone($host, 'subdomain');
  228. $aliases = array();
  229. }
  230. elseif ($this->context->type == 'site') {
  231. $host = $this->context->uri;
  232. $zone = $this->context->dns_zone;
  233. $sub = $this->context->dns_zone_subdomain;
  234. $aliases = $this->context->aliases;
  235. }
  236. else {
  237. return drush_set_error('DRUSH_DNS_NO_ZONE', "Could not determine the zone to create");
  238. }
  239. $ips = drush_get_option('ip_address', array(), 'site');
  240. if (!$ips && count($ips) < 1) {
  241. drush_log(dt("no IP found for server, trying loopback"));
  242. $ips = array('127.0.0.1');
  243. }
  244. $this->config('zone', $zone)->record_set($sub, array('A' => $ips));
  245. foreach ($aliases as $alias) {
  246. if ($this->guess_zone($alias) == $zone) {
  247. $this->config('zone', $zone)->record_set($this->guess_zone($alias, 'subdomain'),
  248. array('CNAME' => array($zone . '.')));
  249. }
  250. }
  251. $this->create_zone($zone);
  252. }
  253. /**
  254. * Delete a host from DNS
  255. *
  256. * Similar to create host, this will seek and destroy that host throughout zonefiles.
  257. *
  258. * @arg $host string the hostname to create. If NULL, we look in the
  259. * current context (should be a site) for a URI.
  260. */
  261. function delete_host($host = NULL) {
  262. if (!is_null($host)) {
  263. $zone = $this->guess_zone($host);
  264. $sub = $this->guess_zone($host, 'subdomain');
  265. $aliases = array();
  266. }
  267. elseif ($this->context->type == 'site') {
  268. $host = $this->context->uri;
  269. $zone = $this->context->dns_zone;
  270. $sub = $this->context->dns_zone_subdomain;
  271. $aliases = $this->context->aliases;
  272. }
  273. else {
  274. return drush_set_error('DRUSH_DNS_NO_ZONE', "Could not determine the zone to create");
  275. }
  276. // remove the records from the zone store
  277. $this->config('zone', $zone)->record_set($sub, array('A' => NULL));
  278. foreach ($aliases as $alias) {
  279. if ( $this->guess_zone($alias) == $zone) {
  280. $this->config('zone', $zone)->record_set($this->guess_zone($alias, 'subdomain'),
  281. array('CNAME' => NULL));
  282. }
  283. }
  284. $this->config('zone', $zone)->write();
  285. }
  286. }