blimpy 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,4 +17,5 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_dependency 'fog'
19
19
  gem.add_dependency 'thor'
20
+ gem.add_dependency 'minitar'
20
21
  end
@@ -0,0 +1,37 @@
1
+ Feature: SCP a file into a named VM
2
+ In order to easily copy files from my local host to the named VM
3
+ As a Blimpy user
4
+ I should be able to run `blimpy scp <name> <file> [dest]`
5
+
6
+ Scenario: SCPing with an invalid blimp name
7
+ Given I have the Blimpfile:
8
+ """
9
+ Blimpy.fleet do |f|
10
+ f.add do |host|
11
+ host.name = 'Cucumber Host'
12
+ end
13
+ end
14
+ """
15
+ And I have a file named "hello.txt"
16
+ When I run `blimpy scp Gherkins hello.txt`
17
+ Then the exit status should be 1
18
+ And the output should contain:
19
+ """
20
+ Could not find a blimp named "Gherkins"
21
+ """
22
+
23
+ # This test is in the same boat that the complimentary test in ssh.feature is
24
+ # in.
25
+ @slow @destroy @wip
26
+ Scenario: SCPing a valid file
27
+ Given I have the Blimpfile:
28
+ """
29
+ Blimpy.fleet do |f|
30
+ f.add do |host|
31
+ host.name = 'Cucumber Host'
32
+ end
33
+ end
34
+ """
35
+ And I have a file named "hello.txt"
36
+ When I run `blimpy scp "Cucumber Host" hello.txt`
37
+ Then the exit status should be 0
@@ -16,7 +16,7 @@ Feature: SSH into a named VM
16
16
  Then the exit status should be 1
17
17
  And the output should contain:
18
18
  """
19
- Could not find blimp named "Gherkins"
19
+ Could not find a blimp named "Gherkins"
20
20
  """
21
21
 
22
22
 
@@ -26,6 +26,12 @@ Given /^I have a single VM running$/ do
26
26
  end
27
27
  end
28
28
 
29
+ Given /^I have a file named "([^"]*)"$/ do |filename|
30
+ File.open(filename, 'w') do |fd|
31
+ fd.write("I am #{filename}\n")
32
+ end
33
+ end
34
+
29
35
  When /^I ssh into the machine$/ do
30
36
  step %{I run `blimpy start`}
31
37
  step %{I run `blimpy ssh "Cucumber Host" -o StrictHostKeyChecking=no` interactively}
@@ -1,4 +1,5 @@
1
1
  require 'blimpy/helpers/state'
2
+ require 'blimpy/livery'
2
3
  require 'blimpy/keys'
3
4
 
4
5
  module Blimpy
@@ -37,6 +38,8 @@ module Blimpy
37
38
  @tags = {}
38
39
  @server = server
39
40
  @fleet_id = 0
41
+ @ssh_connected = false
42
+ @exec_commands = true
40
43
  end
41
44
 
42
45
  def region=(newRegion)
@@ -65,6 +68,14 @@ module Blimpy
65
68
  write_state_file
66
69
  end
67
70
 
71
+ def bootstrap
72
+ @exec_commands = false
73
+ unless livery.nil?
74
+ wait_for_sshd
75
+ bootstrap_livery
76
+ end
77
+ end
78
+
68
79
  def stop
69
80
  unless @server.nil?
70
81
  @server.stop
@@ -91,7 +102,6 @@ module Blimpy
91
102
  end
92
103
  end
93
104
 
94
-
95
105
  def state_file
96
106
  if @server.nil?
97
107
  raise Exception, "I can't make a state file without a @server!"
@@ -120,19 +130,62 @@ module Blimpy
120
130
  'no name'
121
131
  end
122
132
 
123
- def ssh_into
133
+ def run_command(*args)
134
+ if @exec_commands
135
+ ::Kernel.exec(*args)
136
+ else
137
+ ::Kernel.system(*args)
138
+ end
139
+ end
140
+
141
+ def ssh_into(*args)
142
+ # Support using #ssh_into within our own code as well to pass arguments
143
+ # to the ssh(1) binary
144
+ args = args || ARGV[2 .. -1]
145
+ run_command('ssh', '-o', 'StrictHostKeyChecking=no',
146
+ '-l', username, dns_name, *args)
147
+ end
148
+
149
+ def scp_file(filename)
150
+ filename = File.expand_path(filename)
151
+ run_command('scp', '-o', 'StrictHostKeyChecking=no',
152
+ filename, "#{username}@#{dns_name}:", *ARGV[3..-1])
153
+ end
154
+
155
+ def bootstrap_livery
156
+ tarball = nil
157
+ if livery == :cwd
158
+ tarball = Blimpy::Livery.tarball_directory(Dir.pwd)
159
+ scp_file(tarball)
160
+ # HAXX
161
+ basename = File.basename(tarball)
162
+ puts 'Bootstrapping the livery'
163
+ ssh_into("tar -zxf #{basename} && cd #{File.basename(tarball, '.tar.gz')} && sudo ./bootstrap.sh")
164
+ end
165
+ end
166
+
167
+ def wait_for_sshd
168
+ return if @ssh_connected
124
169
  start = Time.now.to_i
