Commit 72471e28 authored by Adrian Rossouw's avatar Adrian Rossouw

Merge branch 'dev-services'

parents 3dc48810 a62e7e39
......@@ -4,3 +4,4 @@ projects[] = "drupal"
projects[hostmaster][type] = "profile"
projects[hostmaster][download][type] = "git"
projects[hostmaster][download][url] = "git://git.aegirproject.org/hostmaster.git"
projects[hostmaster][download][branch] = "dev-services"
<?php
function drush_db_pre_provision_backup() {
d()->service('db')->generate_dump();
}
function drush_db_pre_provision_backup_rollback() {
d()->service('file')->unlink(d()->root . '/sites/' . d()->uri . '/database.sql')
->succeed('Deleted mysql dump from sites directory')
->fail('Could not delete mysql dump from sites directory');
}
function drush_db_post_provision_backup() {
drush_db_pre_provision_backup_rollback();
}
<?php
// $Id$
function drush_db_provision_clone_validate() {
d()->service('db')->connect();
}
This diff is collapsed.
<?php
function drush_provision_mysql_provision_delete_validate() {
if (PROVISION_CONTEXT_SITE) {
provision_db_connect();
function drush_db_provision_delete_validate() {
if (d()->type === 'site') {
d()->service('db')->connect();
}
}
......@@ -12,8 +11,8 @@ function drush_provision_mysql_provision_delete_validate() {
*
* This will drop the database, revoke the privileges and flush the privileges.
*/
function drush_provision_mysql_provision_delete($url = NULL) {
if (PROVISION_CONTEXT_SITE) {
return _provision_mysql_destroy_site_db(drush_get_option('db_name'), drush_get_option('db_user'), drush_get_option('db_passwd'));
function drush_db_provision_delete() {
if (d()->type === 'site') {
d()->service('db')->destroy_site_database();
}
}
<?php
function drush_db_provision_deploy_validate() {
d()->service('db')->connect();
}
function drush_db_provision_deploy() {
d()->service('db')->create_site_database();
d()->service('db')->import_site_database();
}
function drush_db_provision_deploy_rollback() {
d()->service('db')->destroy_site_database();
}
// Rollback doesn't apply here yet. Unless we trigger a deploy of the first dump
// made. Which could go on infinitely if something is really long.
function drush_db_post_provision_deploy() {
d()->service('file')->unlink(d()->root . '/sites/' . d()->uri . '/database.sql')
->succeed('Removed dump file @path after restoring from it')
->fail('Could not remove dump file @path', 'DRUSH_PERM_ERROR');
}
<?php
function drush_db_provision_install_validate() {
d()->service('db')->connect();
}
function drush_db_pre_provision_install() {
d()->service('db')->create_site_database();
}
function drush_db_pre_provision_install_rollback() {
if (!_provision_drupal_site_installed()) {
d()->service('db')->destroy_site_database();
}
}
<?php
// $Id$
function drush_db_provision_migrate_validate() {
d()->service('db')->connect();
}
// Deletes the old database credentials
function drush_db_post_provision_migrate() {
d()->service('db')->destroy_site_database();
}
<?php
// $Id$
// extends the pdo implementation
class provisionService_db_mysql extends provisionService_db_pdo {
public $PDO_type = 'mysql';
function database_exists($name) {
$result = $this->query("SHOW DATABASES LIKE '%s'", $name);
if ($result) {
return $result->fetchColumn(0);
}
}
function drop_database($name) {
return $this->query("DROP DATABASE `%s`", $name);
}
function create_database($name) {
return $this->query("CREATE DATABASE `%s`", $name);
}
function can_create_database() {
$test = drush_get_option('aegir_db_prefix', 'site_') .'test';
$this->create_database($test);
if ($this->database_exists($test)) {
if (!$this->drop_database($test)) {
drush_log(dt("Failed to drop database @dbname", array('@dbname' => $test)), 'warning');
}
return TRUE;
}
return FALSE;
}
function grant($name, $username, $password, $host = '') {
$host = ($host) ? $host : '%';
return $this->query("GRANT ALL PRIVILEGES ON `%s`.* TO `%s`@`%s` IDENTIFIED BY '%s'", $name, $username, $host, $password);
}
function revoke($name, $username, $host = '') {
$host = ($host) ? $host : '%';
$success = $this->query("REVOKE ALL PRIVILEGES ON `%s`.* FROM `%s`@`%s`", $name, $username, $host);
// check if there are any privileges left for the user
$grants = $this->query("SHOW GRANTS FOR `%s`@`%s`", $username, $host);
$grant_found = FALSE;
if ($grants) {
while ($grant = $grants->fetch()) {
// those are empty grants: just the user line
if (!preg_match("/^GRANT USAGE ON /", array_pop($grant))) {
// real grant, we shouldn't remove the user
$grant_found = TRUE;
break;
}
}
}
if (!$grant_found) {
$success = $this->query("DROP USER `%s`@`%s`", $username, $host) && $success;
}
return $success;
}
function import_dump($dump_file, $creds) {
extract($creds);
$cmd = sprintf("mysql --defaults-file=/dev/fd/3 %s", escapeshellcmd($db_name));
$success = $this->safe_shell_exec($cmd, $db_host, $db_user, $db_passwd, $dump_file);
drush_log(sprintf("Importing database using command: %s", $cmd));
if (!$success) {
drush_set_error('PROVISION_DB_IMPORT_FAILED', dt("Database import failed: %output", array('%output' => $output)));
}
}
function grant_host(provisionServer $server) {
$server->shell_exec('mysql -u intntnllyInvalid -h ' . escapeshellarg($this->remote_host));
if (preg_match("/Access denied for user 'intntnllyInvalid'@'([^']*)'/", implode('', drush_shell_exec_output()), $match)) {
return $match[1];
}
else {
return drush_set_error('PROVISION_DB_CONNECT_FAIL', dt('Dummy connection failed to fail: %msg', array('%msg' => join("\n", drush_shell_exec_output()))));
}
}
function generate_dump() {
// Aet the umask to 077 so that the dump itself is generated so it's
// non-readable by the webserver.
umask(0077);
// Mixed copy-paste of drush_shell_exec and provision_shell_exec.
$cmd = sprintf("mysqldump --defaults-file=/dev/fd/3 -r%s/sites/%s/database.sql %s", escapeshellcmd(d($this->context)->root), escapeshellcmd(d($this->context)->uri), escapeshellcmd(drush_get_option('db_name')));
$success = $this->safe_shell_exec($cmd, drush_get_option('db_host'), urldecode(drush_get_option('db_user')), urldecode(drush_get_option('db_passwd')));
if (!$success && !drush_get_option('force', false)) {
drush_set_error('PROVISION_BACKUP_FAILED', dt("Could not generate database backup from mysqldump"));
}
// Reset the umask to normal permissions.
umask(0022);
}
function safe_shell_exec($cmd, $db_host, $db_user, $db_passwd, $dump_file = null) {
# we go through all this trouble to hide the password from the commandline, it's the most secure way (apart from writing a temporary file, which would create conflicts in parallel runs)
$mycnf = sprintf('[client]
host=%s
user=%s
password=%s
', $db_host, $db_user, $db_passwd);
$stdin_spec = (!is_null($dump_file)) ? array("file", $dump_file, "r") : array("pipe", "r");
$descriptorspec = array(
0 => $stdin_spec,
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w"), // stderr is a file to write to
3 => array("pipe", "r"), // fd3 is our special file descriptor where we pass credentials
);
$process = proc_open($cmd, $descriptorspec, $pipes);
$output = "";
if (is_resource($process)) {
fwrite($pipes[3], $mycnf);
fclose($pipes[3]);
$output = stream_get_contents($pipes[1]) . stream_get_contents($pipes[2]);
// "It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock"
fclose($pipes[1]);
fclose($pipes[2]);
$return_value = proc_close($process);
} else {
// XXX: failed to execute? unsure when this happens
$return_value = -1;
}
return ($return_value == 0);
}
}
<?php
function drush_provision_mysql_provision_restore_validate() {
provision_db_connect();
function drush_db_provision_restore_validate() {
d()->service('db')->connect();
}
function drush_provision_mysql_pre_provision_restore($url = NULL) {
$db_type = drush_set_option('db_type', drush_get_option('db_type'));
$db_host = drush_set_option('db_host', drush_get_option('db_host'));
$db_passwd = drush_set_option('db_passwd', provision_password());
$db_name = drush_set_option('db_name', _provision_mysql_suggest_db_name($url));
$db_user = drush_set_option('db_user', $db_name);
function drush_db_pre_provision_restore() {
drush_set_option('old_db_creds', d()->service('db')->fetch_site_credentials());
_provision_mysql_new_site_db($db_name, $db_user, $db_passwd);
d()->service('db')->create_site_database();
}
function drush_provision_mysql_provision_restore($url) {
_provision_mysql_import_dump(
drush_get_option('sites_path') .'/'. $url .'/database.sql',
drush_get_option('db_name'), drush_get_option('db_user'),
drush_get_option('db_passwd'), drush_get_option('db_host')
);
function drush_db_provision_restore() {
d()->service('db')->import_site_database(d()->root . '/sites/' . d()->uri . '.restore/database.sql');
}
function drush_provision_mysql_pre_provision_restore_rollback($url = NULL) {
_provision_mysql_destroy_site_db(drush_get_option('db_name'), drush_get_option('db_user'), drush_get_option('db_passwd'));
function drush_db_pre_provision_restore_rollback() {
d()->service('db')->destroy_site_database();
$keys = array('db_name', 'db_passwd', 'db_user', 'db_host');
......@@ -39,21 +31,14 @@ function drush_provision_mysql_pre_provision_restore_rollback($url = NULL) {
// Rollback doesn't apply here yet. Unless we trigger a restore of the first dump
// made. Which could go on infinitely if something is really long.
function drush_provision_mysql_post_provision_restore($url = NULL) {
provision_path('unlink', drush_get_option('sites_path') . '/' . $url .'/database.sql', TRUE,
dt("Removed dump file @path after restoring from it"),
dt("Could not remove dump file @path"), 'DRUSH_PERM_ERROR');
function drush_db_post_provision_restore() {
d()->service('file')->unlink(d()->root . '/sites/' . d()->uri . '/database.sql')
->succeed('Removed dump file @path after restoring from it')
->fail('Could not remove dump file @path', 'DRUSH_PERM_ERROR');
$db_grant_host = _provision_mysql_grant_host(
drush_get_option('db_host', '', 'site'),
drush_get_option('web_ip', null, 'site'),
drush_get_option('web_host', null, 'site'));
// We have now completed successfully, remove the old database.
_provision_mysql_destroy_site_db(
drush_get_option('db_name', null, 'site'),
drush_get_option('db_user', null, 'site'),
drush_get_option('db_passwd', null, 'site'),
$db_grant_host);
d()->service('db')->destroy_site_database(drush_get_option('old_db_creds'));
// TODO - test this .. it's probably horribly broken .. deleting the newly restored db instead of the old one.
// The new database credentials will be saved against the site now.
drush_set_option('db_name', drush_get_option('db_name'), 'site');
......
<?php
function drush_provision_mysql_pre_provision_backup($url = NULL) {
# set the umask to 077 so that the dump itself is generated so it's non-readable by the webserver
umask(0077);
drush_log("Generating mysql dump for $url.", 'backup');
# mixed copy-paste of drush_shell_exec and provision_shell_exec
$cmd = sprintf("mysqldump --defaults-file=/dev/fd/3 -rsites/%s/database.sql %s", escapeshellcmd($url), escapeshellcmd(drush_get_option('db_name')));
drush_log($cmd);
if (drush_get_context('DRUSH_VERBOSE') || drush_get_context('DRUSH_SIMULATE')) {
drush_print('Executing: ' . $cmd, $indent);
}
if (drush_get_context('DRUSH_SIMULATE')) {
return true;
}
# pipe handling code
# we go through all this trouble to hide the password from the commandline, it's the most secure way (apart from writing a temporary file, which would create conflicts in parallel runs)
$mycnf = sprintf('[client]
host=%s
user=%s
password=%s
', drush_get_option('db_host'), urldecode(drush_get_option('db_user')), urldecode(drush_get_option('db_passwd')));
$descriptorspec = array(
// 0 => array("pipe", "r"), // this would be stdin, but we don't need to input into mysqldump
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w"), // stderr is a file to write to
3 => array("pipe", "r"), // fd3 is our special file descriptor where we pass credentials
);
$process = proc_open($cmd, $descriptorspec, $pipes);
$output = array();
if (is_resource($process)) {
fwrite($pipes[3], $mycnf);
fclose($pipes[3]);
$output = array_filter(array_merge(explode("\n", stream_get_contents($pipes[1])), explode("\n", stream_get_contents($pipes[2]))));
// "It is important that you close any pipes before calling
// proc_close in order to avoid a deadlock"
fclose($pipes[1]);
fclose($pipes[2]);
$return_value = proc_close($process);
} else {
// XXX: failed to execute? unsure when this happens
$return_value = -1;
}
# resuming drush_exec copy/paste
$indent = 0;
_drush_shell_exec_output_set($output);
if (drush_get_context('DRUSH_VERBOSE')) {
foreach ($output as $line) {
drush_print($line, $indent + 2);
}
}
$result = ($return_value == 0);
if (!$result && !drush_get_option('force', false)) {
drush_set_error('PROVISION_BACKUP_FAILED', dt("Could not generate database backup from mysqldump"));
}
# reset the umask to normal permissions
umask(0022);
}
function drush_provision_mysql_pre_provision_backup_rollback($url = NULL) {
provision_path("unlink", drush_get_option('sites_path') . "/$url/database.sql", TRUE, dt("Deleted mysql dump from sites directory"),
dt("Could not delete mysql dump from sites directory"));
}
function drush_provision_mysql_post_provision_backup($url = NULL) {
drush_provision_mysql_pre_provision_backup_rollback($url);
}
<?php
// $Id$
function drush_provision_mysql_provision_clone_validate() {
provision_db_connect();
}
<?php
function drush_provision_mysql_provision_deploy_validate() {
provision_db_connect();
}
function drush_provision_mysql_provision_deploy($url) {
$db_type = drush_get_option('db_type');
// As of Drupal 7 there is no more mysqli type
if (drush_drupal_major_version() >= 7) {
$db_type = ($db_type == 'mysqli') ? 'mysql' : $db_type;
}
$db_type = drush_set_option('db_type', $db_type, 'site');
$db_host = drush_set_option('db_host', drush_get_option('db_host'), 'site');
$db_passwd = drush_set_option('db_passwd', provision_password(), 'site');
$db_name = drush_set_option('db_name', _provision_mysql_suggest_db_name($url), 'site');
$db_user = drush_set_option('db_user', $db_name, 'site');
_provision_mysql_new_site_db($db_name, $db_user, $db_passwd);
_provision_mysql_import_dump(
drush_get_option('sites_path') .'/'. $url .'/database.sql',
$db_name, $db_user, $db_passwd, $db_host );
}
function drush_provision_mysql_provision_deploy_rollback($url = NULL) {
_provision_mysql_destroy_site_db(drush_get_option('db_name'), drush_get_option('db_user'), drush_get_option('db_passwd'));
}
// Rollback doesn't apply here yet. Unless we trigger a deploy of the first dump
// made. Which could go on infinitely if something is really long.
function drush_provision_mysql_post_provision_deploy($url = NULL) {
provision_path('unlink', drush_get_option('sites_path') .'/'. $url .'/database.sql', TRUE,
dt("Removed dump file @path after restoring from it"),
dt("Could not remove dump file @path"), 'DRUSH_PERM_ERROR');
}
<?php
function drush_provision_mysql_provision_install_validate() {
provision_db_connect();
}
function drush_provision_mysql_pre_provision_install($url = NULL) {
$db_type = drush_get_option('db_type');
// As of Drupal 7 there is no more mysqli type
if (drush_drupal_major_version() >= 7) {
$db_type = ($db_type == 'mysqli') ? 'mysql' : $db_type;
}
$db_type = drush_set_option('db_type', $db_type, 'site');
$db_host = drush_set_option('db_host', drush_get_option('db_host'), 'site');
$db_passwd = drush_set_option('db_passwd', provision_password(), 'site');
$db_name = drush_set_option('db_name', _provision_mysql_suggest_db_name($url), 'site');
$db_user = drush_set_option('db_user', $db_name, 'site');
_provision_mysql_new_site_db($db_name, $db_user, $db_passwd);
}
function drush_provision_mysql_pre_provision_install_rollback($url = NULL) {
if (!_provision_drupal_site_installed($url)) {
_provision_mysql_destroy_site_db(drush_get_option('db_name'), drush_get_option('db_user'), drush_get_option('db_passwd'));
}
}
<?php
// $Id$
function drush_provision_mysql_provision_migrate_validate() {
provision_db_connect();
}
// Deletes the old database credentials
function drush_provision_mysql_post_provision_migrate($url) {
return _provision_mysql_destroy_site_db(drush_get_option('db_name'), drush_get_option('db_user'), drush_get_option('db_passwd'));
}
<?php
// $Id$
/**
* @file mysql db api extension
*
* A collection of helper functions used by the main provision hooks to accomplish their tasks.
*/
function _provision_db_connection($conn = NULL) {
static $connection = NULL;
if (!is_null($conn)) {
$connection = $conn;
}
return $connection;
}
function provision_db_connect() {
if (_provision_db_connection()) {
return TRUE;
}
$connection = @mysql_connect(drush_get_option('master_db_host'), drush_get_option('master_db_user'), drush_get_option('master_db_passwd'));
if (!$connection) {
drush_set_error('PROVISION_MASTER_DB_FAILED', dt('Could not connect to the master database server (%err).', array('%err' => mysql_error())), 'error');
}
else {
_provision_db_connection($connection);
}
return TRUE;
}
function provision_db_query($query) {
$args = func_get_args();
array_shift($args);
if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax
$args = $args[0];
}
_provision_db_query_callback($args, TRUE);
$query = preg_replace_callback(PROVISION_QUERY_REGEXP, '_provision_db_query_callback', $query);
return _provision_db_query($query);
}
/**
* Helper function for db_query().
*/
function _provision_db_query($query, $debug = 0) {
$result = mysql_query($query, _provision_db_connection());
if (!mysql_errno(_provision_db_connection())) {
return $result;
}
else {
drush_log( mysql_error(_provision_db_connection()) ."\nquery: ". $query, 'error');
return FALSE;
}
}
function provision_db_result($result, $row = 0) {
if ($result && mysql_num_rows($result) > $row) {
return mysql_result($result, $row);
}
return FALSE;
}
/**
* Fetch one row from the result set
*
* @see db_fetch_array
*/
function provision_db_fetch_array($result) {
if ($result) {
return mysql_fetch_array($result, MYSQL_ASSOC);
}
return $result;
}
/**
* Indicates the place holders that should be replaced in _db_query_callback().
*/
define('PROVISION_QUERY_REGEXP', '/(%d|%s|%%|%f|%b)/');
function _provision_db_query_callback($match, $init = FALSE) {
static $args = NULL;
if ($init) {
$args = $match;
return;
}
switch ($match[1]) {
case '%d': // We must use type casting to int to convert FALSE/NULL/(TRUE?)
return (int) array_shift($args); // We don't need db_escape_string as numbers are db-safe
case '%s':
return mysql_real_escape_string(array_shift($args), _provision_db_connection());
case '%%':
return '%';
case '%f':
return (float) array_shift($args);
case '%b': // binary data
return "'" . mysql_real_escape_string(array_shift($args), _provision_db_connection()) . "'";
}
}
function provision_db_close() {
if (_provision_db_connection()) {
$conn = _provision_db_connection();
mysql_close($conn);
}
}
This diff is collapsed.
name = Provision: Mysql
description = Provides provisioning requirements for the Mysql database
package = Provision
dependencies[] = provision
core = 6.x
\ No newline at end of file
<?php
function drush_provision_mysql_provision_verify_validate() {
provision_db_connect();
}
/**
* Implementation of hook_provision_verify
*
* Can't be rolled back.
*/
function drush_provision_mysql_provision_verify() {
if (PROVISION_CONTEXT_PLATFORM) {
if (!_provision_mysql_can_create_database()) {
drush_set_error('PROVISION_CREATE_DB_FAILED');
}
else {
drush_log(dt('Mysql can create new databases.'), 'message');
}
}
}
function drush_provision_mysql_post_provision_verify() {
if (PROVISION_CONTEXT_PLATFORM) {
drush_set_option('master_db', drush_get_option('master_db'), 'drupal');
}
}
This diff is collapsed.
<?php
class provisionService_file_local extends provisionService_file {
}