boucher 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/boucher.gemspec +1 -1
- data/lib/boucher/servers.rb +1 -1
- data/lib/boucher/snapshots.rb +66 -0
- data/lib/boucher/storage.rb +32 -7
- data/lib/boucher/tasks/snapshots.rake +28 -0
- data/lib/boucher/tasks/storage.rake +14 -13
- data/lib/boucher/tasks/volumes.rake +4 -3
- data/lib/boucher/volumes.rb +5 -4
- data/spec/boucher/snapshots_spec.rb +36 -0
- data/spec/boucher/volumes_spec.rb +1 -0
- metadata +6 -2
data/boucher.gemspec
CHANGED
data/lib/boucher/servers.rb
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'boucher/compute'
|
2
|
+
|
3
|
+
module Boucher
|
4
|
+
|
5
|
+
SNAPSHOT_TABLE_FORMAT = "%-13s %-12s %-18s %-80s\n"
|
6
|
+
|
7
|
+
def self.print_snapshots(volumes)
|
8
|
+
puts
|
9
|
+
printf SNAPSHOT_TABLE_FORMAT, "ID", "Volume ID", "Created At", "Description"
|
10
|
+
puts ("-" * 120)
|
11
|
+
|
12
|
+
volumes.each do |snapshot|
|
13
|
+
printf SNAPSHOT_TABLE_FORMAT,
|
14
|
+
snapshot.id,
|
15
|
+
snapshot.volume_id,
|
16
|
+
snapshot.created_at.strftime("%b %d %Y %H:%M"),
|
17
|
+
snapshot.description[0...80]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Snapshots
|
22
|
+
def self.all
|
23
|
+
@snapshots ||= Boucher.compute.snapshots
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.with_id(snapshot_id)
|
27
|
+
all.find { |snapshot| snapshot.id == snapshot_id }
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.snap(volume_id)
|
31
|
+
description = "Boucher snapshot of #{volume_id} at #{Time.now.strftime("%b %d %Y %H:%M")}"
|
32
|
+
snapshot = all.create(:volume_id => volume_id, :description => description)
|
33
|
+
snapshot.wait_for { snapshot.state == "completed" }
|
34
|
+
snapshot
|
35
|
+
end
|
36
|
+
|
37
|
+
#def self.destroy(volumes)
|
38
|
+
# Array(volumes).each do |snapshot|
|
39
|
+
# snapshot.reload
|
40
|
+
# snapshot.destroy
|
41
|
+
# end
|
42
|
+
#end
|
43
|
+
#
|
44
|
+
#def self.with_id(volume_id)
|
45
|
+
# all.find { |snapshot| snapshot.id == volume_id }
|
46
|
+
#end
|
47
|
+
#
|
48
|
+
#def self.create(options)
|
49
|
+
# zone = options[:availability_zone]
|
50
|
+
# raise ":availability_zone is required to create a snapshot." unless zone
|
51
|
+
# size = options[:size]
|
52
|
+
# snapshot_id = options[:snapshot_id]
|
53
|
+
# response = if snapshot_id
|
54
|
+
# snapshot = Boucher::compute.snapshots.get(snapshot_id)
|
55
|
+
# size = snapshot.volume_size.to_i
|
56
|
+
# Boucher.compute.create_volume(zone, size, "SnapshotId" => snapshot_id)
|
57
|
+
# else
|
58
|
+
# Boucher.compute.create_volume(zone, size)
|
59
|
+
# end
|
60
|
+
# volume_id = response.body["volumeId"]
|
61
|
+
# snapshot = Boucher.compute.volumes.get(volume_id)
|
62
|
+
# snapshot.wait_for { snapshot.ready? }
|
63
|
+
# snapshot
|
64
|
+
#end
|
65
|
+
end
|
66
|
+
end
|
data/lib/boucher/storage.rb
CHANGED
@@ -15,36 +15,60 @@ module Boucher
|
|
15
15
|
@store
|
16
16
|
end
|
17
17
|
|
18
|
-
FILE_TABLE_FORMAT = "%-60s %-10s %-25s %-32s\n"
|
18
|
+
FILE_TABLE_FORMAT = "%-4s %-60s %-10s %-25s %-32s\n"
|
19
19
|
|
20
20
|
def self.print_file_table_header
|
21
21
|
puts
|
22
|
-
printf FILE_TABLE_FORMAT, "Key", "Size", "Last Modified", "etag"
|
23
|
-
puts ("-" *
|
22
|
+
printf FILE_TABLE_FORMAT, "Type", "Key", "Size", "Last Modified", "etag"
|
23
|
+
puts ("-" * 156)
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.print_file(file)
|
27
27
|
printf FILE_TABLE_FORMAT,
|
28
|
+
"file",
|
28
29
|
file.key,
|
29
30
|
file.content_length,
|
30
31
|
file.last_modified,
|
31
32
|
file.etag
|
32
33
|
end
|
33
34
|
|
35
|
+
def self.print_directory(directory)
|
36
|
+
printf FILE_TABLE_FORMAT,
|
37
|
+
"dir",
|
38
|
+
directory.key,
|
39
|
+
"",
|
40
|
+
directory.creation_date,
|
41
|
+
""
|
42
|
+
end
|
43
|
+
|
34
44
|
def self.print_files(files)
|
35
45
|
print_file_table_header
|
36
46
|
files.each do |file|
|
37
|
-
|
47
|
+
if file
|
48
|
+
if file.class.name =~ /Directory/
|
49
|
+
print_directory(file)
|
50
|
+
else
|
51
|
+
print_file(file)
|
52
|
+
end
|
53
|
+
end
|
38
54
|
end
|
39
55
|
puts
|
40
56
|
end
|
41
57
|
|
42
58
|
module Storage
|
43
59
|
|
60
|
+
def self.dir(dir_name)
|
61
|
+
Boucher.storage.directories.get(dir_name)
|
62
|
+
rescue Exception => e
|
63
|
+
raise "Failed to access directory: #{dir_name} (#{e.to_s})"
|
64
|
+
end
|
65
|
+
|
44
66
|
def self.list(dir_name)
|
45
|
-
|
46
|
-
|
47
|
-
|
67
|
+
if dir_name
|
68
|
+
dir(dir_name).files
|
69
|
+
else
|
70
|
+
Boucher.storage.directories
|
71
|
+
end
|
48
72
|
end
|
49
73
|
|
50
74
|
def self.put(dir_name, key, filename)
|
@@ -59,6 +83,7 @@ module Boucher
|
|
59
83
|
def self.get(dir_name, key, filename)
|
60
84
|
dir = Boucher.storage.directories.get(dir_name)
|
61
85
|
url = dir.files.get_https_url(key, Time.now + 3600)
|
86
|
+
puts "url: #{url}"
|
62
87
|
Kernel.system("curl", url, "-o", filename)
|
63
88
|
dir.files.detect { |f| f.key == key }
|
64
89
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'boucher/snapshots'
|
2
|
+
|
3
|
+
namespace :snapshots do
|
4
|
+
desc "List all snapshots"
|
5
|
+
task :list do
|
6
|
+
Boucher.print_snapshots(Boucher::Snapshots.all)
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Takes a snapshot of the specified volume"
|
10
|
+
task :snap, [:volume_id] do |t, args|
|
11
|
+
puts "Taking snapshot of volume #{args.volume_id}"
|
12
|
+
snapshot = Boucher::Snapshots.snap(args.volume_id)
|
13
|
+
Boucher.print_snapshots [snapshot]
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Deleted the specified snapshot"
|
17
|
+
task :delete, [:snapshot_id] do |t, args|
|
18
|
+
snapshot = Boucher::Snapshots.with_id(args.snapshot_id)
|
19
|
+
if snapshot
|
20
|
+
puts "Deleting snapshot:"
|
21
|
+
Boucher.print_snapshots [snapshot]
|
22
|
+
snapshot.destroy
|
23
|
+
puts "The snapshot as been deleted."
|
24
|
+
else
|
25
|
+
raise "Snapshot not found: #{args.snapshot_id}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -4,27 +4,28 @@ require 'boucher/io'
|
|
4
4
|
namespace :storage do
|
5
5
|
|
6
6
|
desc "Lists all the files in the infrastructure bucket on S3"
|
7
|
-
task :list do
|
8
|
-
files
|
7
|
+
task :list, [:path] do |t, args|
|
8
|
+
puts "Listing files: #{args.path || "/"} ..."
|
9
|
+
files = Boucher::Storage.list(args.path)
|
9
10
|
Boucher.print_files files
|
10
11
|
end
|
11
12
|
|
12
13
|
desc "Puts a file in the infrastructure bucket"
|
13
|
-
task :put, [:file] do |t, args|
|
14
|
+
task :put, [:file, :path] do |t, args|
|
14
15
|
filename = args.file
|
15
|
-
key =
|
16
|
-
puts "Storing file #{filename} as #{key}"
|
17
|
-
file = Boucher::Storage.put(
|
16
|
+
bucket, key = args.path.split("/")
|
17
|
+
puts "Storing file #{filename} as #{bucket}/#{key}"
|
18
|
+
file = Boucher::Storage.put(bucket, key, filename)
|
18
19
|
Boucher.print_files [file]
|
19
|
-
puts "File uploaded as #{key}."
|
20
|
+
puts "File uploaded as #{bucket}/#{key}."
|
20
21
|
end
|
21
22
|
|
22
|
-
desc "
|
23
|
-
task :get, [:
|
24
|
-
|
25
|
-
|
26
|
-
puts "Getting file #{
|
27
|
-
file = Boucher::Storage.get(
|
23
|
+
desc "Downloads a file from S3. The path should be <bucket_name>/<file_key>."
|
24
|
+
task :get, [:path] do |t, args|
|
25
|
+
directory, filename = args.path.split("/")
|
26
|
+
raise "Path must be of the form <bucket_name>/<file_key>" unless (directory && filename)
|
27
|
+
puts "Getting file #{args.path} and saving to ./#{filename}"
|
28
|
+
file = Boucher::Storage.get(directory, filename, filename)
|
28
29
|
Boucher.print_files [file]
|
29
30
|
puts "File saved locally as #{filename}."
|
30
31
|
end
|
@@ -7,13 +7,14 @@ namespace :volumes do
|
|
7
7
|
Boucher.print_volumes(Boucher::Volumes.all)
|
8
8
|
end
|
9
9
|
|
10
|
-
desc "
|
11
|
-
task :
|
10
|
+
desc "Delete the specified volume"
|
11
|
+
task :delete, [:volume_id] do |t, args|
|
12
12
|
volume = Boucher::Volumes.with_id(args.volume_id)
|
13
13
|
if volume
|
14
|
-
puts "
|
14
|
+
puts "Deleting volume:"
|
15
15
|
Boucher.print_volumes [volume]
|
16
16
|
volume.destroy
|
17
|
+
puts "The volume as been deleted."
|
17
18
|
else
|
18
19
|
raise "Volume not found: #{args.volume_id}"
|
19
20
|
end
|
data/lib/boucher/volumes.rb
CHANGED
@@ -1,20 +1,21 @@
|
|
1
1
|
require 'boucher/compute'
|
2
|
+
require 'boucher/servers'
|
2
3
|
|
3
4
|
module Boucher
|
4
5
|
|
5
|
-
VOLUME_TABLE_FORMAT = "%-12s %-
|
6
|
+
VOLUME_TABLE_FORMAT = "%-12s %-6s %-10s %-12s %-10s %-13s\n"
|
6
7
|
|
7
8
|
def self.print_volumes(volumes)
|
8
9
|
puts
|
9
|
-
printf VOLUME_TABLE_FORMAT, "ID", "
|
10
|
-
puts ("-" *
|
10
|
+
printf VOLUME_TABLE_FORMAT, "ID", "Size", "Server", "Device", "State", "Snapshot"
|
11
|
+
puts ("-" * 75)
|
11
12
|
|
12
13
|
volumes.each do |volume|
|
13
14
|
printf VOLUME_TABLE_FORMAT,
|
14
15
|
volume.id,
|
15
|
-
(volume.tags["Name"] || "")[0...15],
|
16
16
|
volume.size.to_s + "GB",
|
17
17
|
volume.server_id,
|
18
|
+
volume.device,
|
18
19
|
volume.state,
|
19
20
|
volume.snapshot_id
|
20
21
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
require 'boucher/snapshots'
|
3
|
+
require 'boucher/volumes'
|
4
|
+
|
5
|
+
describe "Boucher::snapshots" do
|
6
|
+
|
7
|
+
context "with mocked volumes" do
|
8
|
+
let(:remote_snapshots) {
|
9
|
+
[OpenStruct.new(:id => "snap-1", :tags => {}, :description => "1"),
|
10
|
+
OpenStruct.new(:id => "snap-2", :tags => {}, :description => "2"),
|
11
|
+
OpenStruct.new(:id => "snap-3", :tags => {}, :description => "3")]
|
12
|
+
}
|
13
|
+
|
14
|
+
before do
|
15
|
+
Boucher.compute.stub(:snapshots).and_return(remote_snapshots)
|
16
|
+
end
|
17
|
+
|
18
|
+
after do
|
19
|
+
Boucher::Config[:env] = "test"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "finds all snapshots" do
|
23
|
+
Boucher::Snapshots.all.size.should == 3
|
24
|
+
Boucher::Snapshots.all.should == remote_snapshots
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "takes a snapshot" do
|
29
|
+
volume = Boucher::Volumes.create(:size => 12, :availability_zone => "us-east-1c")
|
30
|
+
snapshot = Boucher::Snapshots.snap(volume.id)
|
31
|
+
|
32
|
+
snapshot.volume_id.should == volume.id
|
33
|
+
snapshot.state.should == "completed"
|
34
|
+
snapshot.description[0...16].should == "Boucher snapshot"
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: boucher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -99,11 +99,13 @@ files:
|
|
99
99
|
- lib/boucher/meals.rb
|
100
100
|
- lib/boucher/provision.rb
|
101
101
|
- lib/boucher/servers.rb
|
102
|
+
- lib/boucher/snapshots.rb
|
102
103
|
- lib/boucher/storage.rb
|
103
104
|
- lib/boucher/tasks.rb
|
104
105
|
- lib/boucher/tasks/addresses.rake
|
105
106
|
- lib/boucher/tasks/console.rake
|
106
107
|
- lib/boucher/tasks/servers.rake
|
108
|
+
- lib/boucher/tasks/snapshots.rake
|
107
109
|
- lib/boucher/tasks/storage.rake
|
108
110
|
- lib/boucher/tasks/volumes.rake
|
109
111
|
- lib/boucher/util.rb
|
@@ -115,6 +117,7 @@ files:
|
|
115
117
|
- spec/boucher/meals_spec.rb
|
116
118
|
- spec/boucher/provision_spec.rb
|
117
119
|
- spec/boucher/servers_spec.rb
|
120
|
+
- spec/boucher/snapshots_spec.rb
|
118
121
|
- spec/boucher/storage_spec.rb
|
119
122
|
- spec/boucher/util_spec.rb
|
120
123
|
- spec/boucher/volumes_spec.rb
|
@@ -151,6 +154,7 @@ test_files:
|
|
151
154
|
- spec/boucher/meals_spec.rb
|
152
155
|
- spec/boucher/provision_spec.rb
|
153
156
|
- spec/boucher/servers_spec.rb
|
157
|
+
- spec/boucher/snapshots_spec.rb
|
154
158
|
- spec/boucher/storage_spec.rb
|
155
159
|
- spec/boucher/util_spec.rb
|
156
160
|
- spec/boucher/volumes_spec.rb
|