125
- print "..making sure #{@name} is online"
126
- begin
127
- TCPSocket.new(dns_name, 22)
128
- rescue Errno::ECONNREFUSED
129
- if (Time.now.to_i - start) < 30
130
- print '.'
131
- retry
170
+ use_exec = @exec_commands
171
+ # Even if we are supposed to use #exec here, we wait to disable it until
172
+ # after sshd(8) comes online
173
+ @exec_commands = false
174
+
175
+ print "..waiting for sshd on #{@name} to come online"
176
+ until @ssh_connected
177
+ # Run the `true` command and exit
178
+ @ssh_connected = ssh_into('-q', 'true')
179
+
180
+ unless @ssh_connected
181
+ if (Time.now.to_i - start) < 30
182
+ print '.'
183
+ sleep 1
184
+ end
132
185
  end
133
186
  end
134
187
  puts
135
- ::Kernel.exec('ssh', '-l', username, dns_name, *ARGV[2..-1])
188
+ @exec_commands = use_exec
136
189
  end
137
190
 
138
191
  private
@@ -15,6 +15,17 @@ module Blimpy
15
15
  exit 1
16
16
  end
17
17
  end
18
+
19
+ def box_by_name(name)
20
+ fleet = Blimpy::Fleet.new
21
+ box = nil
22
+ fleet.members.each do |instance_id, data|
23
+ box_name = data['name']
24
+ next unless box_name == name
25
+ box = Blimpy::Box.from_instance_id(instance_id, data)
26
+ end
27
+ box
28
+ end
18
29
  end
19
30
 
20
31
  desc 'start', 'Start up a fleet of blimps'
@@ -84,19 +95,25 @@ end
84
95
  desc 'ssh BLIMP_NAME', 'Log into a running blimp'
85
96
  def ssh(name, *args)
86
97
  ensure_blimpfile
87
- fleet = Blimpy::Fleet.new
88
- box = nil
89
- fleet.members.each do |instance_id, data|
90
- box_name = data['name']
91
- next unless box_name == name
92
- box = Blimpy::Box.from_instance_id(instance_id, data)
93
- end
98
+ box = box_by_name(name)
94
99
  if box.nil?
95
- puts "Could not find blimp named \"#{name}\""
100
+ puts "Could not find a blimp named \"#{name}\""
96
101
  exit 1
97
102
  end
98
-
103
+ box.wait_for_sshd
99
104
  box.ssh_into
100
105
  end
106
+
107
+ desc 'scp BLIMP_NAME FILE_NAME', 'Securely copy FILE_NAME into the blimp'
108
+ def scp(name, filename, *args)
109
+ ensure_blimpfile
110
+ box = box_by_name(name)
111
+ if box.nil?
112
+ puts "Could not find a blimp named \"#{name}\""
113
+ exit 1
114
+ end
115
+ box.wait_for_sshd
116
+ box.scp_file(filename)
117
+ end
101
118
  end
102
119
  end
@@ -69,6 +69,7 @@ module Blimpy
69
69
  host.wait_for_state('running') { print '.' }
70
70
  print ".. online at: #{host.dns_name}"
71
71
  host.online!
72
+ host.bootstrap
72
73
  puts
73
74
  end
74
75
 
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'zlib'
3
+ require 'archive/tar/minitar'
4
+
5
+ module Blimpy
6
+ class Livery
7
+ def self.tarball_directory(directory)
8
+ if directory.nil? || !(File.directory? directory)
9
+ raise ArgumentError, "The argument '#{directory}' doesn't appear to be a directory"
10
+ end
11
+
12
+ directory = File.expand_path(directory)
13
+ short_name = File.basename(directory)
14
+
15
+ tarball = nil
16
+ Dir.chdir(File.expand_path(directory + '/../')) do
17
+ tarball = self.gzip_for_directory(short_name, '/tmp') do |tgz|
18
+ Archive::Tar::Minitar.pack(short_name, tgz)
19
+ end
20
+ end
21
+ tarball
22
+ end
23
+
24
+ private
25
+
26
+ def self.gzip_for_directory(directory, root)
27
+ filename = File.join(root, "#{directory}.tar.gz")
28
+ yield Zlib::GzipWriter.new(File.open(filename, 'wb'))
29
+ filename
30
+ end
31
+
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module Blimpy
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -147,5 +147,21 @@ describe Blimpy::Box do
147
147
  end
