Commit 2c5fff22 authored by Adrian Rossouw's avatar Adrian Rossouw

more refactoring. strip mining bind implementation.

parent 2aa3eae7
......@@ -22,163 +22,19 @@ class provisionService_dns_bind extends provisionService_dns_complex {
function init() {
parent::init();
$this->configs['server'][] = 'provisionConfig_bind_server';
$this->configs['zone'][] = 'provisionConfig_bind_zone';
}
/**
* Restart the server to pick up the new configuration files.
*/
function commit() {
// the restart_cmd stuff is part of the base server class now.
function parse_configs() {
$this->restart();
}
function create_zone($zonename) {
$zone = $this->zone_singleton($zonename);
if (!$zone->exists()) {
drush_log("creating zone");
//$zone->add_line_if_not_exists($zone->zone_declaration(), '/zone\s*"'. $zonename . '"/');
$zone->store->records[$zonename] = array('name' => $zonename);
}
return parent::create_zone($zonename);
}
function delete_zone($zonename) {
$zone = $this->zone_singleton($zonename);
if (!$zone->count_records(null, array('NS', 'SOA'))) {
$zone->delete_file();
}
}
function add_record($zonename, $name, $type, $destination) {
drush_log("add: $zonename, $name, $type, $destination");
$zone = $this->zone_singleton($zonename);
if ($type == 'SOA') { // only one SOA per file
foreach ($zone->records as $record) {
if ($record['type'] == 'SOA') {
$record['destination'] = $destination;
}
}
drush_log(dt("not adding a duplicate SOA record, just changing destination"), 'warning');
} else {
$zone->records[] = array('name' => $name, 'type' => $type, 'destination' => $destination);
}
return $zone->write();
}
function edit_record($zonename, $name, $type, $destination = NULL) {
drush_log("edit: $zonename, $name, $type, $destination");
$zone = $this->zone_singleton($zonename);
$found = FALSE;
foreach ($zone->records as $key => $record) {
if ($record['name'] == $name && $record['type'] == $type) {
if ($found) {
unset($zone->records[$key]);
} else {
$record['destination'] = $destination;
$found = TRUE;
}
}
}
if (!$found) {
$this->add_record($zonename, $name, $type, $destination);
}
return $zone->write();
}
function delete_record($zonename, $name, $type = null, $destination = null) {
$zone = $this->zone_singleton($zonename);
drush_log("del: $zonename, $name, $type, $destination");
foreach ($zone->records as $key => $record) {
if ($record['name'] == $name) {
if ( ( is_null($type) || strtoupper($record['type']) == strtoupper($type))
&& ( is_null($destination) || strtoupper($record['destination']) == strtoupper($destination)) ) {
unset($zone->records[$key]);
}
}
}
return $zone->write();
}
function zone_exists($zonename) {
$zone = $this->zone_singleton($zonename);
return $zone->exists();
}
function count_records($zonename, $include = null, $exclude = null) {
$zone = $this->zone_singleton($zonename);
return $zone->count_records($include, $exclude);
}
public function &zone_singleton($zonename) {
if (!$this->zone_cache[$zonename]) {
if ($this->context->type == 'site') {
$this->context = '@server_master';
drush_log("overriding server context");
}
$this->zone_cache[$zonename] = new provisionConfig_bind_zone($this->context, array('name' => $zonename));
}
return $this->zone_cache[$zonename];
}
}
class provisionConfig_bind_zone extends provisionConfig {
public $template = 'zone.tpl.php';
public $records = array();
function parse() {
$file = $this->filename();
$body = file_get_contents($file);
if ($body === FALSE) {
drush_log("no zonefile fonud in " . $file);;
return array();
}
$matches = array();
if ($this->record_count = preg_match_all('/^((?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.?)*|@)?\s*IN\s+(\w+)\s+(.*)\s*$/im', $body, $matches, PREG_SET_ORDER)) {
drush_log(dt("parsed zonefile %file, found %count records", array('%file' => $file, '%count' => $this->record_count)));
} else {
drush_log(dt("could not parse existing zonefile %file", array('%file' => $file)));
}
$SOA = FALSE;
foreach ($matches as $match) {
$name = trim($match[1]);
$type = strtoupper(trim($match[2]));
$destination = trim($match[3]);
switch ($type) {
case 'SOA':
$SOA = TRUE;
default:
drush_log("found record: $name:$type:$destination");
$this->records[] = array('name' => $name, 'type' => $type, 'destination' => $destination);
break;
}
}
if (!$SOA) {
drush_log("no SOA found in zonefile $file, body: ($body)", "warning");
}
return $this->records;
}
class provisionConfig_bind_zone extends provisionConfig_dns_zone {
function filename() {
return $this->dns_zoned_path . '/' . $this->data['name'];
}
function exists() {
if (!$this->filename()) {
drush_log("filename null??");
return FALSE;
}
return provision_file()->exists($this->filename())->status();
}
/**
* This returns the number of records in the zone.
*/
function count_records($include = null, $exclude = null) {
return TRUE;
}
static function parse_soa_data($destination) {
if (preg_match('/([\w.]+)\s+([\w.]+)\s+\(([^)]*)\)/', $destination, $matches)) {
......@@ -255,6 +111,4 @@ class provisionConfig_bind_zone extends provisionConfig {
}
class provisionConfig_bind_server extends provisionConfig_dns_server {
function zone_declaration() {
}
}
......@@ -3,3 +3,12 @@
; Changes here may be lost by user configurations, tread carefully
$TTL <?php print $ttl; ?>
<?php
print("@ IN SOA $soa[name] $soa[email]
$soa[serial] ; serial
$soa[refresh] ; refresh
$soa[retry] ; retry
$soa[expire] ; expire
$soa[minimum] ; minimum
)\n");
?>
......@@ -7,22 +7,9 @@
* Provision hooks for the delete command
**/
/**
* Implementation of hook_provision_delete()
*
* delete the RR for this site at least, but possibly also the zone itself?
* need to lookup the zid for the base zone of this site, and then call dns_rr with the zid and site 'name'
* (ie: pull off the tld and second-level domain for the 'base' zone, and treat the rest as the 'name')
*/
function drush_dns_provision_delete($url = NULL) {
if (d()->type == 'site') {
d()->service('dns')->delete_config('zone');
d()->service('dns')->delete_config('host');
}
}
function drush_dns_post_provision_delete() {
if (d()->type == 'site') {
d()->service('dns')->delete_host();
d()->service('dns')->parse_configs();
}
}
......@@ -88,6 +88,20 @@ class provisionConfig_dns_zone extends provisionConfig_dns {
return "{$this->data['server']->dns_zoned_path}/{$this->data['name']}.zone";
}
function process() {
parent::process();
$records = $this->store->merged_records();
foreach ($records as $key => $record) {
if (preg_match('/^host:/', $key)) {
$this->data['hosts'][$record['host']] = $record;
}
else {
$this->data[$key] = $record;
}
}
}
function write() {
// lock the store until we are done generating our config.
$this->store->lock();
......@@ -106,7 +120,9 @@ class provisionConfig_dns_host extends provisionConfig_dns {
public $description = 'Host-wide DNS configuration';
function filename() {
return "{$this->data['server']->dns_hostd_path}/{$this->uri}.hosts";
$ret = "{$this->data['server']->dns_hostd_path}/{$this->uri}.hosts";
dlm($ret);
return $ret;
}
}
......
......@@ -92,6 +92,32 @@ class provisionService_dns_basic extends provisionService_dns {
$this->server->setProperty('dns_negativettl', 86400); # 24h
}
/**
* Helper function to increment a zone's serial number.
*
* @param $serial
* A serial in YYYYMMDDnn format. If null, a new serial based on
* the date will be generated.
*
* @return
* The serial, incremented based on current date and index
*/
function increment_serial($serial = null) {
$date = substr($serial, 0, 8); # Get the YYYYMMDD part
$today = date('Ymd');
if (is_null($serial) || $date != $today) {
return $today . '00';
} else {
$index = substr($serial, 8, 2); # Get the index part
if ($index >= 99) {
drush_set_error("serial number overflow");
} else {
$index++;
}
return $date . sprintf('%02d', $index);
}
}
function verify() {
if ($this->context->type === 'server') {
provision_file()->create_dir($this->server->dns_data_path, dt("DNS data store"), 0700);
......@@ -130,47 +156,6 @@ class provisionService_dns_basic extends provisionService_dns {
return $data;
}
/**
* This creates a zone, which mostly consists of adding the SOA record.
*/
function create_zone($zone) {
$this->config('server')->record_set($zone, $zone)->write();
$this->config('zone', $zone)->
record_set('soa', array(
'name' => $this->server->remote_host,
))->write();
}
/**
* This completely drops a zone, without any checks.
*/
function delete_zone($zone) {
$this->config('server')->record_del($zone)->write();
}
}
class provisionService_dns_complex extends provisionService_dns_basic {
/**
* Determine if a zone is defined on the nameserver.
*
* To be implemented by engines.
*
* @return if the zone exists
*/
function zone_exists($zone) {
return FALSE;
}
/**
* This returns the number of records in the zone.
*/
function count_records($zone, $include = null, $exclude = null) {
return FALSE;
}
/**
* Guess in which zone we should create the record
......@@ -184,19 +169,21 @@ class provisionService_dns_complex extends provisionService_dns_basic {
*/
function guess_zone($host) {
$tld = $host;
$zones = $this->config('server')->record_get();
$parts = explode(".", $host);
$subdomain = array();
$found = FALSE;
while (!$found && (count($parts) > 2)) {
$tld = join(".", $parts);
if ($this->zone_exists($tld)) {
if (isset($zones[$tld])) {
$found = TRUE;
} else {
$scrap = array_shift($parts);
$subdomain[] = $scrap;
drush_log("zone $tld not found, ditching $scrap, count: " . count($parts));
$found = FALSE;
}
}
}
// this is necessary if we hit the limit of two subdomains
$tld = join(".", $parts);
......@@ -209,58 +196,40 @@ class provisionService_dns_complex extends provisionService_dns_basic {
}
/**
* Helper function to increment a zone's serial number.
*
* @param $serial
* A serial in YYYYMMDDnn format. If null, a new serial based on
* the date will be generated.
*
* @return
* The serial, incremented based on current date and index
* This creates a zone, which mostly consists of adding the SOA record.
*/
function increment_serial($serial = null) {
$date = substr($serial, 0, 8); # Get the YYYYMMDD part
$today = date('Ymd');
if (is_null($serial) || $date != $today) {
return $today . '00';
} else {
$index = substr($serial, 8, 2); # Get the index part
if ($index >= 99) {
drush_set_error("serial number overflow");
} else {
$index++;
}
return $date . sprintf('%02d', $index);
function create_zone($zone = null) {
if (is_null($zone) && $this->context->type == 'site') {
$guess = $this->guess_zone($this->context->uri);
$zone = $guess[1];
}
}
/**
* This adds a (potentially) duplicate record (RR) in a zonefile
*
* This doesn't check if the record already exists, it just adds it
* to the end of the file.
*/
function add_record($zonename, $name, $type, $destination) {
return FALSE;
}
if (!$zone) {
return drush_set_error('DRUSH_DNS_NO_ZONE', "Could not determine the zone to create");
}
/**
* This creates or replaces a record (RR) in a zonefile.
*/
function edit_record($zonename, $name, $type, $destination) {
return FALSE;
$this->config('server')->record_set($zone, $zone)->write();
$soa = $this->config('zone', $zone)->record_get('soa');
$soa['ttl'] = $this->server->dns_ttl;
$soa['name'] = $this->server->remote_host;
$soa['serial'] = $this->increment_serial($soa['serial']);
$soa['refresh'] = $this->server->dns_refresh;
$soa['retry'] = $this->server->dns_retry;
$soa['expire'] = $this->server->dns_expire;
$soa['minimum'] = $this->server->dns_negativettl;
$this->config('zone', $zone)->record_set('soa', $soa)->write();
}
/**
* This removes a record matching the name and destination.
*
* If destination or type is null, they are disregarded in the pattern.
* This completely drops a zone, without any checks.
*/
function delete_record($zonename, $name, $type, $destination = null) {
return FALSE;
function delete_zone($zone) {
$this->config('server')->record_del($zone)->write();
}
/**
/**
* Create a host in DNS.
*
* This can do a lot of things, create a zonefile, add a record to a
......@@ -274,29 +243,33 @@ class provisionService_dns_complex extends provisionService_dns_basic {
if (is_null($host)) {
$host = $this->context->uri;
}
$parts = $this->guess_zone($host);
$zone = $parts[1];
$sub = $parts[0];
if (!$this->zone_exists($zone)) {
drush_log("in create_host, zone $zone not found");
$this->create_zone($zone);
}
$ips = d($site)->service('http')->server->ip_addresses;
$ips = $this->context->site_ip_addresses;
if (!$ips && count($ips) < 1) {
drush_log(dt("no IP found for server, trying loopback"));
$ips = '127.0.0.1';
$ips = array('127.0.0.1');
}
if (is_array($ips)) {
drush_log("a bunch of ips defined, deleting existing ones and readding: " . join(",", $ips));
$this->delete_record($zone, $sub, 'A');
foreach ($ips as $ip) {
$this->add_record($zone, $sub, 'A', $ip);
}
} else {
$this->edit_record($zone, $sub, 'A', $ips);
$this->config('zone', $zone)->record_set("host:$host", array(
'sub' => $sub,
'A' => $ips,
'host' => $host,
));
}
$this->create_zone($zone);
$this->create_config('host');
}
/**
* Delete a host from DNS
*
......@@ -310,12 +283,60 @@ class provisionService_dns_complex extends provisionService_dns_basic {
$host = $this->context->uri;
}
$parts = $this->guess_zone($host);
$this->delete_record($parts[1], $parts[0], 'A');
if ($this->count_records($parts[1], null, array('NS', 'SOA'))) {
$this->delete_zone($parts[1]);
}
$zone = $parts[1];
$sub = $parts[0];
// remove the records from the zone store
$this->config('zone', $zone)->
record_del("host:$host");
$this->create_zone($zone);
$this->delete_config('host');
}
}
class provisionService_dns_complex extends provisionService_dns_basic {
/**
* This returns the number of records in the zone.
*/
function count_records($zone, $include = null, $exclude = null) {
return FALSE;
}
/**
* This adds a (potentially) duplicate record (RR) in a zonefile
*
* This doesn't check if the record already exists, it just adds it
* to the end of the file.
*/
function add_record($zonename, $name, $type, $destination) {
return FALSE;
}
/**
* This creates or replaces a record (RR) in a zonefile.
*/
function edit_record($zonename, $name, $type, $destination) {
return FALSE;
}
/**
* This removes a record matching the name and destination.
*
* If destination or type is null, they are disregarded in the pattern.
*/
function delete_record($zonename, $name, $type, $destination = null) {
return FALSE;
}
/**
* Commit changes to the DNS server
*
......
addn-hosts=<?php print "{$dns_hostd_path}/{$name}.hosts"; ?>
<?php
foreach ($hosts as $host => $info) {
print "addn-hosts={$dns_hostd_path}/{$host}.hosts\n";
}
?>
......@@ -7,13 +7,8 @@
* Provision hooks for the install command
**/
function drush_dns_pre_provision_install() {
d()->service('dns')->create_config('zone');
}
function drush_dns_post_provision_install() {
// we create this post-install because we need the ip's to be assigned already.
d()->service('dns')->create_config('host');
d()->service('dns')->parse_configs();
// we create this post-install because we need the ip's to be assigned already.
d()->service('dns')->create_host();
d()->service('dns')->parse_configs();
}
......@@ -7,22 +7,9 @@
* Provision hooks for the verify command
**/
/**
* Implementation of hook_provision_verify
*
* Can't be rolled back.
*/
function drush_dns_provision_verify() {
switch (d()->type) {
case 'site':
d()->service('dns')->create_config('zone');
break;
}
}
function drush_dns_post_provision_verify() {
if (d()->type == 'site') {
d()->service('dns')->create_config('host');
d()->service('dns')->create_host();
d()->service('dns')->parse_configs();
}
}
......@@ -384,6 +384,10 @@ class provisionConfig_data_store extends provisionConfig {
}
}
function merged_records() {
return array_merge($this->loaded_records, $this->records);
}
function process() {
$this->data['records'] = array_filter(array_merge($this->loaded_records, $this->records));
}
......
......@@ -58,6 +58,7 @@ class provisionService extends provisionChainedState {
if (isset($this->config_cache[$this->context->name][$config])) {
$this->_config = $this->config_cache[$this->context->name][$config];
}
return $this;
}
......@@ -65,6 +66,7 @@ class provisionService extends provisionChainedState {
if (is_object($this->_config)) {
$this->_config->unlink();
}
return $this;
}
......@@ -94,6 +96,33 @@ class provisionService extends provisionChainedState {
return $this->record_set($record, null);
}
function record_exists($record) {
if (is_object($this->_config)) {
if (is_object($this->_config->store)) {
return array_key_exists($record, $this->_config->store->merged_records());
}
}
return FALSE;
}
function record_get($key = null, $default = null) {
if (is_object($this->_config)) {
if (is_object($this->_config->store)) {
$records = $this->_config->store->merged_records();
if (is_null($key)) {
return $records;
}
if (isset($records[$key])) {
return $records[$key];
}
}
}
return $default;
}
/**
* Generate a configuration file.
*
......@@ -110,7 +139,7 @@ class provisionService extends provisionChainedState {
* This method will fetch the class to instantiate from the internal
* $this->configs control array.
*/
function delete_config($config) {
function delete_config($config, $data = array()) {
$this->config($config, $data)->unlink();
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment