Commit 5e736872 authored by anarcat's avatar anarcat Committed by Adrian Rossouw

add new DNS code, still not working right

parent c3875b1e
To test this, drush provision-save @server_alias --dns_service_type=bind
then to call stuff:
d()->service('dns')->METHOD()
anarcat@desktop004.office.koumbit.net.12099:1276609070
\ No newline at end of file
<?php
/**
* Create a new entry for the zone provided in the local named.conf file, pointing to the zonefile.
*
* @param $zone
* The zone object to create an entry for (as returned by dns_status).
**/
function bind_create_zone_config($zone) {
// add the zone to our local named.conf file
$path = drush_get_option('config_path') . '/named/';
$conf = drush_get_option('config_path') . '/named.conf.aegir';
$zone_str = sprintf('zone "%s" { type master; file "%s/%s"; allow-query { any; }; };%s', $zone->origin, $path, $zone->origin, "\n");
if ($fd = fopen($conf, "a")) {
$fd = fwrite($fd, $zone_str);
}
if (!$fd) {
drush_set_error(PROVISION_PERM_ERROR, dt("error adding the zone to the bind configuration in @path", array("@path" => $conf)));
}
@fclose($fd);
}
function bind_delete_zone_config($origin) {
$path = drush_get_option('config_path') . '/named/';
$conf = drush_get_option('config_path') . '/named.conf.aegir';
$zone_re = sprintf('^zone..%s.*$', $zone->origin);
_bind_editline($conf, $zone_re);
}
/**
* Create a zonefile with SOA header plus all other records
*
* @param $zone
* The zone object to create or update
*
* This should use a template, a la:
* $template = variable_get('dns_zonefile_template', _dns_default_template());
* But currently, just writes hardcoded string for all of this stuff directly into the zonefile.
**/
function bind_create_zone($zone) {
// write a zonefile in the appropriate place
$path = drush_get_option('config_path') . '/named/';
# First setup the SOA record
$zone_str = sprintf("\$TTL %s\n", $zone->ttl);
$zone_str .= sprintf("@\t IN\t SOA\t %s. %s. (\n", $zone->origin, str_replace('@', '.', $zone->mbox));
$zone_str .= sprintf("\t\t\t %s ; Serial\n", $zone->serial);
$zone_str .= sprintf("\t\t\t %s ; Refresh\n", $zone->refresh);
$zone_str .= sprintf("\t\t\t %s ; Retry\n", $zone->retry);
$zone_str .= sprintf("\t\t\t %s ; Expire\n", $zone->expire);
$zone_str .= sprintf("\t\t\t %s)\t\t; Negative Cache TTL\n\n", $zone->ttl);
foreach ($zone->records as $rid => $rec) {
$zone_str .= _bind_record_string((object)$rec);
}
bind_create_zone_config($zone); # And re-create the zone in named.conf
drush_log("notice", dt("Creating zonefile @zonefile", array('@zonefile' => $zone->origin)));
$zonefile = $path . '/'. $zone->origin;
if ($fd = fopen($zonefile, "w")) {
$status = fwrite($fd, $zone_str); # Write the zonefile
fclose($fd);
} else {
$status = drush_set_error('PROVISION_PERM_ERROR', dt("Cannot write zonefile @path", array("@path" => $zonefile)));
}
return $status;
}
/**
* Remove the zonefile and named.conf entry for a given zone
*
* @param $zone
* The zone object (as returned by dns_status) to remove.
**/
function bind_delete_zone($zone) {
# Remove the zone from the named.conf file..
$path = drush_get_option('config_path') . '/named/';
# and remove the zonefile itself
$zonefile = $path . '/' . $zone->origin;
if ($status = provision_path("unlink", $zonefile)) {
$status = bind_delete_zone_config($zone->origin);
}
return $status;
}
/**
* Add an RR entry in the given zone's zonefile for the record provided.
*
* @param $zone
* The zone object (as returned by dns_status) in which to add the RR
* @param $record
* The RR object (as returned by dns_status) to add an entry for.
**/
function _bind_add_record($zone, $record) {
$file = drush_get_option('config_path') . '/named/' . $zone->origin;
$line = _bind_record_string($record);
if ($fh = fopen($file, 'a')) {
$status = fwrite($fh, $line);
fclose($fh);
} else {
$status = drush_set_error('PROVISION_PERM_ERROR', dt("Cannot write record to file @path", array("@path" => $file)));
}
return $status;
}
/**
* Update an RR entry in the given zone's zonefile for the record provided.
*
* @param $zone
* The zone object (as returned by dns_status) in which the RR record resides.
* @param $record
* The record object (as returned by dns_status) to update.
**/
function _bind_update_record($zone, $record) {
$file = drush_get_option('config_path') . '/named/' . $zone->origin;
if (!isset($record->old_name)) { $record->old_name = $record->name; }
$line = _bind_record_string($record);
_bind_editline($file, '^'.$record->old_name.'\t.*$', $line);
}
/**
* Remove an RR entry from the given zone.
*
* @param $zone
* The zone object (as returned by dns_status) in which the RR record resides.
* @param $record
* The record object (as returned by dns_status) to delete.
**/
function _bind_delete_record($zone, $record) {
$file = drush_get_option('config_path') . '/named/' . $zone->origin;
$line = _bind_record_string($record);
_bind_editline($file, '^'.$line.'$');
}
/**
* Helper function to restart BIND
**/
function _bind_restart() {
return _bind_reload();
}
function _bind_reload($zone = "") {
// restart bind
$cmd = drush_get_option('bind_rndc', 'sudo /usr/sbin/rndc') . " reload " . $zone;
system($cmd, $status);
return ($status == 0);
}
/**
* Helper function to gather BIND's status (currently unused)
**/
function _bind_status() {
$cmd = "sudo ". drush_get_option('bind_rndc', '/usr/sbin/rndc') . " status > /dev/null";
system($cmd, $status);
return ($status == 0);
}
/**
* Helper function to check a given zone's zonefile (currently unused)
**/
function _bind_namedcheckzone($zone) {
$file = drush_get_option('config_path') . '/named/' . $zone->origin;
$cmd = drush_get_option('bind_namedcheckzone', '/usr/sbin/named-checkzone') ." ". $zone->origin ." ". $path . $zone->origin ." > /dev/null";
system($cmd, $status);
return $status;
}
/**
* Helper function to check the local named.conf
**/
function _bind_namedcheckconf($zone) {
$conf = drush_get_option('config_path') . '/named.conf.aegir';
$cmd = drush_get_option('bind_namedcheckconf', '/usr/sbin/named-checkconf') ." ". $conf ." > /dev/null";
system($cmd, $status);
return $status;
}
/**
* Reads in the given file, locates the 'old' line (regexp), and replaces it with the 'new' one, using preg_replace();
* If $new is empty, simply removes the 'old' line completely.
*
* @param $file
* The file to edit.
* @param $old
* A regexp (without delimiters) which locates the line(s) to be edited
* @param $new
* A replacement string for the $old pattern. If this is empty, the $old pattern will be removed completely.
**/
function _bind_editline($file, $old, $new = '') {
# Read in the file, checking each line and doing a preg_replace on matching lines
if ($fd = fopen($file, 'r')) {
while ($line = fgets($fd)) {
if (preg_match("/$old/", $line)) {
if ($new) {
$lines[] = preg_replace("/$old/", $new, trim($line));
}
} else {
$lines[] = $line;
}
}
fclose($fd);
} else {
drush_set_error('PROVISION_PERM_ERROR');
}
# Write out the changed lines to the original file again.
if (!file_put_contents($file, $lines)) {
drush_set_error('PROVISION_PERM_ERROR');
}
}
/**
* Helper function to generate a RR line from a record object
*
* @param $record
* The record object as returned by dns_status
*
* @return
* A string representing the given record as a line for a zonefile
**/
function _bind_record_string($record) {
if ($record->type == "MX") { $pri = $record->aux; } else { $pri = ""; }
if (( $record->type == "NS" ||
$record->type == "PTR" ||
$record->type == "CNAME" ||
$record->type == "MX" ||
$record->type == "SRV") && ($record-data != "@")
) {
$destination = $record->data .".";
} elseif ($record->type == "TXT") {
$destination = "\"". $record->data ."\"";
} else {
$destination = $record->data;
}
return $record->name ."\t IN\t ". $record->type ."\t". $pri ."\t". $destination ."\n";
}
name = Provision: BIND
description = Provides provisioning requirements for Bind servers
package = Provision
dependencies[] = provision
core = 6.x
<?php
/**
* Implementation of the DNS service through BIND9
*
* A lot of this is inspired by the Apache implementation of the HTTP service.
*/
class provisionService_dns_bind extends provisionService_dns {
static function option_documentation() {
return array_merge(parent::option_documentation(), array(
'--restart_cmd' => 'server with bind: shell command to restart the server; working default will be attepted',
));
}
function init() {
parent::init();
$this->server->bind_conf_path = $this->server->config_path . '/bind.d';
$this->server->bind_zone_master_path = $this->server->config_path . '/zones/master';
$this->server->setProperty('bind_restart_cmd', _bind_default_restart_cmd());
}
function config_data() {
return array(
'bind_conf_path' => $this->server->bind_config_path,
'bind_zone_master_path' => $this->server->bind_zone_master_path
);
}
function create_server_config() {
provision_file()->create_dir($this->server->bind_conf_path, dt("Bind configuration"), 0700);
$this->sync($this->server->bind_conf_path);
$config = new provisionConfig_bind_server($this->context, $this->config_data());
$config->write();
}
function delete_server_config() {
$config = new provisionConfig_bind_server($this->context, $this->config_data());
$config->unlink();
}
function parse_configs() {
// This is required to be configurable, due to the fact that different
// hosts might need to do this differently.
if ($this->server->shell_exec($this->server->bind_restart_cmd)) {
drush_log(dt('Name server on %server has been restarted', array('%server' => $this->server->remote_host)));
}
else {
drush_log(dt('Name server %server could not be restarted. Changes might not be available until this has been done. (error: %msg)', array('%server' => $this->server->remote_host, '%msg' => join("\n", drush_shell_exec_output()))), 'warning');
}
}
function create_zone_config() {
$config = new provisionConfig_bind_master($this->context, $this->config_data() + drush_get_context('zone'));
$config->write();
}
}
// XXX: this is an almost extact copy of provisionConfig_apache, we should probably refactor
class provisionConfig_bind extends provisionConfig {
function write() {
parent::write();
$this->data['server']->sync($this->filename());
}
function unlink() {
parent::unlink();
$this->data['server']->sync($this->filename());
}
}
/**
* Bind server-level configuration file
*
* This file needs to be included in the global bind configuration file, and Aegir will take it from there
*/
class provisionConfig_bind_server extends provisionConfig_bind {
public $template = 'server.tpl.php';
public $description = 'bind server configuration file';
function filename() {
return $this->data['server']->config_path . '/bind.conf';
}
}
/**
* Bind configuration snippet to include the master zonefiles
*/
class provisionConfig_bind_master extends provisionConfig_bind {
public $template = 'master.tpl.php';
public $description = 'bind master configuration file include';
function filename() {
return $this->data['bind_conf_path'] . $this->fqdn;
}
}
<?php
// $Id: delete.provision.inc,v 1.3 2009/05/07 22:04:30 adrian Exp $
/**
* @file
* 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 ($url) {
# dns_delete($url);
}
}
<?php
/**
* copy of frontend's hosting_dns_split_url
*/
function _dns_split_url($url) {
$tlds = split("\n", variable_get('hosting_dns_tlds', ''));
$first_dot = strpos($url, '.');
# Strip off the first part
$host = substr($url, 0, $first_dot);
$zone = substr($url, $first_dot);
# If the remaining hostname is a TLD
if (in_array($zone, $tlds)) {
# Add the first part back, and that's the zone (the host is @)
$zone = $host . $zone;
$host = '@';
} else {
# that's the zone (and the host is the first part)
$zone = substr($zone, 1); # strip the leading .
}
return array('host' => $host, 'zone' => $zone);
}
<?php
// $Id: dns.drush.inc,v 1.4 2009/03/20 16:13:24 adrian Exp $
/**
* @file
* DNS provisioning module.
*
* The goal of this module is to manage DNS zonefiles and Resource Records
* (RRs), for sites that are about to be created. It uses the provision API to
* tie into the right places in the site creation work flow.
*/
/**
* Implementation of hok_drush_command().
*/
function dns_drush_command() {
$items['provision-zone'] = array(
'arguments' => array('operation' => dt('The operation to perform on a zone (verify, delete, rr-add, rr-delete)')),
'description' => dt('Manipulate a zonefile'),
'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
);
return $items;
}
function drush_dns_provision_zone($action, $zone) {
switch ($action) {
case 'verify':
case 'create':
$status = d()->service('dns')->create_zone($zone);
break;
case 'delete':
$status = d()->service('dns')->delete_zone($zone);
break;
case 'rr-add':
case 'rr-delete':
drush_set_error("not implemented");
break;
}
if ($status) {
_bind_reload($zone->origin);
}
}
/**
* Helper function to increment a zone's serial number.
*
* @param $serial
* A serial in YYYYMMDDnn format
*
* @return
* The serial, incremented based on current date and index
*/
function _dns_increment_serial($serial) {
$date = substr($serial, 0, 8); # Get the YYYYMMDD part
$index = substr($serial, 8, 2); # Get the index part
$today = date('Ymd');
if ($date == $today) {
return $date . sprintf('%02d', $index+1);
} else {
return $today . '01';
}
}
function dns_provision_services() {
return array('dns' => NULL);
}
class provisionService_dns extends provisionService {
static function option_documentation() {
return array(
);
}
function init() {
}
function verify() {
return $this->create_server_config();
}
function create_server_config() {
return FALSE;
}
function delete_server_config() {
return FALSE;
}
/**
* Create a host in DNS.
*
* This can do a lot of things, create a zonefile, add a record to a
* zonefile, it's going to make its best guess doing the Right Thing.
*/
function create_host($host) {
return FALSE;
}
/**
* Delete a host from DNS
*
* Similar to create host, this will seek and destroy that host throughout zonefiles.
*/
function delete_host($host) {
return FALSE;
}
/**
* Commit changes to the DNS server
*
* This may involve restarting the server.
*
* @arg $host only reload a single zone. if null, reload all zones
*/
function commit($zone = null) {
return FALSE;
}
}
name = Provision: DNS
description = Provides provisioning requirements for DNS servers
package = Provision
dependencies[] = provision
core = 6.x
<?php
// $Id: install.provision.inc,v 1.7 2009/05/07 22:04:30 adrian Exp $
/**
* @file
* Provision hooks for the install command
**/
function drush_dns_pre_provision_install() {
if (d()->type == 'site') {
d()->service('dns')->create_host(d()->uri);
}
}
function drush_dns_pre_provision_install_rollback() {
if (d()->type == 'site') {
d()->service('dns')->delete_host(d()->uri);
}
}
function drush_dns_post_provision_install() {
if (d()->type == 'site') {
d()->service('dns')->commit();
}
}
<?php
// $Id: restore.provision.inc,v 1.4 2009/05/07 22:04:30 adrian Exp $
/**
* @file
* Provision hooks for the restore command
**/
/**
* Implementation of hook_provision_pre_restore
* This is a duplicate of the _pre_install hook
**/
function drush_dns_pre_provision_restore($url = NULL) {
# re-install the zonefiles and/or resource records for the site?
# _dns_provision_pre_restore($url, $data);
}
/**
* Implementation of hook_provision_pre_restore_rollback
* This duplicates the _pre_install_rollback hook
**/
function drush_dns_pre_provision_restore_rollback($url = NULL) {
# remove them again?
if ($url) {
# _dns_delete($url);
}
}
function drush_dns_post_provision_restore($url = NULL) {
# restart bind?
}
function drush_dns_post_provision_restore_rollback($url = NULL) {
# restart bind
}
<?php
// $Id: verify.provision.inc,v 1.5 2009/03/26 01:40:39 anarcat Exp $
/**
* @file
* Provision hooks for the verify command
**/
include_once("dns.api.inc");
/**
* Implementation of hook_provision_verify
*
* Can't be rolled back.
*/
function drush_dns_provision_verify($url = NULL) {
if (!$url) {
// we are verifying a platform
# Where does this constant come from now?
_provision_create_dir(PROVISION_NAMED_PATH, dt('Provision DNS configuration'), 0755);
# The above perms should really be 750, but that means the aegir user must be in the 'bind' group, so this will work:
provision_path("chgrp", PROVISION_NAMED_PATH, 'bind',
dt('Changed group ownership of '.PROVISION_NAMED_PATH.' to @confirm'),
dt('Could not change group ownership of '.PROVISION_NAMED_PATH.' to @confirm'));
} else {
drush_log("notice", "Hit dns_provision_verify hook: $url");
$url_parts = _dns_split_url($url);
if (!isset($url_parts['zone'])) {
drush_set_error('PROVISION_FRAMEWORK_ERROR');
return;
}
$zone = dns_create_zone($url_parts['zone']); # initializes the zone for the domain (if it doesn't exist)
dns_create_record($url_parts['host'], $zone); # creates the RR for the (sub)domain
dns_commit(drush_get_option('dns_id')); # makes the changes live (ie: restart bind)
drush_log(dt("Edited zone file %zone", array("%zone" => $zone)));
}
}
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