148
148
 
149
149
  end
150
+
151
+ describe '#bootstrap_livery' do
152
+ context 'with a livery of :cwd' do
153
+ before :each do
154
+ subject.livery = :cwd
155
+ end
156
+
157
+ it 'should tarball up the current directory' do
158
+ Dir.should_receive(:pwd).and_return('mock-pwd')
159
+ Blimpy::Livery.should_receive(:tarball_directory).with('mock-pwd').and_return('mock-pwd.tar.gz')
160
+ subject.should_receive(:scp_file).with('mock-pwd.tar.gz')
161
+ subject.should_receive(:ssh_into)
162
+ subject.bootstrap_livery
163
+ end
164
+ end
165
+ end
150
166
  end
151
167
  end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ require 'blimpy/livery'
3
+
4
+ describe Blimpy::Livery do
5
+ context 'class methods' do
6
+ describe '#tarball_directory' do
7
+ subject { Blimpy::Livery } # No instantiating!
8
+ it 'should raise an exception if the directory doesn\'t exist' do
9
+ expect {
10
+ subject.tarball_directory(nil)
11
+ }.to raise_error(ArgumentError)
12
+
13
+ expect {
14
+ subject.tarball_directory('/tmp/never-gonna-give-you-up.lolz')
15
+ }.to raise_error(ArgumentError)
16
+ end
17
+ end
18
+ end
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blimpy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-28 00:00:00.000000000Z
12
+ date: 2012-04-29 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog
16
- requirement: &6754760 !ruby/object:Gem::Requirement
16
+ requirement: &6248380 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *6754760
24
+ version_requirements: *6248380
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: thor
27
- requirement: &6754100 !ruby/object:Gem::Requirement
27
+ requirement: &6247840 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,18 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *6754100
35
+ version_requirements: *6247840
36
+ - !ruby/object:Gem::Dependency
37
+ name: minitar
38
+ requirement: &6247360 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *6247360
36
47
  description: Blimpy is a tool for managing a fleet of machines in the CLOUD!
37
48
  email:
38
49
  - tyler@monkeypox.org
@@ -50,6 +61,7 @@ files:
50
61
  - blimpy.gemspec
51
62
  - features/cli/init.feature
52
63
  - features/cli/list.feature
64
+ - features/cli/scp.feature
53
65
  - features/cli/ssh.feature
54
66
  - features/cli/start.feature
55
67
  - features/step_definitions/cli_steps.rb
@@ -62,12 +74,14 @@ files:
62
74
  - lib/blimpy/fleet.rb
63
75
  - lib/blimpy/helpers/state.rb
64
76
  - lib/blimpy/keys.rb
77
+ - lib/blimpy/livery.rb
65
78
  - lib/blimpy/version.rb
66
79
  - spec/blimpy/box_spec.rb
67
80
  - spec/blimpy/engine_spec.rb
68
81
  - spec/blimpy/fleet_spec.rb
69
82
  - spec/blimpy/helpers/state_spec.rb
70
83
  - spec/blimpy/keys_spec.rb
84
+ - spec/blimpy/livery_spec.rb
71
85
  - spec/blimpy_spec.rb
72
86
  - spec/spec_helper.rb
73
87
  homepage: https://github.com/rtyler/blimpy
@@ -97,6 +111,7 @@ summary: Ruby + CLOUD = Blimpy
97
111
  test_files:
98
112
  - features/cli/init.feature
99
113
  - features/cli/list.feature
114
+ - features/cli/scp.feature
100
115
  - features/cli/ssh.feature
101
116
  - features/cli/start.feature
102
117
  - features/step_definitions/cli_steps.rb
@@ -107,5 +122,6 @@ test_files:
107
122
  - spec/blimpy/fleet_spec.rb
108
123
  - spec/blimpy/helpers/state_spec.rb
109
124
  - spec/blimpy/keys_spec.rb
125
+ - spec/blimpy/livery_spec.rb
110
126
  - spec/blimpy_spec.rb
111
127
  - spec/spec_helper.rb