Smarter CDE Setups: One-Time Drupal Database Syncs with Acquia Pipelines πŸš€

  • 10 minute read

Acquia's Cloud Development Environments (CDEs) are a game-changer for developer workflows, spinning up a dedicated environment for every pull request. A common first step is seeding this new environment with a database from a source, like your staging or dev integration environment. But what happens on the second, third, or fourth push to that same pull request? You don't want to overwrite your work every single time!

This article will show you how to build an intelligent post-deploy script that syncs a Drupal database only on the first run for a new CDE. We'll dive into how to detect the CDE's name within Acquia Pipelines and use some simple shell script logic to avoid unnecessary, and potentially destructive, database syncs.


πŸ” Securing Your Credentials: API Keys and SSH

Before our script can run, it needs to authenticate with Acquia's services. Hardcoding keys and secrets directly into your acquia-pipelines.yml file is a major security risk. Instead, you should always use Acquia Pipelines' built-in encryption.

Let’s walk through setting up and encrypting the two types of credentials our script uses: ACLI API tokens and an SSH key.


1. Generating and Encrypting ACLI Tokens

The Acquia CLI (ACLI) needs an API Key and Secret to communicate with your Acquia applications.

First, generate a new API token in the Acquia Cloud UI by navigating to Manage > Profile > API Tokens. You'll receive a **Key** and a **Secret**.

Next, use the pipelines encrypt command locally to secure these values. This command must be run from within your codebase directory where your acquia-pipelines.yml file is located.

# Encrypt your ACLI Key
pipelines encrypt --string="YOUR_ACLI_KEY_HERE"

# Encrypt your ACLI Secret
pipelines encrypt --string="YOUR_ACLI_SECRET_HERE"

Each command will output a multi-line secure: block. Copy these blocks and place them in the global variables section of your acquia-pipelines.yml file.

# acquia-pipelines.yml
variables:
  global:
    ACLI_KEY: 
      secure: REDACTED
    ACLI_SECRET: 
      secure: REDACTED

2. Generating and Encrypting an SSH Key

Our script also needs an SSH key to authenticate with the server environment. It’s best practice to generate a dedicated key for Pipelines.

Create a new SSH key pair without a passphrase, as the script needs to use it non-interactively:

# Generates a private key (write-key) and a public key (write-key.pub)
ssh-keygen -t ed25519 -C "pipelines-key" -f ./write-key -N ""

Next Step: You must add the contents of the public key (write-key.pub) to your Acquia Cloud account's SSH keys before the pipeline can use it.

Now, encrypt the private key file (write-key) using the same encryption command, but this time with the --file flag:

# Encrypt the private key file
pipelines encrypt --file=./write-key

Finally, place the resulting secure: block into the ssh-keys section of your acquia-pipelines.yml. The key name here (write-key) is how you will reference it inside the pipeline environment (e.g., ~/.ssh/write-key).

# acquia-pipelines.yml
ssh-keys:
  write-key: 
    secure: REDACTED

With these encrypted credentials in place, your pipeline can securely authenticate and execute its tasks without exposing any secrets in your codebase.


The Goal: Sync Once, Then Step Back

The core of our task is to make our deployment process smart. It should ask a simple question: "Is this a brand new, empty CDE?"

  • βœ… If yes: It's the first deployment. Go ahead and sync the database from our source environment.
  • ❌ If no: A Drupal site is already here. A developer might have made changes. Do not touch the database and let them continue their work.

This approach saves time on subsequent deployments and, more importantly, protects the developer's progress within that CDE.


Connecting the Dots: From Pipelines to Your Script

First, we need to configure our acquia-pipelines.yaml file to run our script after a deployment finishes. The magic lies in the post-deploy event. We also need a way to get the unique name of the CDE that was just deployed.

Acquia Pipelines makes this information available in a special file, $PIPELINES_SCRIPT_DATA_FILE. We can parse this JSON file to extract the environment name and pass it as an argument to our shell script.

The `acquia-pipelines.yaml` Configuration

Here’s how we set up the post-deploy step:

# acquia-pipelines.yaml

events:
  # The 'post-deploy' event runs AFTER the automatic deployment finishes.
  post-deploy:
    steps:
      - run_post_deploy_tasks:
          name: Run tasks after deployment
          service: pipelines-deployment
          script:
            - pipelines-deploy
            # This is the key line! We extract the CDE name from the data file.
            - CDE_NAME=$(cat $PIPELINES_SCRIPT_DATA_FILE | python3 -c "import sys, json; print(json.load(sys.stdin)['environment']['PIPELINES_DEPLOYMENT_NAME'])")
            # Make our script executable and run it with the CDE name as an argument.
            - chmod +x ./scripts/pipelines/post-deploy.sh
            - ./scripts/pipelines/post-deploy.sh $CDE_NAME

