Skip to content

Commit

Permalink
Merge pull request #111 from palantirnet/better-acquia-backups
Browse files Browse the repository at this point in the history
Download one Acquia backup database at a time.
  • Loading branch information
becw authored Nov 20, 2018
2 parents 7afd060 + f772121 commit 83ddcbb
Show file tree
Hide file tree
Showing 6 changed files with 521 additions and 50 deletions.
66 changes: 40 additions & 26 deletions defaults.properties.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,25 +118,24 @@ drupal:
# environment.
services_template: .the-build/drupal.services.build.yml


# Configuration for the database loading utility.
load_db:
# Pattern to match gzipped database dump files.
export_pattern: artifacts/backups/*.sql.gz

# The following two commands are composed to load the database into Drupal:
# $> gunzip -c FILENAME.sql.gz | drush sqlc
#
# Command to extract text contents of the backup file.
contents_command: gunzip -c
# Command to load database contents into Drupal.
mysql_command: drush sqlc

# Load a specific file rather than one matching the `export_pattern`. This can be used
# if your build relies on a seed database that is checked in to the repository.
# Otherwise, you may occasionally want to set this value at run time:
# $> phing load-db -Ddb.load.file=artifacts/foo.sql.gz
#file:
# Configuration for the database loading utility.
load_db:
# Pattern to match gzipped database dump files.
export_pattern: artifacts/backups/*.sql.gz

# The following two commands are composed to load the database into Drupal:
# $> gunzip -c FILENAME.sql.gz | drush sqlc
#
# Command to extract text contents of the backup file.
contents_command: gunzip -c
# Command to load database contents into Drupal.
mysql_command: drush sqlc

# Load a specific file rather than one matching the `export_pattern`. This can be used
# if your build relies on a seed database that is checked in to the repository.
# Otherwise, you may occasionally want to set this value at run time:
# $> phing load-db -Ddb.load.file=artifacts/foo.sql.gz
#file:


# Configuration for tasks/artifact.xml
Expand Down Expand Up @@ -178,16 +177,31 @@ artifact:

# Configuration for tasks/acquia.xml
acquia:
# Directory for storing downloaded database backups.
backups: artifacts/backups

# Machine name of your Acquia site account.
#accountname:
# Max age of the downloaded backup database, in hours.
backup_age_hours: 24

# Acquia SSH host, like `srv-1234.devcloud.hosting.acquia.com` or
# `staging-12345.prod.hosting.acquia.com`
#ssh:
# The Acquia Cloud hosting "realm" where the site is running.
# - Acquia Cloud Enterprise: 'prod'
# - Acquia Cloud Professional: 'devcloud'
realm: ""

# Directory for storing downloaded database backups.
backups: artifacts/backups
# Acquia site/application name.
site: ""

# Acquia database name. This can be left to match the site name unless you're
# using multisites.
database: "${acquia.site}"

# Acquia environment to download backups from.
env: "prod"

# Acquia Cloud API credentials file, downloaded from your Acquia account. Do not check
# this file into your codebase.
cloud:
conf: "${env.HOME}/.acquia/cloudapi.conf"


# Configuration to use the PHP interpreter's built in linter to check for syntax errors
Expand Down
30 changes: 30 additions & 0 deletions docs/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,33 @@ If the `prefix` attribute does not end in a `.`, one will be added.
```xml
<selectpropertykey prefix="drupal.sites." omitKeys="_defaults" propertyName="build.site" message="Select a site to build:" />
```

## Acquia\GetLatestBackupTask [🔗](../src/TheBuild/Acquia/GetLatestBackupTask.php)

Download a recent backup from Acquia Cloud.

### Attributes

| Name | Type | Description | Default | Required |
|---|---|---|---|---|
| dir | directory path | Local backups directory. | | Yes |
| realm | string | Acquia hosting realm, either "devcloud" or "prod". | | Yes |
| site | string | Acquia site name. | | Yes |
| env | string | Acquia environment, generally "dev", "test", or "prod". | | Yes |
| database | string | Acquia database name. | The site name. | No |
| maxAge | int | Maximum age of the backup, in hours. | 24 | No |
| propertyName | string | Name of a property to set to the backup file. | | No |
| credentialsFile | file path | Path to your Acquia Cloud API credentials. (Do not check this file in to your repository) | `~/.acquia/cloudapi.conf` | No |

### Example

```xml
<!-- Provide the <getAcquiaBackup /> task. -->
<taskdef name="getAcquiaBackup" classname="TheBuild\Acquia\GetLatestBackupTask" />

<!-- Required parameters only -->
<getAcquiaBackup dir="artifacts/backups" realm="devcloud" site="mysite" env="prod" />

<!-- More parameters -->
<getAcquiaBackup dir="artifacts/backups" realm="devcloud" site="mysite" env="prod" credentialsFile="artifacts/.acquia/cloudapi.conf" propertyName="drupal.site.load_db.file" />
```
129 changes: 129 additions & 0 deletions src/TheBuild/Acquia/AcquiaTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php
/**
* @file AcquiaTask.php
*
* Abastract base task for creating Acquia Cloud API tasks.
*
* Loads the Acquia Cloud credentials from a JSON file and constructs
* authenticated requests against the Cloud API.
*
* This class will use the credentials file at ~/.acquia/cloudapi.conf if none
* is provided in the task call:
*
* @code
* <exampleTask credentialsFile="artifacts/cloudapi.conf" />
* @endcode
*
* Extending classes may also set the 'endpoint' property if it is necessary to
* use the v2 API instead of v1.
*
* @copyright 2018 Palantir.net, Inc.
*/

