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 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