Skip to content

Commit 03ddca5

Browse files
committed
Merge pull request #79 from kmala/storage
feat(storage): Add support for multiple object storages
2 parents b08cab7 + b31cea7 commit 03ddca5

5 files changed

Lines changed: 101 additions & 76 deletions

File tree

contrib/ci/test.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ echo "1234567890123456789012345678901234567890" > $CURRENT_DIR/tmp/aws-admin/acc
3232
# create fake AWS credentials for minio user credentials
3333
mkdir -p $CURRENT_DIR/tmp/aws-user
3434
# needs to be 20 characters long
35+
echo "12345678901234567890" > $CURRENT_DIR/tmp/aws-user/accesskey
3536
echo "12345678901234567890" > $CURRENT_DIR/tmp/aws-user/access-key-id
3637
# needs to be 40 characters long
38+
echo "1234567890123456789012345678901234567890" > $CURRENT_DIR/tmp/aws-user/secretkey
3739
echo "1234567890123456789012345678901234567890" > $CURRENT_DIR/tmp/aws-user/access-secret-key
3840

3941
puts-step "creating fake kubernetes service account token"
@@ -47,7 +49,7 @@ echo "cert" > $CURRENT_DIR/tmp/k8s/ca.crt
4749
MINIO_JOB=$(docker run -dv $CURRENT_DIR/tmp/aws-admin:/var/run/secrets/deis/minio/admin -v $CURRENT_DIR/tmp/aws-user:/var/run/secrets/deis/minio/user -v $CURRENT_DIR/tmp/k8s:/var/run/secrets/kubernetes.io/serviceaccount quay.io/deisci/minio:canary boot server /home/minio/)
4850

4951
# boot postgres, linking the minio container and setting DEIS_MINIO_SERVICE_HOST and DEIS_MINIO_SERVICE_PORT
50-
PG_JOB=$(docker run -d --link $MINIO_JOB:minio -e BACKUP_FREQUENCY=1s -e DEIS_MINIO_SERVICE_HOST=minio -e DEIS_MINIO_SERVICE_PORT=9000 -v $CURRENT_DIR/tmp/creds:/var/run/secrets/deis/database/creds -v $CURRENT_DIR/tmp/aws-user:/etc/wal-e.d/env $1)
52+
PG_JOB=$(docker run -d --link $MINIO_JOB:minio -e BACKUP_FREQUENCY=1s -e DATABASE_STORAGE=minio -e DEIS_MINIO_SERVICE_HOST=minio -e DEIS_MINIO_SERVICE_PORT=9000 -v $CURRENT_DIR/tmp/creds:/var/run/secrets/deis/database/creds -v $CURRENT_DIR/tmp/aws-user:/var/run/secrets/deis/objectstore/creds $1)
5153

5254
# wait for postgres to boot
5355
puts-step "sleeping for 90s while postgres is booting..."

rootfs/Dockerfile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ ENV LANG en_US.utf8
2121
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8
2222

2323
ENV PG_MAJOR 9.4
24-
ENV PG_VERSION 9.4.6-1.pgdg80+1
24+
ENV PG_VERSION 9.4.7-1.pgdg80+1
2525

2626
RUN echo 'deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main' $PG_MAJOR > /etc/apt/sources.list.d/pgdg.list
2727

