butcher 0.1.0 → 1.0.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Gemfile +1 -0
- data/bin/stab +6 -45
- data/butcher.gemspec +1 -1
- data/features/stab.feature +26 -31
- data/features/step_definitions/pry_steps.rb +3 -0
- data/features/support/env.rb +1 -0
- data/features/support/mocha.rb +2 -2
- data/lib/butcher.rb +0 -1
- data/lib/butcher/cache.rb +11 -13
- data/lib/butcher/stab.rb +3 -1
- data/lib/butcher/stab/cli.rb +55 -22
- data/lib/butcher/version.rb +1 -1
- data/spec/lib/cache_spec.rb +15 -25
- data/spec/lib/stab/cli_spec.rb +116 -21
- data/spec/spec_helper.rb +1 -0
- data/spec/support/test_cache.rb +9 -10
- metadata +8 -6
- data/.rbenv-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df03308964023fc67e995645841fd7626c20cdbe
|
4
|
+
data.tar.gz: c56762d59d52c4fb9c7fe6dcc19726b03537aa64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55b204f81f80998fbbad7927faf6033162f03d8caad10a53df6101daeaa9c7e64202c1b49524d1bcd0f310f123592332c69867162596f47e3a35fdb93a37bf55
|
7
|
+
data.tar.gz: 91c194896fb1df3da4391628166c383271314f54ce93a92a085d4b6032a643c8f25f27cf298f2d6f7e7d522992b1bf49b498e38a968018e87dcc9efe03e1c6ea
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/bin/stab
CHANGED
@@ -5,56 +5,17 @@ require 'optparse'
|
|
5
5
|
|
6
6
|
EX_USAGE = 64
|
7
7
|
EX_UNMATCHED = 65
|
8
|
-
EX_AMBIGUOUS = 66
|
9
8
|
EX_KNIFE = 67
|
10
9
|
|
11
|
-
|
12
|
-
parser = OptionParser.new do |opts|
|
13
|
-
opts.banner = "Usage: stab [options] node_name"
|
14
|
-
|
15
|
-
opts.on('-c', '--cache-dir DIR', 'Location to save cache files (default: ~/.butcher/cache)') do |dir|
|
16
|
-
ENV["CACHE_DIR"] = dir
|
17
|
-
end
|
18
|
-
|
19
|
-
opts.on('-f', '--force', 'Check for new nodes even if a cache file exists') do
|
20
|
-
options[:force] = true
|
21
|
-
end
|
22
|
-
|
23
|
-
opts.on('-h', '--help', 'Display this screen') do
|
24
|
-
puts opts
|
25
|
-
exit
|
26
|
-
end
|
27
|
-
|
28
|
-
opts.on('-l', '--login LOGIN', 'Use LOGIN for ssh session') do |login|
|
29
|
-
options[:login] = login
|
30
|
-
end
|
31
|
-
|
32
|
-
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
33
|
-
options[:verbose] = v
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
begin parser.parse!
|
38
|
-
rescue OptionParser::InvalidOption => e
|
39
|
-
puts e
|
40
|
-
puts parser
|
41
|
-
exit EX_USAGE
|
42
|
-
end
|
43
|
-
|
44
|
-
if ARGV == []
|
45
|
-
puts parser
|
46
|
-
exit EX_USAGE
|
47
|
-
end
|
48
|
-
|
10
|
+
runner = Butcher::Stab::CLI.new(ARGV)
|
49
11
|
begin
|
50
|
-
|
12
|
+
runner.execute!
|
13
|
+
rescue Butcher::Stab::UsageError => e
|
14
|
+
STDERR.puts e.message
|
15
|
+
exit EX_USAGE
|
51
16
|
rescue Butcher::UnmatchedNode
|
52
|
-
STDERR.puts %Q{Unable to find node "#{
|
17
|
+
STDERR.puts %Q{Unable to find node "#{runner.node_name}"}
|
53
18
|
exit EX_UNMATCHED
|
54
|
-
rescue Butcher::AmbiguousNode => e
|
55
|
-
STDERR.puts %Q{Multiple nodes match "#{ARGV.first}"}
|
56
|
-
STDERR.puts e.message
|
57
|
-
exit EX_AMBIGUOUS
|
58
19
|
rescue Butcher::NoKnifeRB
|
59
20
|
STDERR.puts "Unable to find knife.rb in ./.chef"
|
60
21
|
STDERR.puts "Are you stabbing from a valid working chef directory?"
|
data/butcher.gemspec
CHANGED
data/features/stab.feature
CHANGED
@@ -16,7 +16,7 @@ Feature: Stab
|
|
16
16
|
Then the exit status should be 0
|
17
17
|
And the output should contain:
|
18
18
|
"""
|
19
|
-
Usage: stab [options]
|
19
|
+
Usage: stab [options] <node name> [ssh options]
|
20
20
|
"""
|
21
21
|
|
22
22
|
Scenario: Usage information when no node name is given
|
@@ -24,49 +24,35 @@ Feature: Stab
|
|
24
24
|
Then the exit status should be 64
|
25
25
|
And the output should contain:
|
26
26
|
"""
|
27
|
-
Usage: stab [options]
|
27
|
+
Usage: stab [options] <node name> [ssh options]
|
28
28
|
"""
|
29
29
|
|
30
|
-
Scenario: Invalid option
|
31
|
-
When I run `stab --invalid-option`
|
32
|
-
Then the exit status should be 64
|
33
|
-
And the output should contain:
|
34
|
-
"""
|
35
|
-
invalid option: --invalid-option
|
36
|
-
Usage: stab [options] node_name
|
37
|
-
"""
|
38
|
-
|
39
|
-
Scenario: Set cache directory
|
40
|
-
Given a directory named "tmp/test_dir" should not exist
|
41
|
-
When I run `stab app.node -c tmp/test_dir`
|
42
|
-
Then a directory named "tmp/test_dir" should exist
|
43
|
-
|
44
30
|
Scenario: Tell user what IP address ssh uses
|
45
31
|
Given I have the following chef nodes:
|
46
32
|
| 1 minute ago | app.node | app.domain | 1.1.1.1 | os |
|
47
|
-
When I run `stab app.node -
|
33
|
+
When I run `stab app.node -v`
|
48
34
|
Then the output should contain "Connecting to app.node at 1.1.1.1"
|
49
35
|
Then the output should contain "ssh yay!"
|
50
36
|
|
51
37
|
Scenario: Don't download node list if already cached
|
52
38
|
Given I have the following chef nodes:
|
53
39
|
| 1 minute ago | app.node | app.domain | 1.1.1.1 | os |
|
54
|
-
Then a file named "tmp/test/my_organization.cache" should exist
|
55
|
-
When I run `stab app.node -
|
40
|
+
Then a file named "tmp/test/.butcher/cache/my_organization.cache" should exist
|
41
|
+
When I run `stab app.node -v`
|
56
42
|
Then the output should not contain "Creating cache file of nodes"
|
57
43
|
|
58
44
|
Scenario: Force download of cache file
|
59
45
|
Given I have the following chef nodes:
|
60
46
|
| 1 minute ago | app.node | app.domain | 1.1.1.1 | os |
|
61
|
-
When I run `stab app.node -
|
47
|
+
When I run `stab app.node -f -v`
|
62
48
|
Then the output should contain "Creating cache file of nodes"
|
63
|
-
And the double `knife status` should have been run
|
64
49
|
And the exit status should be 0
|
50
|
+
And the double `knife status` should have been run
|
65
51
|
|
66
52
|
Scenario: User sees error message if no node matches given name
|
67
53
|
Given I have the following chef nodes:
|
68
54
|
| 1 minute ago | app.node | app.domain | 1.1.1.1 | os |
|
69
|
-
When I run `stab some.node
|
55
|
+
When I run `stab some.node`
|
70
56
|
Then the stderr should contain:
|
71
57
|
"""
|
72
58
|
Unable to find node "some.node"
|
@@ -77,14 +63,16 @@ Feature: Stab
|
|
77
63
|
Given I have the following chef nodes:
|
78
64
|
| 1 minute ago | other.node | other.domain | 1.1.1.2 | os |
|
79
65
|
| 1 minute ago | app.node | app.domain | 1.1.1.1 | os |
|
80
|
-
|
81
|
-
|
66
|
+
And I double `ssh 1.1.1.2`
|
67
|
+
When I run `stab node` interactively
|
68
|
+
And I type "2"
|
69
|
+
Then the stdout should contain:
|
82
70
|
"""
|
83
|
-
|
84
|
-
|
85
|
-
["other.node", "other.domain"] => 1.1.1.2
|
71
|
+
1 "app.node" => 1.1.1.1
|
72
|
+
2 "other.node" => 1.1.1.2
|
86
73
|
"""
|
87
|
-
|
74
|
+
Then the exit status should be 0
|
75
|
+
And the double `ssh 1.1.1.2` should have been run
|
88
76
|
|
89
77
|
Scenario: User can connect to server with given user name
|
90
78
|
Given I have the following chef nodes:
|
@@ -93,15 +81,22 @@ Feature: Stab
|
|
93
81
|
"""
|
94
82
|
user: I'm a computer!
|
95
83
|
"""
|
96
|
-
When I run `stab app.node -
|
84
|
+
When I run `stab app.node -l user`
|
97
85
|
Then the stdout should contain:
|
98
86
|
"""
|
99
87
|
user: I'm a computer!
|
100
88
|
"""
|
101
89
|
|
90
|
+
Scenario: Arbitrary command line options are passed to ssh
|
91
|
+
Given I have the following chef nodes:
|
92
|
+
| 1 minute ago | app.node | app.domain | 1.1.1.1 | os |
|
93
|
+
Given I double `ssh 1.1.1.1 -l user --arrrh`
|
94
|
+
When I run `stab app.node -l user --arrrh`
|
95
|
+
Then the double `ssh 1.1.1.1 -l user --arrrh` should have been run
|
96
|
+
|
102
97
|
Scenario: User sees error message if knife.rb cannot be found
|
103
98
|
Given I don't have a knife configuration file
|
104
|
-
When I run `stab app.node
|
99
|
+
When I run `stab app.node`
|
105
100
|
Then the stderr should contain:
|
106
101
|
"""
|
107
102
|
Unable to find knife.rb in ./.chef
|
@@ -111,7 +106,7 @@ Feature: Stab
|
|
111
106
|
|
112
107
|
Scenario: User sees error message if knife.rb is invalid
|
113
108
|
Given I have an invalid knife configuration file
|
114
|
-
When I run `stab app.node
|
109
|
+
When I run `stab app.node`
|
115
110
|
Then the stderr should contain:
|
116
111
|
"""
|
117
112
|
Unable to read organization from knife.rb
|
data/features/support/env.rb
CHANGED
data/features/support/mocha.rb
CHANGED
data/lib/butcher.rb
CHANGED
data/lib/butcher/cache.rb
CHANGED
@@ -4,32 +4,29 @@ require 'chef/config'
|
|
4
4
|
class Butcher::Cache
|
5
5
|
include Singleton
|
6
6
|
|
7
|
-
CACHE_DIR = "#{ENV["HOME"]}/.butcher/cache"
|
8
7
|
KNIFE_FILE = ".chef/knife.rb"
|
9
8
|
|
10
|
-
def initialize
|
11
|
-
FileUtils.mkdir_p(cache_dir)
|
12
|
-
end
|
13
|
-
|
14
9
|
def nodes(options = {})
|
15
|
-
|
10
|
+
n = []
|
16
11
|
cache_file(options) do |file|
|
17
12
|
while file.gets
|
18
13
|
node = $_.split(", ")
|
19
|
-
|
14
|
+
n << {:ip => node[3], :name => node[1], :fqdn => node[2]}
|
20
15
|
end
|
21
16
|
end
|
22
|
-
|
17
|
+
n.sort{ |a,b| a[:name] <=> b[:name] }
|
23
18
|
end
|
24
19
|
|
25
20
|
def cache_dir # :nodoc:
|
26
|
-
ENV["
|
21
|
+
"#{ENV["HOME"]}/.butcher/cache"
|
27
22
|
end
|
28
23
|
|
29
|
-
def self.
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
def self.formatted_nodes_for_output(nodes)
|
25
|
+
i = 0
|
26
|
+
nodes.map do |node|
|
27
|
+
i += 1
|
28
|
+
sprintf("%- 5d %p => %s", i, node[:name], node[:ip])
|
29
|
+
end.join("\n")
|
33
30
|
end
|
34
31
|
|
35
32
|
def nodes_file
|
@@ -54,6 +51,7 @@ class Butcher::Cache
|
|
54
51
|
|
55
52
|
def create_node_cachefile
|
56
53
|
with_safe_paths do
|
54
|
+
FileUtils.mkdir_p(cache_dir)
|
57
55
|
File.open(nodes_file, "w") do |file|
|
58
56
|
file.puts %x[knife status]
|
59
57
|
end
|
data/lib/butcher/stab.rb
CHANGED
data/lib/butcher/stab/cli.rb
CHANGED
@@ -1,38 +1,71 @@
|
|
1
1
|
class Butcher::Stab::CLI
|
2
|
-
attr_accessor :
|
3
|
-
attr_accessor :options
|
2
|
+
attr_accessor :argv, :options, :stdin, :stdout, :stderr, :kernel
|
4
3
|
|
5
|
-
def
|
6
|
-
self.
|
7
|
-
self.
|
8
|
-
|
4
|
+
def initialize(argv, stdin=STDIN, stdout=STDOUT, stderr=STDERR, kernel=Kernel)
|
5
|
+
self.argv = argv
|
6
|
+
self.stdin = stdin
|
7
|
+
self.stdout = stdout
|
8
|
+
self.stderr = stderr
|
9
|
+
self.kernel = kernel
|
10
|
+
self.options = {}
|
11
|
+
optparse
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute!
|
15
|
+
return stdout.puts(usage) if options[:help]
|
16
|
+
raise Butcher::Stab::UsageError.new(usage) if node_name.nil?
|
9
17
|
|
10
18
|
ssh_to(matching_node)
|
11
19
|
end
|
12
20
|
|
13
|
-
|
21
|
+
def node_name
|
22
|
+
@node_name ||= argv.shift
|
23
|
+
end
|
14
24
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
def usage
|
26
|
+
<<-END.gsub(/^ {6}/, '')
|
27
|
+
Usage: stab [options] <node name> [ssh options]
|
28
|
+
-f --force # download new node list even if a cache file exists
|
29
|
+
-v --verbose # be expressive
|
30
|
+
-h --help # print this info
|
31
|
+
END
|
19
32
|
end
|
20
33
|
|
34
|
+
private
|
35
|
+
|
21
36
|
def matching_node
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
37
|
+
@node ||= begin
|
38
|
+
nodes = Butcher::Cache.instance.nodes(options).reject do |node|
|
39
|
+
! node[:name].include? self.node_name
|
40
|
+
end
|
41
|
+
|
42
|
+
raise(Butcher::UnmatchedNode) if nodes.size == 0
|
26
43
|
|
27
|
-
|
28
|
-
|
29
|
-
|
44
|
+
if nodes.size > 1
|
45
|
+
stdout.puts Butcher::Cache.formatted_nodes_for_output(nodes)
|
46
|
+
stdout.write "\n which server? > "
|
47
|
+
begin
|
48
|
+
choice = stdin.gets.chomp.to_i - 1
|
49
|
+
rescue Interrupt
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
else
|
53
|
+
choice = 0
|
54
|
+
end
|
55
|
+
|
56
|
+
nodes[choice]
|
30
57
|
end
|
31
58
|
end
|
32
59
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
60
|
+
def optparse
|
61
|
+
options[:force] = !(argv.delete("--force") || argv.delete("-f")).nil?
|
62
|
+
options[:verbose] = !(argv.delete("--verbose") || argv.delete("-v")).nil?
|
63
|
+
options[:help] = !(argv.delete("--help") || argv.delete("-h")).nil?
|
64
|
+
end
|
65
|
+
|
66
|
+
def ssh_to(node)
|
67
|
+
STDOUT.sync = true # exec takes over stdout in tests, so sync output
|
68
|
+
puts "Connecting to #{node[:name]} at #{node[:ip]}" if options[:verbose]
|
69
|
+
exec("ssh #{[node[:ip], argv].flatten.join(' ')}")
|
37
70
|
end
|
38
71
|
end
|
data/lib/butcher/version.rb
CHANGED
data/spec/lib/cache_spec.rb
CHANGED
@@ -1,26 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Butcher::Cache, "initialization" do
|
4
|
-
## singletons do not reset after initialization, so we run tests against clones
|
5
|
-
|
6
|
-
class CacheSingletonForEnv < Butcher::Cache; end
|
7
|
-
it "should accept cache_dir from env" do
|
8
|
-
ENV["CACHE_DIR"] = "tmp/cache_from_options"
|
9
|
-
test(?d, "tmp/cache_from_options").should be_false
|
10
|
-
CacheSingletonForEnv.instance
|
11
|
-
ENV["CACHE_DIR"] = nil
|
12
|
-
test(?d, "tmp/cache_from_options").should be_true
|
13
|
-
end
|
14
|
-
|
15
|
-
class CacheSingleton < Butcher::Cache; end
|
16
|
-
it "should create cache directory" do
|
17
|
-
CacheSingleton.any_instance.stubs(:cache_dir).returns("tmp/cache_stub")
|
18
|
-
test(?d, "tmp/cache_stub").should be_false
|
19
|
-
CacheSingleton.instance
|
20
|
-
test(?d, "tmp/cache_stub").should be_true
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
3
|
describe Butcher::Cache, "#nodes_file" do
|
25
4
|
context "cannot find knife.rb" do
|
26
5
|
it "should raise an error" do
|
@@ -89,10 +68,21 @@ describe Butcher::Cache, "#nodes" do
|
|
89
68
|
end
|
90
69
|
|
91
70
|
it "maps file to hash" do
|
92
|
-
Butcher::Cache.instance.nodes.should ==
|
93
|
-
"192.168.1.1" =>
|
94
|
-
"192.168.1.2" =>
|
95
|
-
|
71
|
+
Butcher::Cache.instance.nodes.should == [
|
72
|
+
{:ip => "192.168.1.1", :name => "app.node", :fqdn => "app.domain.com"},
|
73
|
+
{:ip => "192.168.1.2", :name => "other.node", :fqdn => "other.domain.com"}
|
74
|
+
]
|
96
75
|
end
|
97
76
|
end
|
98
77
|
end
|
78
|
+
|
79
|
+
describe Butcher::Cache, '.formatted_nodes_for_output' do
|
80
|
+
it 'returns node info in a numbered list' do
|
81
|
+
nodes = [
|
82
|
+
{:ip => "123.4.5.6", :name => "node1", :fqdn => "node1.prod"},
|
83
|
+
{:ip => "901.4.5.6", :name => "node2", :fqdn => "node2.prod"}
|
84
|
+
]
|
85
|
+
expect(Butcher::Cache.formatted_nodes_for_output(nodes)).
|
86
|
+
to eql(%Q{ 1 "node1" => 123.4.5.6\n 2 "node2" => 901.4.5.6})
|
87
|
+
end
|
88
|
+
end
|
data/spec/lib/stab/cli_spec.rb
CHANGED
@@ -1,60 +1,155 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Butcher::Stab::CLI do
|
3
|
+
describe Butcher::Stab::CLI, 'option parsing' do
|
4
|
+
let(:cli) { Butcher::Stab::CLI.new(args) }
|
5
|
+
let(:options) { cli.options }
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
7
|
+
describe 'defaults' do
|
8
|
+
let(:args) { [''] }
|
9
|
+
it "sets :force to false" do
|
10
|
+
expect(options[:force]).to be_false
|
11
|
+
end
|
12
|
+
|
13
|
+
it "sets :verbose to false" do
|
14
|
+
expect(options[:verbose]).to be_false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "sets :help to false" do
|
18
|
+
expect(options[:help]).to be_false
|
8
19
|
end
|
9
20
|
end
|
10
21
|
|
11
|
-
|
12
|
-
|
13
|
-
|
22
|
+
describe '--force' do
|
23
|
+
context 'long' do
|
24
|
+
let(:args) { ["--force"] }
|
25
|
+
it "sets option :force to true" do
|
26
|
+
expect(options[:force]).to be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "short" do
|
31
|
+
let(:args) { ["-f"] }
|
32
|
+
it "sets option :force to true" do
|
33
|
+
expect(options[:force]).to be_true
|
34
|
+
end
|
14
35
|
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '--verbose' do
|
39
|
+
context 'long' do
|
40
|
+
let(:args) { ["--verbose"] }
|
41
|
+
it "sets option :verbose to true" do
|
42
|
+
expect(options[:verbose]).to be_true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'short' do
|
47
|
+
let(:args) { ["-v"] }
|
48
|
+
it "sets option :verbose to true" do
|
49
|
+
expect(options[:verbose]).to be_true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '--help' do
|
55
|
+
context 'long' do
|
56
|
+
let(:args) { ['--help']}
|
57
|
+
it "sets :help to true" do
|
58
|
+
expect(options[:help]).to be_true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'short' do
|
63
|
+
let(:args) { ['-h']}
|
64
|
+
it "sets :help to true" do
|
65
|
+
expect(options[:help]).to be_true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe Butcher::Stab::CLI, '#usage' do
|
72
|
+
it 'returns usage info' do
|
73
|
+
expect(Butcher::Stab::CLI.new([]).usage).to eql(<<-END.gsub(/^ {6}/, ''))
|
74
|
+
Usage: stab [options] <node name> [ssh options]
|
75
|
+
-f --force # download new node list even if a cache file exists
|
76
|
+
-v --verbose # be expressive
|
77
|
+
-h --help # print this info
|
78
|
+
END
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe Butcher::Stab::CLI, '#execute!' do
|
83
|
+
context 'when :help is true' do
|
84
|
+
let(:stdout) { mock() }
|
85
|
+
let(:runner) { Butcher::Stab::CLI.new([], mock, stdout) }
|
86
|
+
|
87
|
+
it 'writes usage and exits' do
|
88
|
+
runner.options[:help] = true
|
89
|
+
stdout.expects(:puts).with(runner.usage)
|
90
|
+
runner.execute!
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "when arguments are empty" do
|
95
|
+
it "raises a Usage error" do
|
96
|
+
runner = Butcher::Stab::CLI.new([])
|
97
|
+
expect { runner.execute! }.to raise_error(Butcher::Stab::UsageError, runner.usage)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "node cache file exists" do
|
102
|
+
let(:nodes) {
|
103
|
+
[
|
104
|
+
{:ip => "10.1.1.1", :name => 'app.node', :fqdn => 'app.node.com'},
|
105
|
+
{:ip => "10.1.1.2", :name => 'other.node', :fqdn => 'other.node.com'}
|
106
|
+
]
|
107
|
+
}
|
108
|
+
before { Butcher::Cache.any_instance.stubs(:nodes).returns(nodes) }
|
15
109
|
|
16
110
|
context "stabbing an existing node" do
|
17
111
|
it "should open an SSH session to named node" do
|
18
112
|
Butcher::Stab::CLI.any_instance.expects(:exec).with("ssh 10.1.1.1").returns(true).once
|
19
|
-
Butcher::Stab::CLI.new
|
113
|
+
Butcher::Stab::CLI.new(['app']).execute!
|
20
114
|
end
|
21
115
|
|
22
116
|
it "should ssh to IP based on matched node" do
|
23
117
|
Butcher::Stab::CLI.any_instance.expects(:exec).with("ssh 10.1.1.1").never
|
24
118
|
Butcher::Stab::CLI.any_instance.expects(:exec).with("ssh 10.1.1.2").returns(true).once
|
25
|
-
Butcher::Stab::CLI.new
|
119
|
+
Butcher::Stab::CLI.new(["other"]).execute!
|
26
120
|
end
|
27
121
|
end
|
28
122
|
|
29
123
|
context "stabbing a non-existing node" do
|
30
124
|
it "should raise an UnmatchedNode error" do
|
31
125
|
Butcher::Stab::CLI.any_instance.expects(:exec).never
|
32
|
-
|
33
|
-
Butcher::Stab::CLI.new
|
34
|
-
}.
|
126
|
+
expect {
|
127
|
+
Butcher::Stab::CLI.new(["nil.node"]).execute!
|
128
|
+
}.to raise_error(Butcher::UnmatchedNode)
|
35
129
|
end
|
36
130
|
end
|
37
131
|
|
38
132
|
context "ambiguous stabbing" do
|
39
|
-
it "
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
133
|
+
it "asks the user which server to connect to" do
|
134
|
+
stdin = mock(:gets => "2")
|
135
|
+
stdout = mock(:puts => Butcher::Cache.formatted_nodes_for_output(nodes), :write => "\n which server? > ")
|
136
|
+
Butcher::Stab::CLI.any_instance.expects(:exec).with("ssh 10.1.1.2").returns(true).once
|
137
|
+
|
138
|
+
Butcher::Stab::CLI.new(["node"], stdin, stdout).execute!
|
44
139
|
end
|
45
140
|
end
|
46
141
|
end
|
47
142
|
|
48
|
-
context "options" do
|
143
|
+
context "ssh options" do
|
49
144
|
mock_cache(:nodes) do
|
50
|
-
{"10.1.1.1" =>
|
145
|
+
[{:ip => "10.1.1.1", :name => 'app.node', :fqdn => 'app.node.com'}]
|
51
146
|
end
|
52
147
|
|
53
148
|
describe ":login" do
|
54
149
|
it "should include login in ssh params" do
|
55
150
|
Butcher::Stab::CLI.any_instance.expects(:exec).with("ssh 10.1.1.1 -l username").returns(true).once
|
56
|
-
Butcher::Stab::CLI.new
|
151
|
+
Butcher::Stab::CLI.new(["app", "-l", "username"]).execute!
|
57
152
|
end
|
58
153
|
end
|
59
154
|
end
|
60
|
-
end
|
155
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/test_cache.rb
CHANGED
@@ -20,7 +20,8 @@
|
|
20
20
|
# World(Butcher::TestCache::TestHelpers)
|
21
21
|
#
|
22
22
|
module Butcher::TestCache
|
23
|
-
PWD = ENV[
|
23
|
+
PWD = ENV['PWD']
|
24
|
+
HOME = ENV['HOME']
|
24
25
|
|
25
26
|
def self.setup_rspec(config)
|
26
27
|
config.before(:each) do
|
@@ -42,26 +43,23 @@ module Butcher::TestCache
|
|
42
43
|
|
43
44
|
def self.cleanup # :nodoc:
|
44
45
|
FileUtils.rm_rf("tmp")
|
45
|
-
ENV
|
46
|
-
ENV[
|
46
|
+
ENV['PWD'] = PWD
|
47
|
+
ENV['HOME'] = HOME
|
47
48
|
end
|
48
49
|
|
49
50
|
def self.cache_dir # :nodoc:
|
50
|
-
File.expand_path("tmp/test")
|
51
|
+
File.expand_path("tmp/test/.butcher/cache")
|
51
52
|
end
|
52
53
|
|
53
54
|
private
|
54
55
|
|
55
56
|
def self.setup
|
56
|
-
|
57
|
-
|
57
|
+
pwd = "#{PWD}/tmp/test"
|
58
|
+
ENV["PWD"] = pwd
|
59
|
+
ENV['HOME'] = pwd
|
58
60
|
FileUtils.mkdir_p("tmp/test")
|
59
61
|
end
|
60
62
|
|
61
|
-
def self.stub_cache
|
62
|
-
ENV["CACHE_DIR"] = cache_dir
|
63
|
-
end
|
64
|
-
|
65
63
|
public
|
66
64
|
|
67
65
|
# == RSpecExampleHelpers
|
@@ -106,6 +104,7 @@ module Butcher::TestCache
|
|
106
104
|
|
107
105
|
# Creates a file that Butcher::Cache can parse
|
108
106
|
def create_cache_file(filename)
|
107
|
+
FileUtils.mkdir_p(Butcher::TestCache.cache_dir)
|
109
108
|
File.open("#{Butcher::TestCache.cache_dir}/#{filename}", "w") do |file|
|
110
109
|
yield file
|
111
110
|
end
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: butcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Saxby
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '10.14'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '10.14'
|
27
27
|
description: Chef is a tool for managing server automation. A good butcher makes for
|
@@ -34,7 +34,6 @@ extensions: []
|
|
34
34
|
extra_rdoc_files: []
|
35
35
|
files:
|
36
36
|
- .gitignore
|
37
|
-
- .rbenv-version
|
38
37
|
- .rspec
|
39
38
|
- .travis.yml
|
40
39
|
- Gemfile
|
@@ -46,6 +45,7 @@ files:
|
|
46
45
|
- butcher.gemspec
|
47
46
|
- features/stab.feature
|
48
47
|
- features/step_definitions/chef_steps.rb
|
48
|
+
- features/step_definitions/pry_steps.rb
|
49
49
|
- features/support/aruba.rb
|
50
50
|
- features/support/env.rb
|
51
51
|
- features/support/mocha.rb
|
@@ -78,13 +78,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
78
|
version: '0'
|
79
79
|
requirements: []
|
80
80
|
rubyforge_project: butcher
|
81
|
-
rubygems_version: 2.0.
|
81
|
+
rubygems_version: 2.0.3
|
82
82
|
signing_key:
|
83
83
|
specification_version: 4
|
84
84
|
summary: All the things to make a chef
|
85
85
|
test_files:
|
86
86
|
- features/stab.feature
|
87
87
|
- features/step_definitions/chef_steps.rb
|
88
|
+
- features/step_definitions/pry_steps.rb
|
88
89
|
- features/support/aruba.rb
|
89
90
|
- features/support/env.rb
|
90
91
|
- features/support/mocha.rb
|
@@ -93,3 +94,4 @@ test_files:
|
|
93
94
|
- spec/lib/stab/cli_spec.rb
|
94
95
|
- spec/spec_helper.rb
|
95
96
|
- spec/support/test_cache.rb
|
97
|
+
has_rdoc:
|
data/.rbenv-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.0.0-p195
|