πŸ’‘ How it works: We use a short, inline Python script to parse the JSON content provided by Pipelines and print the value of the PIPELINES_DEPLOYMENT_NAME key. This value is then stored in the $CDE_NAME shell variable.


The Intelligence: The `post-deploy.sh` Script

Now that our YAML is passing the CDE name to post-deploy.sh, the script can use that information to check the status of the Drupal installation on that specific environment.

Setting Up the Environment: ACLI and SSH

Before we can check on Drupal, our script needs to prepare its own environment. This involves installing the Acquia CLI, authenticating with both the API and SSH, and linking to the correct application. These steps ensure our script has the authorization and tools needed to interact with the CDE.

Here's what the initial setup block in the script does:

  • Install ACLI: It creates a local directory, downloads the latest acli.phar executable from GitHub, makes it executable with chmod, and adds it to the system's PATH.
  • Authenticate and Link: It logs into the API non-interactively using the $ACLI_KEY and $ACLI_SECRET variables we defined in our YAML file. It then links ACLI to the target application using the $PIPELINES_CLOUD_SITE variable.
  • Start SSH Agent: It starts the ssh-agent and adds our decrypted write-key. This is crucial for allowing ACLI to establish a secure shell connection to the CDE to run remote Drush commands.
# 1. Install Acquia CLI (ACLI)
echo "Installing Acquia CLI (ACLI)..."
mkdir -p "$HOME/.acli/bin"
curl -sSLf -o "$HOME/.acli/bin/acli" "https://github.com/acquia/cli/releases/latest/download/acli.phar"
chmod +x "$HOME/.acli/bin/acli"
export PATH="$HOME/.acli/bin:$PATH"

# Authenticate with acli and link application
acli auth:login -k $ACLI_KEY -s $ACLI_SECRET -n
acli app:link $PIPELINES_CLOUD_SITE
echo "ACLI installed successfully."

# Start SSH agent and propagate keys
echo "πŸ”‘ Starting SSH agent and propagating keys..."
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/write-key
echo "SSH keys propagated successfully."

Checking for an Existing Drupal Installation

With the environment set up, the most reliable way to see if Drupal is installed and running is to ask Drush. We can use the now-authenticated ACLI to run a remote Drush command against our CDE.

The command acli remote:drush "$PIPELINES_CLOUD_SITE.$1" -- "status --field=bootstrap" attempts to get the bootstrap status of the Drupal site.

  • If it returns Successful and the command exits with code 0, Drupal is installed.
  • If the command fails (e.g., non-zero exit code), we can safely assume Drupal isn't installed yet.

Here’s the logic in our script:

#!/bin/bash
set -e

# ... (ACLI installation and other setup happens here) ...

echo "Loading database status for $PIPELINES_CLOUD_SITE.$1"

# Temporarily allow commands to fail so we can capture the exit code
set +e
DRUSH_STATUS=$(acli remote:drush "$PIPELINES_CLOUD_SITE.$1" -- "status --field=bootstrap" 2>/dev/null)
EXIT_CODE=$?
set -e # Re-enable exiting on error

# Trim whitespace from the output for a reliable comparison
DRUSH_STATUS_TRIMMED=$(echo "$DRUSH_STATUS" | xargs)

if [ $EXIT_CODE -eq 0 ] && [ "$DRUSH_STATUS_TRIMMED" == "Successful" ]; then
  # If the command succeeds, Drupal is already there.
  echo "βœ… Drupal is already installed. Skipping database sync."
else
  # If the command fails, it's a fresh CDE that needs its database.
  echo "ℹ️ Drush command failed. Assuming new CDE and syncing database..."
  
  # Sync the database from your specified source environment.
  pipelines-sync-dbs "your-application-alias"
  echo "βœ… Database sync from 'eeearias' completed."
fi

Conclusion

And that's it! By combining the power of the post-deploy hook in Pipelines, a bit of JSON parsing to get the environment name, and a smart check in a shell script, you can create a seamless and safe workflow for your CDEs. Your developers get a perfectly seeded environment on their first push, and their work is preserved on all subsequent pushes. This small automation adds up to a big improvement in developer experience and productivity.