@@ -48,6 +48,8 @@ RUN apt-get update && apt-get install -y \
4848
pv \
4949
python \
5050
python-dev \
51+
libssl-dev \
52+
libffi-dev \
5153
--no-install-recommends \
5254
&& rm -rf /var/lib/apt/lists/*
5355

@@ -56,7 +58,7 @@ RUN curl -sSL https://raw.githubusercontent.com/pypa/pip/7.1.2/contrib/get-pip.p
5658

5759
# install deis/wal-e from the tip of the boto3-upgrade branch
5860
# NOTE (bacongobbler): we use the commit here so Docker's cache will bust when we make changes upstream
59-
RUN pip install --disable-pip-version-check --no-cache-dir git+https://github.com/deis/wal-e.git@dfa35c648b1a7b554122312d6c6b592be372e17a
61+
RUN pip install --disable-pip-version-check --no-cache-dir git+https://github.com/deis/wal-e.git@0eee12665149d8389cda9575b737359d066fa663
6062

6163
# install python port of daemontools
6264
RUN pip install --disable-pip-version-check --no-cache-dir envdir

rootfs/bin/create_bucket

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,69 @@ import sys
55

66
import boto3
77
import botocore
8+
import json
89
from botocore.utils import fix_s3_host
10+
from botocore.client import Config
11+
from oauth2client.service_account import ServiceAccountCredentials
12+
from gcloud.storage.client import Client
13+
from gcloud import exceptions
14+
from azure.storage.blob import BlockBlobService
915

1016
bucket_name = os.getenv('BUCKET_NAME')
1117

1218
if os.getenv('DATABASE_STORAGE') == "s3":
1319
conn = boto3.resource('s3')
14-
else:
15-
conn = boto3.resource('s3', endpoint_url=os.getenv('S3_URL'))
16-
# stop boto3 from automatically changing the endpoint
17-
conn.meta.client.meta.events.unregister('before-sign.s3', fix_s3_host)
18-
19-
exists = True
20-
try:
21-
conn.meta.client.head_bucket(Bucket=bucket_name)
22-
except botocore.exceptions.ClientError as e:
23-
# If a client error is thrown, then check that it was a 404 error.
24-
# If it was a 404 error, then the bucket does not exist.
25-
error_code = int(e.response['Error']['Code'])
26-
if error_code == 404:
20+
exists = True
21+
try:
22+
conn.meta.client.head_bucket(Bucket=bucket_name)
23+
except botocore.exceptions.ClientError as e:
24+
# If a client error is thrown, then check that it was a 404 error.
25+
# If it was a 404 error, then the bucket does not exist.
26+
error_code = int(e.response['Error']['Code'])
27+
if error_code == 404:
28+
exists = False
29+
else:
30+
raise
31+
32+
if not exists:
33+
conn.create_bucket(Bucket=bucket_name)
34+
35+
elif os.getenv('DATABASE_STORAGE') == "gcs":
36+
scopes = ['https://www.googleapis.com/auth/devstorage.full_control']
37+
credentials = ServiceAccountCredentials.from_json_keyfile_name(os.getenv('GS_APPLICATION_CREDS'), scopes=scopes)
38+
with open(os.getenv('GS_APPLICATION_CREDS')) as data_file:
39+
data = json.load(data_file)
40+
client = Client(credentials=credentials, project=data['project_id'])
41+
exists = True
42+
try:
43+
client.get_bucket(bucket_name)
44+
except exceptions.NotFound:
2745
exists = False
28-
else:
46+
except:
2947
raise
48+
if not exists:
49+
client.create_bucket(bucket_name)
50+
51+
elif os.getenv('DATABASE_STORAGE') == "azure":
52+
block_blob_service = BlockBlobService(account_name=os.getenv('WABS_ACCOUNT_NAME'), account_key=os.getenv('WABS_ACCESS_KEY'))
53+
#It doesn't throw an exception if the container exists by default(https://github.com/Azure/azure-storage-python/blob/master/azure/storage/blob/baseblobservice.py#L504).
54+
block_blob_service.create_container(bucket_name)
55+
56+
else :
57+
conn = boto3.resource('s3', endpoint_url=os.getenv('S3_URL'), config=Config(signature_version='s3v4'))
58+
# stop boto3 from automatically changing the endpoint
59+
conn.meta.client.meta.events.unregister('before-sign.s3', fix_s3_host)
60+
exists = True
61+
try:
62+
conn.meta.client.head_bucket(Bucket=bucket_name)
63+
except botocore.exceptions.ClientError as e:
64+
# If a client error is thrown, then check that it was a 404 error.
65+
# If it was a 404 error, then the bucket does not exist.
66+
error_code = int(e.response['Error']['Code'])
67+
if error_code == 404:
68+
exists = False
69+
else:
70+
raise
3071

31-
if not exists:
32-
conn.create_bucket(Bucket=bucket_name)
72+
if not exists:
73+
conn.create_bucket(Bucket=bucket_name)

rootfs/docker-entrypoint-initdb.d/001_setup_envdir.sh

Lines changed: 34 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,42 @@
22

33
cd "$WALE_ENVDIR"
44

5-
# access-key-id and access-secret-key files are mounted in via kubernetes secrets
6-
AWS_ACCESS_KEY_ID=$(cat access-key-id)
7-
AWS_SECRET_ACCESS_KEY=$(cat access-secret-key)
8-
AWS_DEFAULT_REGION="us-east-1"
9-
BUCKET_NAME="dbwal"
10-
11-
if [ "$DATABASE_STORAGE" == "s3" ]; then
5+
if [[ "$DATABASE_STORAGE" == "s3" || "$DATABASE_STORAGE" == "minio" ]]; then
126
AWS_ACCESS_KEY_ID=$(cat /var/run/secrets/deis/objectstore/creds/accesskey)
137
AWS_SECRET_ACCESS_KEY=$(cat /var/run/secrets/deis/objectstore/creds/secretkey)
14-
AWS_DEFAULT_REGION=$(cat /var/run/secrets/deis/objectstore/creds/region)
15-
BUCKET_NAME=$(cat /var/run/secrets/deis/objectstore/creds/database-bucket)
16-
else
17-
# these only need to be set if we're not accessing S3 (boto will figure this out)
18-
echo "http://$DEIS_MINIO_SERVICE_HOST:$DEIS_MINIO_SERVICE_PORT" > WALE_S3_ENDPOINT
19-
if [ "$DEIS_MINIO_SERVICE_PORT" == "80" ]; then
20-
# If you add port 80 to the end of the endpoint_url, boto3 freaks out.
21-
# God I hate boto3 some days.
22-
echo "http://$DEIS_MINIO_SERVICE_HOST" > S3_URL
8+
if [[ "$DATABASE_STORAGE" == "s3" ]]; then
9+
AWS_DEFAULT_REGION=$(cat /var/run/secrets/deis/objectstore/creds/region)
10+
BUCKET_NAME=$(cat /var/run/secrets/deis/objectstore/creds/database-bucket)
2311
else
24-
echo "http://$DEIS_MINIO_SERVICE_HOST:$DEIS_MINIO_SERVICE_PORT" > S3_URL
12+
# these only need to be set if we're not accessing S3 (boto will figure this out)
13+
echo "http://$DEIS_MINIO_SERVICE_HOST:$DEIS_MINIO_SERVICE_PORT" > WALE_S3_ENDPOINT
14+
if [ "$DEIS_MINIO_SERVICE_PORT" == "80" ]; then
15+
# If you add port 80 to the end of the endpoint_url, boto3 freaks out.
16+
# God I hate boto3 some days.
17+
echo "http://$DEIS_MINIO_SERVICE_HOST" > S3_URL
18+
else
19+
echo "http://$DEIS_MINIO_SERVICE_HOST:$DEIS_MINIO_SERVICE_PORT" > S3_URL
20+
fi
21+
AWS_DEFAULT_REGION="us-east-1"
22+
BUCKET_NAME="dbwal"
2523
fi
24+
echo "s3://$BUCKET_NAME" > WALE_S3_PREFIX
25+
echo $AWS_ACCESS_KEY_ID > AWS_ACCESS_KEY_ID
26+
echo $AWS_SECRET_ACCESS_KEY > AWS_SECRET_ACCESS_KEY
27+
echo $AWS_DEFAULT_REGION > AWS_DEFAULT_REGION
28+
echo $BUCKET_NAME > BUCKET_NAME
29+
elif [ "$DATABASE_STORAGE" == "gcs" ]; then
30+
GS_APPLICATION_CREDS="/var/run/secrets/deis/objectstore/creds/key.json"
31+
BUCKET_NAME=$(cat /var/run/secrets/deis/objectstore/creds/database-bucket)
32+
echo "gs://$BUCKET_NAME" > WALE_GS_PREFIX
33+
echo $GS_APPLICATION_CREDS > GS_APPLICATION_CREDS
34+
echo $BUCKET_NAME > BUCKET_NAME
35+
elif [ "$DATABASE_STORAGE" == "azure" ]; then
36+
WABS_ACCOUNT_NAME=$(cat /var/run/secrets/deis/objectstore/creds/accountname)
37+
WABS_ACCESS_KEY=$(cat /var/run/secrets/deis/objectstore/creds/accountkey)
38+
BUCKET_NAME=$(cat /var/run/secrets/deis/objectstore/creds/database-container)
39+
echo $WABS_ACCOUNT_NAME > WABS_ACCOUNT_NAME
40+
echo $WABS_ACCESS_KEY > WABS_ACCESS_KEY
41+
echo "wabs://$BUCKET_NAME" > WALE_WABS_PREFIX
42+
echo $BUCKET_NAME > BUCKET_NAME
2643
fi
27-
28-
echo $AWS_ACCESS_KEY_ID > AWS_ACCESS_KEY_ID
29-
echo $AWS_SECRET_ACCESS_KEY > AWS_SECRET_ACCESS_KEY
30-
echo $AWS_DEFAULT_REGION > AWS_DEFAULT_REGION
31-
echo $BUCKET_NAME > BUCKET_NAME
32-
33-
# setup envvars for wal-e
34-
echo "s3://$BUCKET_NAME" > WALE_S3_PREFIX
35-
36-
37-
# setup boto config
38-
mkdir -p /root/.aws /home/postgres/.aws
39-
40-
cat << EOF > /root/.aws/credentials
41-
[default]
42-
aws_access_key_id = $AWS_ACCESS_KEY_ID
43-
aws_secret_access_key = $AWS_SECRET_ACCESS_KEY
44-
EOF
45-
46-
if [ "$DATABASE_STORAGE" == "s3" ]; then
47-
cat << EOF > /root/.aws/config
48-
[default]
49-
region = $AWS_DEFAULT_REGION
50-
EOF
51-
else
52-
# HACK (bacongobbler): minio *must* use us-east-1 and signature version 4
53-
# for authentication.
54-
# see https://github.com/minio/minio#how-to-use-aws-cli-with-minio
55-
cat << EOF > /root/.aws/config
56-
[default]
57-
region = $AWS_DEFAULT_REGION
58-
s3 =
59-
signature_version = s3v4
60-
EOF
61-
fi
62-
63-
# write AWS config to postgres homedir as well
64-
cp /root/.aws/* /home/postgres/.aws/
65-
chown -R postgres:postgres /home/postgres

rootfs/docker-entrypoint-initdb.d/003_restore_from_backup.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ gosu postgres pg_ctl -D "$PGDATA" -w restart
1515
# check if there are any backups -- if so, let's restore
1616
# we could probably do better than just testing number of lines -- one line is just a heading, meaning no backups
1717
if [[ $(envdir "$WALE_ENVDIR" wal-e --terse backup-list | wc -l) -gt "1" ]]; then
18-
echo "Found backups on S3. Restoring from backup..."
18+
echo "Found backups. Restoring from backup..."
1919
gosu postgres pg_ctl -D "$PGDATA" -w stop
2020
rm -rf "$PGDATA"
2121
envdir "$WALE_ENVDIR" wal-e backup-fetch "$PGDATA" LATEST
@@ -44,6 +44,8 @@ host all all 0.0.0.0/0 md5
4444
EOF
4545
touch "$PGDATA/pg_ident.conf"
4646
echo "restore_command = 'envdir /etc/wal-e.d/env wal-e wal-fetch \"%f\" \"%p\"'" >> "$PGDATA/recovery.conf"
47+
chown -R postgres:postgres "$PGDATA"
48+
chmod 0700 "$PGDATA"
4749
gosu postgres pg_ctl -D "$PGDATA" \
4850
-o "-c listen_addresses=''" \
4951
-t 1200 \

0 commit comments

Comments
 (0)