Skip to content

Commit

Permalink
Backup plugin buckets enhancement (#107)
Browse files Browse the repository at this point in the history
* Backup plugin buckets enhancement

* PR fixes

* Additional specs
  • Loading branch information
borsothy authored and askreet committed Jun 23, 2016
1 parent be9bfaf commit bba5aba
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 9 deletions.
25 changes: 24 additions & 1 deletion docs/plugins/backup.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ present in the same account and region as your deployment.
When instantiating a class, you need to set the following options
in a block, where the object is provided as a block argument:

- `bucket`: the name of the S3 bucket you wish to upload the tarball
- `bucket`: the name of the S3 bucket you wish to upload the tarball (optional)
- `buckets`: a hash map containing account aliases as keys, and target buckets as values (optional)
- `files`: an array of relative path names as strings
- `hooks`: which hooks to run the backup logic, works with all valid Moonshot hooks
- `target_name`: tarball archive name, default: `<app_name>_<timestamp>_<user>.tar.gz`

You must provide either `bucket` or `buckets`, but **not both**.

## Default method

If you wish to back up only the current template and parameter files, you can simply
Expand Down Expand Up @@ -50,10 +53,30 @@ parameter file after create or update.
plugin(
Backup.new do |b|
b.bucket = 'your-bucket-name'

b.files = [
'cloud_formation/%{app_name}.json',
'cloud_formation/parameters/%{stack_name}.yml'
]

b.hooks = [:post_create, :post_update]
end
)
```

```ruby
plugin(
Backup.new do |b|
b.buckets = {
'dev_account' => 'dev_bucket',
'prod_account' => 'prod_bucket'
}

b.files = [
'cloud_formation/%{app_name}.json',
'cloud_formation/parameters/%{stack_name}.yml'
]

b.hooks = [:post_create, :post_update]
end
)
Expand Down
39 changes: 34 additions & 5 deletions lib/plugins/backup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@
module Moonshot
module Plugins
# Moonshot plugin class for deflating and uploading files on given hooks
class Backup
class Backup # rubocop:disable Metrics/ClassLength
include Moonshot::CredsHelper

attr_accessor :bucket,
:buckets,
:files,
:hooks,
:target_name

def initialize
yield self if block_given?
raise ArgumentError if @bucket.nil? || @files.nil? || @files.empty? || @hooks.nil?
raise ArgumentError \
if @files.nil? || @files.empty? || @hooks.nil? || !(@bucket.nil? ^ @buckets.nil?)

@target_name ||= '%{app_name}_%{timestamp}_%{user}.tar.gz'
end

Expand Down Expand Up @@ -45,6 +48,9 @@ def backup(resources) # rubocop:disable Metrics/AbcSize
@app_name = resources.stack.app_name
@stack_name = resources.stack.name
@target_name = render(@target_name)
@target_bucket = define_bucket

return if @target_bucket.nil?

resources.ilog.start("#{log_message} in progress.") do |s|
begin
Expand Down Expand Up @@ -74,7 +80,8 @@ def respond_to?(method_name, include_private = false)
private

attr_accessor :app_name,
:stack_name
:stack_name,
:target_bucket

# Create a tar archive in memory, returning the IO object pointing at the
# beginning of the archive.
Expand Down Expand Up @@ -117,7 +124,7 @@ def zip(io_tar)
def upload(io_zip)
s3_client.put_object(
acl: 'private',
bucket: @bucket,
bucket: @target_bucket,
key: @target_name,
body: io_zip
)
Expand All @@ -138,7 +145,29 @@ def render(placeholder)
end

def log_message
"Uploading '#{@target_name}' to '#{@bucket}'"
"Uploading '#{@target_name}' to '#{@target_bucket}'"
end

def iam_account
iam_client.list_account_aliases.account_aliases.first
end

def define_bucket
case
# returning already calculated bucket name
when @target_bucket
@target_bucket
# single bucket for all accounts
when @bucket
@bucket
# calculating bucket based on account name
when @buckets
bucket_by_account(iam_account)
end
end

def bucket_by_account(account)
@buckets[account]
end
end
end
Expand Down
55 changes: 52 additions & 3 deletions spec/moonshot/plugins/backup_spec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
class MockInteractiveLogger
def start(_)
yield self
end

def success(_)
end

def failure(_)
end
end

describe Moonshot::Plugins::Backup do
let(:hooks) do
[
Expand Down Expand Up @@ -32,6 +44,17 @@
expect { subject.new }.to raise_error(ArgumentError)
end

it 'should raise ArgumentError if redundant parameters are provided' do
expect do
subject.new do |b|
b.bucket = 'test'
b.buckets = {}
b.files = %w(sample files)
b.hooks = [:sample, :hooks]
end
end.to raise_error(ArgumentError)
end

let(:backup) do
subject.new do |b|
b.bucket = 'testbucket'
Expand Down Expand Up @@ -74,18 +97,44 @@
end

describe '#backup' do
subject { Moonshot::Plugins::Backup.to_bucket bucket: 'bucket' }
subject do
Moonshot::Plugins::Backup.new do |b|
b.buckets = {
'dev_account' => 'dev_bucket'
}
b.files = ['test_file']
b.hooks = %i(post_create post_update)
end
end

let(:resources) do
instance_double(
Moonshot::Resources,
stack: instance_double(Moonshot::Stack),
stack: instance_double(Moonshot::Stack, app_name: 'test_app_name', name: 'test_name'),
ilog: instance_double(Moonshot::InteractiveLoggerProxy)
)
end

it 'should raise ArgumentError if resources not injected' do
it 'should raise ArgumentError if resources are not injected' do
expect { subject.backup }.to raise_error(ArgumentError)
end

it 'should return silent if account not found in buckets hash' do
allow(subject).to receive(:iam_account).and_return('prod_account')
expect(resources).not_to receive(:ilog)
subject.backup(resources)
end

it 'should upload' do
allow(subject).to receive(:iam_account).and_return('dev_account')
expect(resources).to receive(:ilog).and_return(MockInteractiveLogger.new)

%i(tar zip upload).each do |s|
allow(subject).to receive(s)
expect(subject).to receive(s)
end

subject.backup(resources)
end
end
end

0 comments on commit bba5aba

Please sign in to comment.