namespace TheBuild\Acquia;

use BuildException;
use HTTP_Request2;
use PhingFile;

abstract class AcquiaTask extends \Task {

/**
* Required. The Acquia Cloud credentials file containing a json array with
* 'mail' and 'key' values.
* @var \PhingFile
*/
protected $credentialsFile;

/**
* Email address associated with the Acquia Cloud access. This value is set
* from the credentials file.
* @var string
*/
protected $mail;

/**
* Secure key associated with the Acquia Cloud access. This value is set from
* the credentials file.
* @var string
*/
protected $key;

/**
* The Acquia Cloud API endpoint. This code is specific to version 1 of the
* API.
* @var string
*/
protected $endpoint = 'https://cloudapi.acquia.com/v1';

/**
* Load the Acquia Cloud credentials from the cloudapi.conf JSON file.
*
* @throws \IOException
* @throws \NullPointerException
*/
protected function loadCredentials() {
if (empty($this->mail) || empty($this->key)) {
if (empty($this->credentialsFile)) {
$this->credentialsFile = new PhingFile($_SERVER['HOME'] . '/.acquia/cloudapi.conf');
}

if (!file_exists($this->credentialsFile) || !is_readable($this->credentialsFile)) {
throw new BuildException("Acquia Cloud credentials file '{$this->credentialsFile}' is not available.");
}

$contents = file_get_contents($this->credentialsFile);
$creds = json_decode($contents, TRUE);

$this->mail = $creds['mail'];
$this->key = $creds['key'];
}

if (empty($this->mail) || empty($this->key)) {
throw new BuildException('Missing Acquia Cloud API credentials.');
}
}

/**
* Build an HTTP request object against the Acquia Cloud API.
*
* @param $path
* @return HTTP_Request2
*/
protected function createRequest($path) {
$this->loadCredentials();

$uri = $this->endpoint . '/' . ltrim($path, '/');

$request = new HTTP_Request2($uri);
$request->setConfig('follow_redirects', TRUE);
$request->setAuth($this->mail, $this->key);

return $request;
}

/**
* Example of how to query the Acquia Cloud API.
*
* @param $path
* @return string
* @throws \HTTP_Request2_Exception
*/
protected function getApiResponseBody($path) {
$request = $this->createRequest($path);

$this->log('GET ' . $request->getUrl());
$response = $request->send();
return $response->getBody();
}

/**
* @param PhingFile $file
* @throws \IOException
* @throws \NullPointerException
*/
public function setCredentialsFile(PhingFile $file) {
$this->credentialsFile = new PhingFile($file);
}

}
Loading

0 comments on commit 83ddcbb

Please sign in to comment.