Skip to content

Handle gsi #67

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM node:7.9.0-alpine

# Add project
COPY . /home/root
RUN cd /home/root && npm install
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Can be run as a command line script or as an npm module.
-p, --backup-path <name> backup path to store table dumps in. default is DynamoDB-backup-YYYY-MM-DD-HH-mm-ss
-e, --base64-encode-binary if passed, encode binary fields in base64 before exporting
-d, --save-datapipeline-format save in format compatible with the AWS datapipeline import. Default to false (save as exported by DynamoDb)
-f, --save-schema save table schema. Default to true
--aws-key AWS access key. Will use AWS_ACCESS_KEY_ID env var if --aws-key not set
--aws-secret AWS secret key. Will use AWS_SECRET_ACCESS_KEY env var if --aws-secret not set
--aws-region AWS region. Will use AWS_DEFAULT_REGION env var if --aws-region not set
Expand Down Expand Up @@ -161,7 +162,7 @@ __Arguments__

It is suitable for restoring large tables without needing to write to disk or use a large amount of memory. Use it on an AWS EC2 instance for best results and to minimise network latency, this should yield restore speeds of around 15min per GB.

Use `--overwrite` if the table already exists. Otherwise it will attempt to generate table on the fly.
Use `--overwrite` if the table already exists. Otherwise it will attempt to generate table on the fly using table.schema.json created on the backup.

Can be run as a command line script or as an npm module.

Expand Down
3 changes: 3 additions & 0 deletions backup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

./home/root/bin/dynamo-backup-to-s3 --bucket uniplaces.com.backups -p $(date +%Y-%m-%d) -r 0.1 --aws-key $AWS_KEY_BACKUP --aws-secret $AWS_SECRET_BACKUP --aws-region eu-west-1 --excluded-tables prod-search-offers,prod-admin-session,prod-ap-session,prod-core-session,prod-ops-session,prod-photography-session,prod-spa-session
4 changes: 3 additions & 1 deletion bin/dynamo-backup-to-s3
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ program
.option('-p, --backup-path <name>', 'backup path to store table dumps in. default is DynamoDB-backup-YYYY-MM-DD-HH-mm-ss')
.option('-e, --base64-encode-binary', 'encode binary fields in base64 before exporting')
.option('-d, --save-data-pipeline-format', 'save in format compatible with the AWS Data Pipeline import. Default to false (save as exported by DynamoDb)')
.option('-f, --save-schema', 'save table schema. Default to false')
.option('--aws-key <key>', 'AWS access key. Will use AWS_ACCESS_KEY_ID env var if --aws-key not set')
.option('--aws-secret <secret>', 'AWS secret key. Will use AWS_SECRET_ACCESS_KEY env var if --aws-secret not set')
.option('--aws-region <region>', 'AWS region. Will use AWS_DEFAULT_REGION env var if --aws-region not set')
Expand All @@ -46,7 +47,8 @@ var dynamoBackup = new DynamoBackup({
readPercentage: program.readPercentage,
stopOnFailure: program.stopOnFailure,
base64Binary: program.base64EncodeBinary,
saveDataPipelineFormat: program.saveDataPipelineFormat
saveDataPipelineFormat: program.saveDataPipelineFormat,
saveSchema: program.saveSchema
});

