boucher 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/boucher.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "boucher"
5
- s.version = "0.2.3"
5
+ s.version = "0.3.0"
6
6
  s.authors = ["'Micah Micah'"]
7
7
  s.email = ["'micah@8thlight.com'"]
8
8
  s.homepage = "http://github.com/8thlight/boucher"
@@ -117,7 +117,7 @@ module Boucher
117
117
  end
118
118
 
119
119
  def with_id(server_id)
120
- Servers.cultivate(self.find_all { |s| s.id == server_id }).first
120
+ Servers.cultivate(self.all.find_all { |s| s.id == server_id }).first
121
121
  end
122
122
 
123
123
  def [](meal)
@@ -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
@@ -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 ("-" * 150)
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
- print_file(file) if file
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
- dir = Boucher.storage.directories.get(dir_name)
46
- result = dir.files.select { |f| f.key[-1] != "/" }.to_a
47
- result
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 = Boucher::Storage.list("infrastructure")
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 = File.basename(filename)
16
- puts "Storing file #{filename} as #{key}"
17
- file = Boucher::Storage.put("infrastructure", key, filename)
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 "Gets a file from the infrastructure bucket. The file arg is the key on AWS."
23
- task :get, [:file] do |t, args|
24
- key = args.file
25
- filename = File.basename(key)
26
- puts "Getting file #{key} and saving to #{filename}"
27
- file = Boucher::Storage.get("infrastructure", key, filename)
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 "Destroy the specified volume"
11
- task :destroy, [:volume_id] do |t, args|
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 "Destroying volume:"
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
@@ -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 %-15s %-6s %-10s %-10s %-13s\n"
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", "Name", "Size", "Server", "State", "Snapshot"
10
- puts ("-" * 76)
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
@@ -47,4 +47,5 @@ describe "Boucher::Volumes" do
47
47
  new_volume.size.should == 12
48
48
  new_volume.availability_zone.should == "us-east-1c"
49
49
  end
50
+
50
51
  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.2.3
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-09 00:00:00.000000000 Z
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