heirloom 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/README.md +0 -1
- data/lib/heirloom/acl/s3.rb +10 -8
- data/lib/heirloom/artifact.rb +44 -43
- data/lib/heirloom/artifact/artifact_authorizer.rb +20 -22
- data/lib/heirloom/artifact/artifact_builder.rb +41 -37
- data/lib/heirloom/artifact/artifact_destroyer.rb +16 -14
- data/lib/heirloom/artifact/artifact_downloader.rb +22 -40
- data/lib/heirloom/artifact/artifact_lister.rb +10 -7
- data/lib/heirloom/artifact/artifact_reader.rb +17 -20
- data/lib/heirloom/artifact/artifact_updater.rb +6 -5
- data/lib/heirloom/artifact/artifact_uploader.rb +8 -8
- data/lib/heirloom/aws/s3.rb +1 -1
- data/lib/heirloom/cli.rb +37 -30
- data/lib/heirloom/cli/build.rb +40 -0
- data/lib/heirloom/cli/destroy.rb +20 -0
- data/lib/heirloom/cli/download.rb +23 -0
- data/lib/heirloom/cli/list.rb +17 -0
- data/lib/heirloom/cli/show.rb +27 -0
- data/lib/heirloom/cli/update.rb +23 -0
- data/lib/heirloom/config.rb +11 -6
- data/lib/heirloom/destroyer/s3.rb +6 -4
- data/lib/heirloom/directory/directory.rb +15 -11
- data/lib/heirloom/directory/git_directory.rb +4 -3
- data/lib/heirloom/downloader/s3.rb +1 -1
- data/lib/heirloom/logger.rb +6 -4
- data/lib/heirloom/version.rb +1 -1
- data/spec/acl/s3_spec.rb +51 -0
- data/spec/artifact/artifact_authorizer_spec.rb +34 -0
- data/spec/artifact/artifact_builder_spec.rb +41 -0
- data/spec/artifact/artifact_destroyer_spec.rb +45 -0
- data/spec/artifact/artifact_downloader_spec.rb +93 -0
- data/spec/artifact/artifact_lister_spec.rb +21 -0
- data/spec/artifact/artifact_reader_spec.rb +55 -0
- data/spec/artifact/artifact_updater_spec.rb +16 -0
- data/spec/artifact/artifact_uploader_spec.rb +16 -0
- data/spec/artifact_spec.rb +69 -19
- data/spec/aws/s3_spec.rb +55 -0
- data/spec/aws/simpledb_spec.rb +50 -0
- data/spec/config_spec.rb +32 -3
- data/spec/destroyer/s3_spec.rb +21 -0
- data/spec/directory/directory_spec.rb +26 -0
- data/spec/directory/git_directory_spec.rb +28 -0
- data/spec/downloader/s3_spec.rb +23 -0
- data/spec/logger_spec.rb +20 -0
- metadata +55 -16
@@ -2,9 +2,11 @@ module Heirloom
|
|
2
2
|
module Destroyer
|
3
3
|
class S3
|
4
4
|
|
5
|
+
attr_accessor :config, :region
|
6
|
+
|
5
7
|
def initialize(args)
|
6
|
-
|
7
|
-
|
8
|
+
self.config = args[:config]
|
9
|
+
self.region = args[:region]
|
8
10
|
end
|
9
11
|
|
10
12
|
def destroy_file(args)
|
@@ -18,8 +20,8 @@ module Heirloom
|
|
18
20
|
private
|
19
21
|
|
20
22
|
def s3
|
21
|
-
@s3 ||= AWS::S3.new :config =>
|
22
|
-
:region =>
|
23
|
+
@s3 ||= AWS::S3.new :config => config,
|
24
|
+
:region => region
|
23
25
|
end
|
24
26
|
|
25
27
|
end
|
@@ -8,32 +8,36 @@ module Heirloom
|
|
8
8
|
|
9
9
|
class Directory
|
10
10
|
|
11
|
+
attr_accessor :config, :exclude, :local_build, :path, :logger
|
12
|
+
|
11
13
|
def initialize(args)
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
self.config = args[:config]
|
15
|
+
self.exclude = args[:exclude]
|
16
|
+
self.path = args[:path]
|
17
|
+
self.logger = config.logger
|
15
18
|
end
|
16
19
|
|
17
20
|
def build_artifact_from_directory
|
18
21
|
random_text = (0...8).map{65.+(rand(25)).chr}.join
|
19
|
-
temp_file_name = File.join(Dir.tmpdir, random_text + ".tar.gz")
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
unless local_build
|
24
|
+
self.local_build = File.join(Dir.tmpdir, random_text + ".tar.gz")
|
25
|
+
end
|
26
|
+
|
27
|
+
logger.info "Building artifact '#{local_build}' from '#{path}'."
|
28
|
+
logger.info "Excluding #{exclude.to_s}."
|
29
|
+
logger.info "Adding #{files_to_pack.to_s}."
|
24
30
|
|
25
|
-
tgz = Zlib::GzipWriter.new File.open(
|
31
|
+
tgz = Zlib::GzipWriter.new File.open(local_build, 'wb')
|
26
32
|
|
27
33
|
Minitar.pack(files_to_pack, tgz)
|
28
|
-
temp_file_name
|
29
34
|
end
|
30
35
|
|
31
36
|
private
|
32
37
|
|
33
38
|
def files_to_pack
|
34
|
-
Dir.entries(
|
39
|
+
Dir.entries(path) - ['.', '..'] - exclude
|
35
40
|
end
|
36
41
|
|
37
|
-
|
38
42
|
end
|
39
43
|
end
|
@@ -6,13 +6,14 @@ module Heirloom
|
|
6
6
|
|
7
7
|
class GitDirectory
|
8
8
|
|
9
|
+
attr_accessor :path
|
10
|
+
|
9
11
|
def initialize(args)
|
10
|
-
|
11
|
-
@logger = args[:logger]
|
12
|
+
self.path = args[:path]
|
12
13
|
end
|
13
14
|
|
14
15
|
def commit(sha = nil)
|
15
|
-
r = Repo.new
|
16
|
+
r = Repo.new path
|
16
17
|
sha ? r.commits(sha).first : r.commits.first
|
17
18
|
end
|
18
19
|
|
data/lib/heirloom/logger.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
module Heirloom
|
2
2
|
class HeirloomLogger
|
3
3
|
|
4
|
-
def initialize(args)
|
4
|
+
def initialize(args = {})
|
5
5
|
@logger = args[:logger] ||= Logger.new(STDOUT)
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
unless args[:logger]
|
8
|
+
@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
9
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
10
|
+
"#{datetime}: #{msg}\n"
|
11
|
+
end
|
10
12
|
end
|
11
13
|
|
12
14
|
@logger
|
data/lib/heirloom/version.rb
CHANGED
data/spec/acl/s3_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Heirloom do
|
4
|
+
before do
|
5
|
+
@config_mock = double 'config'
|
6
|
+
@logger_mock = double 'logger'
|
7
|
+
@config_mock.should_receive(:logger).and_return(@logger_mock)
|
8
|
+
@config_mock.should_receive(:authorized_aws_accounts).
|
9
|
+
and_return ['acct1@test.com', 'acct2@test.com']
|
10
|
+
|
11
|
+
@s3 = Heirloom::ACL::S3.new :config => @config_mock,
|
12
|
+
:region => 'us-west-1'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should allow read access for the specified accounts" do
|
16
|
+
acls = {
|
17
|
+
'Owner' => {
|
18
|
+
'Name' => 'Brett',
|
19
|
+
'ID' => '123'
|
20
|
+
}
|
21
|
+
}
|
22
|
+
s3_mock = mock 's3'
|
23
|
+
|
24
|
+
@s3.should_receive(:s3).exactly(2).times.
|
25
|
+
and_return(s3_mock)
|
26
|
+
|
27
|
+
s3_mock.should_receive(:get_bucket_acl).with('bucket').
|
28
|
+
and_return acls
|
29
|
+
|
30
|
+
grants_mock = mock 'grants'
|
31
|
+
@s3.should_receive(:build_bucket_grants).
|
32
|
+
with(:id => '123',
|
33
|
+
:name => 'Brett',
|
34
|
+
:accounts => ['acct1@test.com', 'acct2@test.com']).
|
35
|
+
and_return grants_mock
|
36
|
+
|
37
|
+
@logger_mock.should_receive(:info).
|
38
|
+
with 'Authorizing acct1@test.com to s3://bucket/key-folder/key.tar.gz.'
|
39
|
+
@logger_mock.should_receive(:info).
|
40
|
+
with 'Authorizing acct2@test.com to s3://bucket/key-folder/key.tar.gz.'
|
41
|
+
|
42
|
+
s3_mock.should_receive(:put_object_acl).with('bucket', 'key-folder/key.tar.gz', grants_mock)
|
43
|
+
|
44
|
+
@s3.allow_read_access_from_accounts :bucket => 'bucket',
|
45
|
+
:key_name => 'key',
|
46
|
+
:key_folder => 'key-folder'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should test build_bucket_grants private method"
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Heirloom do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config_mock = double('config')
|
7
|
+
@logger_mock = double('logger')
|
8
|
+
@config_mock.should_receive(:logger).and_return(@logger_mock)
|
9
|
+
@authorizer = Heirloom::ArtifactAuthorizer.new :config => @config_mock,
|
10
|
+
:name => 'tim',
|
11
|
+
:id => '123'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should authorize access to an acl across all regions" do
|
15
|
+
artifact_reader = double
|
16
|
+
s3_acl = double
|
17
|
+
@logger_mock.should_receive(:info).exactly(2).times
|
18
|
+
@config_mock.should_receive(:regions).
|
19
|
+
and_return(['us-west-1', 'us-west-2'])
|
20
|
+
@authorizer.should_receive(:artifact_reader).exactly(2).times.
|
21
|
+
and_return(artifact_reader)
|
22
|
+
artifact_reader.should_receive(:get_bucket).exactly(2).times.
|
23
|
+
and_return('the-bucket')
|
24
|
+
Heirloom::ACL::S3.should_receive(:new).exactly(2).
|
25
|
+
times.and_return(s3_acl)
|
26
|
+
s3_acl.should_receive(:allow_read_access_from_accounts).
|
27
|
+
exactly(2).times.
|
28
|
+
with(:key_name => '123',
|
29
|
+
:key_folder => 'tim',
|
30
|
+
:bucket => 'the-bucket')
|
31
|
+
@authorizer.authorize
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Heirloom do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config_mock = double 'config'
|
7
|
+
@logger_mock = double 'logger'
|
8
|
+
@simpledb_mock = double 'simple db'
|
9
|
+
@config_mock.should_receive(:logger).and_return(@logger_mock)
|
10
|
+
Heirloom::AWS::SimpleDB.should_receive(:new).with(:config => @config_mock).
|
11
|
+
and_return(@simpledb_mock)
|
12
|
+
@simpledb_mock.should_receive(:create_domain).with 'tim'
|
13
|
+
@builder = Heirloom::ArtifactBuilder.new :config => @config_mock,
|
14
|
+
:name => 'tim',
|
15
|
+
:id => '123'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should build an artifact" do
|
19
|
+
directory_mock = double "directory"
|
20
|
+
Heirloom::Directory.should_receive(:new).with(:path => 'path_to_build',
|
21
|
+
:exclude => ['.dir_to_exclude'],
|
22
|
+
:config => @config_mock).
|
23
|
+
and_return(directory_mock)
|
24
|
+
directory_mock.should_receive :build_artifact_from_directory
|
25
|
+
directory_mock.should_receive(:local_build).and_return('/tmp/file')
|
26
|
+
@builder.should_receive(:create_artifact_record)
|
27
|
+
@builder.should_receive(:add_git_commit)
|
28
|
+
@logger_mock.should_receive(:info).with("Build complete.")
|
29
|
+
@builder.build(:exclude => ['.dir_to_exclude'],
|
30
|
+
:directory => 'path_to_build',
|
31
|
+
:git => 'true').should == '/tmp/file'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should cleanup the local artifact" do
|
35
|
+
@builder.local_build = '/tmp/file'
|
36
|
+
@logger_mock.should_receive(:info).with("Cleaning up local build /tmp/file.")
|
37
|
+
File.should_receive(:delete).with('/tmp/file')
|
38
|
+
@builder.cleanup
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Heirloom do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config_mock = double 'config'
|
7
|
+
@logger_mock = double 'logger'
|
8
|
+
@config_mock.should_receive(:logger).and_return(@logger_mock)
|
9
|
+
@destroyer = Heirloom::ArtifactDestroyer.new :config => @config_mock,
|
10
|
+
:name => 'tim',
|
11
|
+
:id => '123'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should destroy the given artifact" do
|
15
|
+
@logger_mock.should_receive(:info).
|
16
|
+
with "Destroying tim - 123"
|
17
|
+
@config_mock.should_receive(:regions).and_return ['us-west-1']
|
18
|
+
artifact_reader_mock = mock 'artifact reader'
|
19
|
+
@destroyer.should_receive(:artifact_reader).and_return artifact_reader_mock
|
20
|
+
bucket_mock = mock 'bucket'
|
21
|
+
artifact_reader_mock.should_receive(:get_bucket).
|
22
|
+
with(:region => 'us-west-1').
|
23
|
+
and_return 'bucket-us-west-1'
|
24
|
+
|
25
|
+
@logger_mock.should_receive(:info).
|
26
|
+
with "Destroying 's3://bucket-us-west-1/tim/123.tar.gz'."
|
27
|
+
|
28
|
+
s3_destroyer_mock = mock 's3 destroyer'
|
29
|
+
Heirloom::Destroyer::S3.should_receive(:new).
|
30
|
+
with(:config => @config_mock,
|
31
|
+
:region => 'us-west-1').
|
32
|
+
and_return s3_destroyer_mock
|
33
|
+
s3_destroyer_mock.should_receive(:destroy_file).
|
34
|
+
with :key_name => '123.tar.gz',
|
35
|
+
:key_folder => 'tim',
|
36
|
+
:bucket => 'bucket-us-west-1'
|
37
|
+
sdb_mock = mock 'sdb'
|
38
|
+
@destroyer.should_receive(:sdb).and_return sdb_mock
|
39
|
+
sdb_mock.should_receive(:delete).with 'tim', '123'
|
40
|
+
@logger_mock.should_receive(:info).
|
41
|
+
with "Destroy complete."
|
42
|
+
@destroyer.destroy
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Heirloom do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config_mock = double 'config'
|
7
|
+
@logger_mock = double 'logger'
|
8
|
+
@config_mock.should_receive(:logger).and_return(@logger_mock)
|
9
|
+
@downloader = Heirloom::ArtifactDownloader.new :config => @config_mock,
|
10
|
+
:name => 'tim',
|
11
|
+
:id => '123'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should download an artifact" do
|
15
|
+
s3_downloader_mock = mock 's3 downloader'
|
16
|
+
Heirloom::Downloader::S3.should_receive(:new).
|
17
|
+
with(:config => @config_mock,
|
18
|
+
:logger => @logger_mock,
|
19
|
+
:region => 'us-west-1').
|
20
|
+
and_return s3_downloader_mock
|
21
|
+
artifact_reader_mock = mock 'artifact_reader'
|
22
|
+
@downloader.should_receive(:artifact_reader).
|
23
|
+
exactly(2).times.
|
24
|
+
and_return artifact_reader_mock
|
25
|
+
artifact_reader_mock.should_receive(:get_bucket).
|
26
|
+
with(:region => 'us-west-1').
|
27
|
+
and_return 'bucket-us-west-1'
|
28
|
+
artifact_reader_mock.should_receive(:get_key).
|
29
|
+
with(:region => 'us-west-1').
|
30
|
+
and_return 'key'
|
31
|
+
|
32
|
+
@logger_mock.should_receive(:info).
|
33
|
+
with "Downloading s3://bucket-us-west-1/key from us-west-1."
|
34
|
+
|
35
|
+
s3_downloader_mock.should_receive(:download_file).
|
36
|
+
with(:bucket => 'bucket-us-west-1',
|
37
|
+
:key => 'key').
|
38
|
+
and_return 'filename'
|
39
|
+
|
40
|
+
@logger_mock.should_receive(:info).
|
41
|
+
with "Writing file to /tmp/file."
|
42
|
+
|
43
|
+
file_mock = mock 'file'
|
44
|
+
|
45
|
+
File.should_receive(:open).with('/tmp/file', 'w').
|
46
|
+
and_return file_mock
|
47
|
+
|
48
|
+
@logger_mock.should_receive(:info).with "Download complete."
|
49
|
+
|
50
|
+
@downloader.download(:output => '/tmp/file',
|
51
|
+
:region => 'us-west-1')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should download the artifact to the current path if output is unspecficief" do
|
55
|
+
s3_downloader_mock = mock 's3 downloader'
|
56
|
+
Heirloom::Downloader::S3.should_receive(:new).
|
57
|
+
with(:config => @config_mock,
|
58
|
+
:logger => @logger_mock,
|
59
|
+
:region => 'us-west-1').
|
60
|
+
and_return s3_downloader_mock
|
61
|
+
artifact_reader_mock = mock 'artifact_reader'
|
62
|
+
@downloader.should_receive(:artifact_reader).
|
63
|
+
exactly(2).times.
|
64
|
+
and_return artifact_reader_mock
|
65
|
+
artifact_reader_mock.should_receive(:get_bucket).
|
66
|
+
with(:region => 'us-west-1').
|
67
|
+
and_return 'bucket-us-west-1'
|
68
|
+
artifact_reader_mock.should_receive(:get_key).
|
69
|
+
with(:region => 'us-west-1').
|
70
|
+
and_return 'key'
|
71
|
+
|
72
|
+
@logger_mock.should_receive(:info).
|
73
|
+
with "Downloading s3://bucket-us-west-1/key from us-west-1."
|
74
|
+
|
75
|
+
s3_downloader_mock.should_receive(:download_file).
|
76
|
+
with(:bucket => 'bucket-us-west-1',
|
77
|
+
:key => 'key').
|
78
|
+
and_return 'filename'
|
79
|
+
|
80
|
+
@logger_mock.should_receive(:info).
|
81
|
+
with "Writing file to ./key."
|
82
|
+
|
83
|
+
file_mock = mock 'file'
|
84
|
+
|
85
|
+
File.should_receive(:open).with('./key', 'w').
|
86
|
+
and_return file_mock
|
87
|
+
|
88
|
+
@logger_mock.should_receive(:info).with "Download complete."
|
89
|
+
|
90
|
+
@downloader.download(:region => 'us-west-1')
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Heirloom do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config_mock = double 'config'
|
7
|
+
@lister = Heirloom::ArtifactLister.new :config => @config_mock,
|
8
|
+
:name => 'test123'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should list the known artifacts" do
|
12
|
+
sdb_mock = mock 'sdb'
|
13
|
+
@lister.should_receive(:sdb).and_return sdb_mock
|
14
|
+
sdb_mock.should_receive(:select).
|
15
|
+
with("select * from test123 where built_at > '2000-01-01T00:00:00.000Z' \
|
16
|
+
order by built_at desc limit 10").
|
17
|
+
and_return( {'1' => 'one', '2' => 'two', '3' => 'three'} )
|
18
|
+
@lister.list.should == ['1', '2', '3']
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Heirloom do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@config_mock = double 'config'
|
7
|
+
@reader = Heirloom::ArtifactReader.new :config => @config_mock,
|
8
|
+
:name => 'tim',
|
9
|
+
:id => '123'
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should show the item record" do
|
13
|
+
sdb_mock = mock 'sdb'
|
14
|
+
@reader.should_receive(:sdb).and_return sdb_mock
|
15
|
+
sdb_mock.should_receive(:select).
|
16
|
+
with("select * from tim where itemName() = '123'").
|
17
|
+
and_return( { '123' => 'details' } )
|
18
|
+
@reader.show.should == 'details'
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return true if the record exists" do
|
22
|
+
@reader.should_receive(:show).and_return 'a record'
|
23
|
+
@reader.exists?.should == true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return false if the recrod does not exist" do
|
27
|
+
@reader.should_receive(:show).and_return nil
|
28
|
+
@reader.exists?.should == false
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return the bucket for the specified region" do
|
32
|
+
@reader.should_receive(:get_url).
|
33
|
+
with(:region => 'us-west-1').
|
34
|
+
and_return 's3://bucket-us-west-1/tim/123.tar.gz'
|
35
|
+
@reader.get_bucket(:region => 'us-west-1').should == 'bucket-us-west-1'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return the key" do
|
39
|
+
@reader.should_receive(:show).
|
40
|
+
and_return( { 'us-west-1-s3-url' =>
|
41
|
+
[ 's3://bucket-us-west-1/tim/123.tar.gz' ] } )
|
42
|
+
@reader.should_receive(:get_bucket).
|
43
|
+
with(:region => 'us-west-1').
|
44
|
+
and_return 'bucket-us-west-1'
|
45
|
+
@reader.get_key(:region => 'us-west-1').should == 'tim/123.tar.gz'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "shoudl return the s3 url for the given region" do
|
49
|
+
@reader.should_receive(:show).
|
50
|
+
and_return( { 'us-west-1-s3-url' =>
|
51
|
+
[ 's3://bucket-us-west-1/tim/123.tar.gz' ] } )
|
52
|
+
@reader.get_url(:region => 'us-west-1').should == 's3://bucket-us-west-1/tim/123.tar.gz'
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|