dynamoBackup.on('error', function(data) {
Expand Down
31 changes: 27 additions & 4 deletions bin/dynamo-restore-from-s3
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env node

var MY_SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/T1JC01J20/B56R0998F/' + process.env.SLACK_ID;
var slack = require('slack-notify')(MY_SLACK_WEBHOOK_URL);
var program = require('commander'),
fs = require('fs'),
DynamoRestore = require('../').Restore;
Expand All @@ -11,6 +12,7 @@ program
.option('-t, --table [name]', 'Name of the Dynamo Table to restore to (Required)')
.option('-o, --overwrite', 'Table already exists, skip auto-create. Default is false.')
.option('-c, --concurrency <requestcount>', 'Number of concurrent requests & dynamo capacity units. Defaults to 200.')
.option('-ic, --index-concurrency <requestcount>', 'Number of concurrent requests & dynamo capacity units for global secondary indexes. Defaults to 200.')
.option('-pk, --partitionkey [columnname]', 'Name of Primary Partition Key. If not provided will try determine from backup.')
.option('-sk, --sortkey [columnname]', 'Name of Secondary Sort Key. Ignored unless --partitionkey is provided.')
.option('-rc, --readcapacity <units>', 'Read Units for new table (when finished). Default is 5.')
Expand Down Expand Up @@ -39,6 +41,7 @@ var dynamoRestore = new DynamoRestore({
table: program.table,
overwrite: !!program.overwrite,
concurrency: program.concurrency,
indexConcurrency: program.indexConcurrency,
stopOnFailure: !!program.stopOnFailure,
// New table properties
partitionkey: program.partitionkey,
Expand All @@ -62,20 +65,34 @@ function translate(contentLength) {

// Define events
dynamoRestore.on('error', function(message) {
slack.note({
channel: '#ped_backup_restore',
text: 'Something went wrong restoring: ' + program.table,
fields: {
'Error': message,
},
username: 'Pato'
});
console.log(message);
process.exit(-1);
setTimeout(function() { process.exit(-1); }, 3000);
});

dynamoRestore.on('warning', function(message) {
console.log(message);
});

dynamoRestore.on('start-download', function(streamMeta) {
slack.note({
channel: '#ped_backup_restore',
text: 'Restoring ' + program.table + '. Write capacity set to: ' + program.concurrency,
username: 'Pato'
});
var time = runTimes.startDownload = new Date().getTime();
console.log('Starting download. %s remaining...', translate(streamMeta.ContentLength));
});

dynamoRestore.on('send-batch', function(batches, requests, streamMeta) {
return;
console.log('Batch sent. %d in flight. %s remaining to download...', requests, translate(streamMeta.RemainingLength));
});

Expand All @@ -85,6 +102,12 @@ dynamoRestore.run(function() {
diff = time - runTimes.start,
minutes = Math.floor(diff / (1000 * 60)),
seconds = Math.floor((diff % 1000 * 60) / 1000);

slack.note({
channel: '#ped_backup_restore',
text: 'Restore completed for ' + program.table + ' in ' + minutes + ' minutes ' + seconds + ' seconds. Write capacity: ' + program.writecapacity + ', Read capacity: ' + program.writecapacity,
username: 'Pato'
});
console.log('Done! Process completed in %s minutes %s seconds.', minutes, seconds);
process.exit(0);
});
setTimeout(function() { process.exit(0); }, 3000);
});
67 changes: 67 additions & 0 deletions deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# SET YOUR AWS CONFIG BEFORE RUNNING
$(aws ecr get-login --region eu-west-1)
docker build -t dynamo-backup-to-s3 .
docker tag dynamo-backup-to-s3:latest 584629324139.dkr.ecr.eu-west-1.amazonaws.com/dynamo-backup-to-s3:latest
docker push 584629324139.dkr.ecr.eu-west-1.amazonaws.com/dynamo-backup-to-s3:latest

# more bash-friendly output for jq
JQ="jq --raw-output --exit-status"

# create task def
make_task_def() {
task_def="[
{
\"name\": \"dynamo-backup-to-s3\",
\"image\": \"584629324139.dkr.ecr.eu-west-1.amazonaws.com/dynamo-backup-to-s3:latest\",
\"essential\": true,
\"memory\": 2500,
\"cpu\": 800,
\"logConfiguration\": {
\"logDriver\": \"awslogs\",
\"options\": {
\"awslogs-group\": \"prod-jobs\",
\"awslogs-region\": \"eu-west-1\",
\"awslogs-stream-prefix\": \"dynamo-backup-job\"
}
},
\"environment\": [
{
\"name\": \"AWS_KEY_BACKUP\",
\"value\":\"$AWS_KEY_BACKUP\"
},
{
\"name\": \"AWS_SECRET_BACKUP\",
\"value\": \"$AWS_SECRET_BACKUP\"
},
{
\"name\": \"AWS_KEY_RESTORE\",
\"value\": \"$AWS_KEY_RESTORE\"
},
{
\"name\": \"AWS_SECRET_RESTORE\",
\"value\": \"$AWS_SECRET_RESTORE\"
},
{
\"name\": \"SLACK_ID\",
\"value\": \"$SLACK_ID\"
}
]
}
]"
}

# register definition
register_definition() {
family="dynamo-backup-to-s3"
if revision=$(aws ecs register-task-definition --container-definitions "$task_def" --family $family | $JQ '.taskDefinition.taskDefinitionArn'); then
echo "Revision: $revision"
echo "$revision" > arn_revision.txt
echo $revision | sed -n -e 's/^.*task-definition\///p' > task_revision.txt
else
echo "Failed to register task definition"
return 1
fi
}

make_task_def
register_definition
8 changes: 8 additions & 0 deletions ecs-overrides-backup.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"containerOverrides": [
{
"name": "dynamo-backup-to-s3",
"command": ["sh","/home/root/backup.sh"]
}
]
}
8 changes: 8 additions & 0 deletions ecs-overrides-restore.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"containerOverrides": [
{
"name": "dynamo-backup-to-s3",
"command": ["sh","/home/root/restore.sh"]
}
]
}
Loading