Commit 0637b032 authored by anarcat's avatar anarcat

Merge remote branch 'origin/dev-ssl-ip-allocation-refactor' into 6.x-2.x

parents 4b9e3166 1c538625
<?php
foreach ($site_ip_addresses as $server => $ip) {
foreach ($ip_addresses as $server => $ip) {
print "{$ip}\t {$this->uri}\n";
}
?>
......@@ -136,7 +136,13 @@ class Provision_Service_dns extends Provision_Service {
}
if ($config == 'host') {
$data['site_ip_addresses'] = drush_get_option('site_ip_addresses', array(), 'site');
// get the IP explicitely allocate to this site
$ips = drush_get_option('ip_address', array(), 'site');
// .. or the server IPs if none is allocated
if (count($ips) < 1) {
$ips = $this->server->ip_addresses;
}
$data['ip_address'] = $ips;
}
return $data;
......@@ -244,7 +250,7 @@ class Provision_Service_dns extends Provision_Service {
return $status;
}
/**
/**
* Create a host in DNS.
*
* This can do a lot of things, create a zonefile, add a record to a
......@@ -270,18 +276,13 @@ class Provision_Service_dns extends Provision_Service {
return drush_set_error('DRUSH_DNS_NO_ZONE', "Could not determine the zone to create");
}
$ips = drush_get_option('site_ip_addresses', array(), 'site');
$ips = drush_get_option('ip_address', array(), 'site');
if (!$ips && count($ips) < 1) {
drush_log(dt("no IP found for server, trying loopback"));
$ips = array('127.0.0.1');
}
// XXX: kill me?
if (!is_array($ips)) {
$ips = array($ips); // backward compatibility?
}
$this->config('zone', $zone)->record_set($sub, array('A' => $ips));
foreach ($aliases as $alias) {
if ($this->guess_zone($alias) == $zone) {
......
......@@ -14,32 +14,6 @@ class Provision_Config_Http_Site extends Provision_Config_Http {
return $this->data['http_vhostd_path'] . '/' . $this->uri;
}
function write() {
parent::write();
// We also leave a record of this IP in the site's drushrc.php
// This way we can pass the info back to the front end.
$ip_addresses = drush_get_option('site_ip_addresses', array(), 'site');
if ($this->data['ip_address'] != '*') {
$ip_addresses[$this->data['server']->name] = $this->data['ip_address'];
}
elseif (isset($context['site_ip_addresses'][$this->data['server']->name])) {
unset($ip_addresses[$this->data['server']->name]);
}
drush_set_option('site_ip_addresses', $ip_addresses, 'site');
}
function unlink() {
parent::unlink();
// We also remove the record of this IP in the site's drushrc.php
// This way we can pass the info back to the front end.
$ip_addresses = drush_get_option('site_ip_addresses', array(), 'site');
unset($ip_addresses[$this->data['server']->name]);
drush_set_option('site_ip_addresses', $ip_addresses, 'site');
}
function process() {
parent::process();
......
......@@ -15,7 +15,6 @@ class Provision_Config_Http_Ssl_Site extends Provision_Config_Http_Site {
function write() {
parent::write();
$ip_addresses = drush_get_option('site_ip_addresses', array(), 'site');
if ($this->ssl_enabled && $this->ssl_key) {
$path = dirname($this->data['ssl_cert']);
// Make sure the ssl.d directory in the server ssl.d exists.
......@@ -26,7 +25,9 @@ class Provision_Config_Http_Ssl_Site extends Provision_Config_Http_Site {
)), 0700);
// Touch a file in the server's copy of this key, so that it knows the key is in use.
touch("{$path}/{$this->uri}.receipt");
// XXX: test. data structure may not be sound. try d($this->uri)
// if $this fails
Provision_Service_http_ssl::assign_certificate_site($this->ssl_key, $this);
// Copy the certificates to the server's ssl.d directory.
provision_file()->copy(
......@@ -49,10 +50,9 @@ class Provision_Config_Http_Ssl_Site extends Provision_Config_Http_Site {
'exclude' => "{$path}/*.receipt", // Don't need to synch the receipts
));
}
elseif ($ip = $ip_addresses[$this->data['server']->name]) {
if ($ssl_key = Provision_Service_http_ssl::get_ip_certificate($ip, $this->data['server'])) {
$this->clear_certs($ssl_key);
}
else {
// XXX: to be tested, not sure the data structure is sound
Provision_Service_http_ssl::free_certificate_site($this->ssl_key, $this);
}
}
......@@ -62,45 +62,18 @@ class Provision_Config_Http_Ssl_Site extends Provision_Config_Http_Site {
function unlink() {
parent::unlink();
$ip_addresses = drush_get_option('site_ip_addresses', array(), 'site');
if ($this->ssl_enabled && $this->ssl_key) {
$this->clear_certs($this->ssl_key);
}
elseif ($ip = $ip_addresses[$this->data['server']->name]) {
if ($ssl_key = Provision_Service_http_ssl::get_ip_certificate($ip, $this->data['server'])) {
$this->clear_certs($ssl_key);
}
}
// XXX: to be tested, not sure the data structure is sound
Provision_Service_http_ssl::free_certificate_site($this->ssl_key, $this);
}
/**
* Small utility function to stop code duplication.
*
* @deprecated unused
* @see Provision_Service_http_ssl::free_certificate_site()
*/
private function clear_certs($ssl_key) {
$path = $this->data['server']->http_ssld_path . "/$ssl_key";
// Remove the file system reciept we left for this file
provision_file()->unlink("{$path}/{$this->uri}.receipt")->
succeed(dt("Deleted SSL Certificate association stub for %site on %server", array(
'%site' => $this->uri,
'%server' => $this->data['server']->remote_host)));
$used = Provision_Service_http_ssl::certificate_in_use($ssl_key, $this->data['server']);
if (!$used) {
// we can remove the certificate from the server ssl.d directory.
_provision_recursive_delete($path);
// remove the file from the remote server too.
$this->data['server']->sync($path);
// Most importantly, we remove the hold this cert had on the IP address.
Provision_Service_http_ssl::free_certificate_ip($ssl_key, $this->data['server']);
}
return FALSE;
}
}
......@@ -38,6 +38,7 @@ class Provision_Service_http_ssl extends Provision_Service_http_public {
$this->context->setProperty('ssl_enabled', 0);
$this->context->setProperty('ssl_key', NULL);
$this->context->setProperty('ip_address', '*');
}
......@@ -55,23 +56,8 @@ class Provision_Service_http_ssl extends Provision_Service_http_public {
if ($ssl_key = $this->context->ssl_key) {
// Retrieve the paths to the cert and key files.
// they are generated if not found.
$certs = $this->get_certificates($ssl_key);
$data = array_merge($data, $certs);
// assign ip address based on ssl_key
$ip = Provision_Service_http_ssl::assign_certificate_ip($ssl_key, $this->server);
if (!$ip) {
drush_set_error("SSL_IP_FAILURE", dt("There are no more IP addresses available on %server for the %ssl_key certificate.", array(
"%server" => $this->server->remote_host,
"%ssl_key" => $ssl_key,
)));
}
else {
$data['ip_address'] = $ip;
}
}
}
......@@ -148,6 +134,51 @@ class Provision_Service_http_ssl extends Provision_Service_http_public {
}
}
/**
* Assign the given site to a certificate to mark its usage.
*
* This is necessary for the backend to figure out when it's okay to
* remove certificates.
*
* Should never fail unless the receipt file cannot be created.
*
* @return the path to the receipt file if allocation succeeded
*/
static function assign_certificate_site($ssl_key, $site) {
$path = $site->platform->server->http_ssld_path . "/" . $ssl_key . "/" . $site->uri . ".receipt";
drush_log(dt("registering site %site with SSL certificate %key with receipt file %path", array("%site" => $site->uri, "%key" => $ssl_key, "%path" => $path)));
if (touch($path)) {
return $path;
}
else {
return FALSE;
}
}
/**
* Unallocate this certificate from that site.
*
* @return the path to the receipt file if removal was successful
*/
static function free_certificate_site($ssl_key, $site) {
$ssl_dir = $site->platform->server->http_ssld_path . "/" . $ssl_key . "/";
// Remove the file system reciept we left for this file
if (provision_file()->unlink($ssl_dir . $site->uri . ".receipt")->
succeed(dt("Deleted SSL Certificate association receipt for %site on %server", array(
'%site' => $site->uri,
'%server' => $site->server->remote_host)))->status()) {
if (!Provision_Service_http_ssl::certificate_in_use($ssl_key, $site->server)) {
drush_log(dt("Deleting unused SSL directory: %dir", array('%dir' => $ssl_dir)));
_provision_recursive_delete($ssl_dir);
$site->server->sync($path);
}
return $path;
}
else {
return FALSE;
}
}
/**
* Assign the certificate it's own distinct IP address for this server.
*
......@@ -156,51 +187,26 @@ class Provision_Service_http_ssl extends Provision_Service_http_public {
*
* This code uses the filesystem by touching a reciept file in the
* server's ssl.d directory.
*
* @deprecated this is now based the site URI
* @see assign_certificate_site()
*/
static function assign_certificate_ip($ssl_key, $server) {
$path = $server->http_ssld_path;
$pattern = "{$path}/{$ssl_key}__*.receipt";
$files = glob($pattern);
if (sizeof($files) == 1) {
$pattern = "/^{$ssl_key}__(.*)\.receipt$/";
preg_match($pattern, basename($files[0]), $matches);
if (in_array($matches[1], $server->ip_addresses)) {
// Return an existing match.
return $matches[1];
}
// This is a stale match, remove it.
// Any sites using it will either find a new
// IP on the next verify task, or fail.
unlink($files[0]);
}
// try to assign one
foreach ($server->ip_addresses as $ip) {
if (!Provision_Service_http_ssl::get_ip_certificate($ip, $server)) {
touch("{$path}/{$ssl_key}__{$ip}.receipt");
return $ip;
}
}
return FALSE; // generate error
return FALSE;
}
/**
* Remove the certificate's lock on the server's public IP.
*
* This function will delete the receipt file left behind by
* the assign_certificate_ip script, allowing the IP to be used
* by other certificates.
*
* @deprecated this is now based on the site URI
* @see free_certificate_site()
*/
static function free_certificate_ip($ssl_key, $server) {
$ip = Provision_Service_http_ssl::assign_certificate_ip($ssl_key, $server);
$file = "{$server->http_ssld_path}/{$ssl_key}__{$ip}.receipt";
if (file_exists($file)) {
unlink($file);
}
return FALSE;
}
......@@ -222,18 +228,10 @@ class Provision_Service_http_ssl extends Provision_Service_http_public {
/**
* Check for an existing record for this IP address.
*
* @deprecated we only use the URI-based allocation now
*/
static function get_ip_certificate($ip, $server) {
$path = $server->http_ssld_path;
$pattern = "{$path}/*__{$ip}.receipt";
$files = glob($pattern);
if (sizeof($files) == 1) {
$pattern = "/^(.*)__{$ip}\.receipt$/";
preg_match($pattern, basename($files[0]), $matches);
return $matches[1];
}
return FALSE;
}
......
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