screwcap 0.6.3 → 0.7

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/Rakefile CHANGED
@@ -11,7 +11,7 @@ Hoe.plugin :newgem
11
11
  # Generate all the Rake tasks
12
12
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
13
  $hoe = Hoe.spec 'screwcap' do
14
- self.version = '0.6.3'
14
+ self.version = '0.7'
15
15
  self.developer 'Grant Ammons', 'grant@pipelinedeals.com'
16
16
  self.rubyforge_name = self.name # TODO this is default value
17
17
  self.extra_deps = [['net-ssh','>= 2.0.23'],['net-ssh-gateway','>=1.0.1'], ['net-scp','>=1.0.4']]
data/bin/screwcap CHANGED
@@ -6,6 +6,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../lib/trollop')
6
6
 
7
7
  p = Trollop::Parser.new do
8
8
  opt :silent, "Be silent", :short => "s"
9
+ opt :verbose, "Be verbose", :short => "v"
9
10
  opt :nocolor, "Do not color output"
10
11
  opt :debug, "Turn on debugger. Will print full stacktrace if an exeception was raised", :short => "d"
11
12
  opt :help, "Show this message", :short => "h"
@@ -4,74 +4,80 @@ class Runner
4
4
 
5
5
  def self.execute! options
6
6
  @@silent = options[:silent]
7
- begin
8
- _log "\nExecuting task named #{options[:name]} on #{options[:server].name}..\n", :color => :blue
9
- options[:server].__with_connection_for(options[:address]) do |ssh|
10
- options[:commands].each do |command|
11
- ret = run_command(command, ssh, options)
12
- break if ret != 0 and command[:abort_on_fail] == true
13
- end
7
+ @@verbose = options[:verbose]
8
+ task = options[:task]
9
+
10
+ if (task.__servers.nil? or task.__servers == [] or task.__servers.compact == []) and task.__built_commands.any? {|c| c[:type] == :remote or c[:type] == :scp }
11
+ raise Screwcap::ConfigurationError, "The task #{task.name} includes remote commands, however no servers were defined for this task."
12
+ end
13
+
14
+ if options[:servers] and task.__servers
15
+ begin
16
+ servers = options[:servers].select {|s| task.__servers.include? s.__name }
17
+ connections = servers.map {|server| server.connect! }.flatten
18
+ rescue Net::SSH::AuthenticationFailed => e
19
+ raise Net::SSH::AuthenticationFailed, "Authentication failed for server named #{server.name}. Please check your authentication credentials."
14
20
  end
15
- rescue Net::SSH::AuthenticationFailed => e
16
- raise Net::SSH::AuthenticationFailed, "Authentication failed for server named #{server.name}. Please check your authentication credentials."
17
- ensure
18
- _log "\nComplete\n", :color => :blue
19
21
  end
20
- options[:commands] # for tests
21
- end
22
22
 
23
- def self.execute_locally! options
24
- @@silent = options[:silent]
25
- _log "\n*** BEGIN executing local task #{options[:name]}\n", :color => :blue
26
- options[:commands].each do |command|
27
- command[:stdout] = ret = `#{command[:command]}`
28
-
29
- if $?.to_i == 0
30
- _log " I: (local): #{command[:command]}\n", :color => :blue
31
- _log(" O: (local): #{ret}\n", :color => :blue) unless ret.nil? or ret == ""
32
- else
33
- _log " I: (local): #{command[:command]}\n", :color => :blue
34
- _errorlog(" O: (local): #{ret}\n", :color => :red) unless ret.nil? or ret == ""
35
- _errorlog(" E: (local): #{command[:command]} return exit code: #{$?}\n", :color => :red) if $? != 0
23
+ _log "\nExecuting task #{task.name}\n", :color => :blue
24
+
25
+ task.__built_commands.each do |command|
26
+ ret = case command[:type]
27
+ when :remote
28
+ threads = []
29
+ connections.each do |connection|
30
+ threads << Thread.new(connection) do |conn|
31
+ run_remote_command(command, conn, options)
32
+ end
33
+ end
34
+ threads.each {|t| t.join }
35
+ when :local
36
+ ret = `#{command[:command]}`
37
+ command[:stdout] = ret
38
+ if $?.to_i == 0
39
+ if options[:verbose]
40
+ _log " O: #{ret}\n", :color => :green
41
+ else
42
+ _log(".", :color => :green)
43
+ end
44
+ else
45
+ _errorlog(" E: (local): #{command[:command]} return exit code: #{$?}\n", :color => :red) if $? != 0
46
+ end
47
+ ret
48
+ when :scp
49
+ threads = []
50
+ servers.each do |server|
51
+ threads << Thread.new(server) { |_server| _server._upload! command[:local], command[:remote] }
52
+ end
53
+ thread.each {|t| t.join }
54
+ return 0
55
+ when :block
56
+ command[:block].call
36
57
  end
37
58
  end
38
- _log "\n*** END executing local task #{options[:name]}\n", :color => :blue
39
- options[:commands]
59
+ _log "Complete\n", :color => :blue
60
+ task.__built_commands # for tests
40
61
  end
41
62
 
42
63
  private
43
64
 
44
- def self.run_command(command, ssh, options)
45
- case command[:type]
46
- when :remote
47
- stdout, stderr, exit_code, exit_signal = ssh_exec! ssh, command[:command]
48
- command[:stdout] = stdout
49
- command[:stderr] = stderr
50
- command[:exit_code] = exit_code
51
- if exit_code == 0
52
- _log(".", :color => :green)
65
+ def self.run_remote_command(command, ssh, options)
66
+ stdout, stderr, exit_code, exit_signal = ssh_exec! ssh, command[:command]
67
+ command[:stdout] = stdout
68
+ command[:stderr] = stderr
69
+ command[:exit_code] = exit_code
70
+ if exit_code == 0
71
+ if @@verbose
72
+ _log(" I: #{command[:command]}\n", :color => :green)
73
+ _log(" O: #{command[:stdout]}\n", :color => :green)
53
74
  else
54
- _errorlog("\n E: (#{options[:address]}): #{command[:command]} return exit code: #{exit_code}\n", :color => :red) if exit_code != 0
55
- end
56
- return exit_code
57
- when :local
58
- ret = `#{command[:command]}`
59
- command[:stdout] = ret
60
- if $?.to_i == 0
61
75
  _log(".", :color => :green)
62
- else
63
- _errorlog("\n E: (local): #{command[:command]} return exit code: #{$?}\n", :color => :red) if $? != 0
64
76
  end
65
- return $?
66
- when :scp
67
- putc "."
68
- options[:server].__upload_to!(options[:address], command[:local], command[:remote])
69
-
70
- # this will need to be improved to allow for :onfailure
71
- return 0
72
- when :block
73
- command[:block].call
77
+ else
78
+ _errorlog(" E: (#{options[:address]}): #{command[:command]} return exit code: #{exit_code}\n", :color => :red) if exit_code != 0
74
79
  end
80
+ exit_code
75
81
  end
76
82
 
77
83
  # courtesy of flitzwald on stackoverflow
@@ -19,6 +19,7 @@ class Server < Screwcap::Base
19
19
 
20
20
  servers = opts.delete(:servers)
21
21
  self.__gateway = servers.select {|s| s.__options[:is_gateway] == true }.find {|s| s.__name == opts[:gateway] } if servers
22
+ self.__connections = []
22
23
 
23
24
  self.__options = opts
24
25
 
@@ -33,20 +34,21 @@ class Server < Screwcap::Base
33
34
  self
34
35
  end
35
36
 
36
- def __with_connection_for(address, &block)
37
- if self.__gateway
38
- __gateway.__get_gateway_connection.ssh(address, self.__user, options_for_net_ssh) do |ssh|
39
- yield ssh
40
- end
41
- else
42
- Net::SSH.start(address, self.__user, options_for_net_ssh) do |ssh|
43
- yield ssh
37
+ def connect!
38
+ self.__addresses.each do |address|
39
+ if self.__gateway
40
+ self.__connections << __gateway.__get_gateway_connection.ssh(address, self.__user, options_for_net_ssh)
41
+ else
42
+ self.__connections << Net::SSH.start(address, self.__user, options_for_net_ssh)
44
43
  end
45
44
  end
45
+ self.__connections
46
46
  end
47
47
 
48
- def __upload_to!(address, local, remote)
49
- self.__with_connection_for(address) {|ssh| ssh.scp.upload! local, remote }
48
+ def upload! (local, remote)
49
+ self.__connections.each do |conn|
50
+ conn.scp.upload! local, remote
51
+ end
50
52
  end
51
53
 
52
54
  protected
data/lib/screwcap/task.rb CHANGED
@@ -11,6 +11,7 @@ class Task < Screwcap::Base
11
11
  self.__servers = opts.delete(:servers)
12
12
  self.__callback = opts.delete(:callback)
13
13
  self.__block = block
14
+ self.__built_commands = []
14
15
 
15
16
  if self.__options[:before] and self.__options[:before].class != Array
16
17
  self.__options[:before] = [self.__options[:before]]
@@ -211,20 +212,13 @@ class Task < Screwcap::Base
211
212
  end
212
213
  end
213
214
 
214
- commands.flatten
215
+ commands.flatten!
216
+ self.__built_commands = commands
215
217
  end
216
218
 
217
219
  def validate(servers)
218
- raise Screwcap::ConfigurationError, "Could not find a server to run this task on. Please specify :server => :servername or :servers => [:server1, :server2] in the task_for directive." if servers == [] or servers.nil?
219
-
220
- # marshal :server into :servers
221
220
  self.__servers = [self.__options.delete(:server)] if self.__options[:server]
222
221
  self.__servers = [self.__servers] if self.__servers.class != Array
223
-
224
- server_names = servers.map {|s| s.__name }
225
- self.__servers.each do |server_name|
226
- raise Screwcap::ConfigurationError, "Could not find a server to run this task on. Please specify :server => :servername or :servers => [:server1, :server2] in the task_for directive." unless server_names.include?(server_name)
227
- end
228
222
  end
229
223
 
230
224
  private
@@ -10,7 +10,6 @@ class TaskManager < Screwcap::Base
10
10
  self.__options = opts
11
11
  self.__tasks = []
12
12
  self.__servers = []
13
- self.__command_sets = []
14
13
  self.__sequences = []
15
14
 
16
15
  instance_eval(File.read(self.__options[:recipe_file])) if self.__options[:recipe_file]
@@ -82,10 +81,11 @@ class TaskManager < Screwcap::Base
82
81
  def task name, options = {}, &block
83
82
  t = Task.new(options.merge(:name => name), &block)
84
83
  t.clone_from(self)
85
- t.validate(self.__servers) unless options[:local] == true
84
+ t.validate(self.__servers)
86
85
  self.__tasks << t
87
86
  end
88
87
  alias :task_for :task
88
+ alias :command_set :task
89
89
 
90
90
  # ====A *command set* is like a generic set of tasks that you intend to use in multiple tasks.
91
91
  #
@@ -114,12 +114,6 @@ class TaskManager < Screwcap::Base
114
114
  # redundant_task
115
115
  # end
116
116
 
117
- def command_set(name,options = {},&block)
118
- t = Task.new(options.merge(:name => name), &block)
119
- t.clone_from(self)
120
- self.__command_sets << t
121
- end
122
-
123
117
  # ====A *server* is the address(es) that you run a *:task* on.
124
118
  # server :myserver, :address => "abc.com", :password => "xxx"
125
119
  # server :app_servers, :addresses => ["abc.com","def.com"], :keys => "~/.ssh/my_key"
@@ -187,37 +181,12 @@ class TaskManager < Screwcap::Base
187
181
 
188
182
  ret = []
189
183
  tasks_to_run.each do |task|
190
- commands = task.__build_commands(self.__command_sets)
191
- if task.__options[:local] == true
192
- Runner.execute_locally! :commands => commands, :silent => self.__options[:silent]
193
- else
194
- threads = []
195
- self.__servers.select {|s| task.__servers.include? s.__name }.each do |server|
196
- server.__addresses.each do |address|
197
- if task.__options[:parallel] == false
198
- Runner.execute!(:name => task.__name,
199
- :commands => commands,
200
- :address => address,
201
- :server => server,
202
- :silent => self.__options[:silent])
203
- else
204
- threads << Thread.new(server,address) do |server, address|
205
- Runner.execute!(:name => task.__name,
206
- :commands => commands,
207
- :address => address,
208
- :server => server,
209
- :silent => self.__options[:silent])
210
- end
211
- end
212
- end
213
- end
214
- threads.each {|t| t.join }
215
- end
216
- ret << commands
184
+ ret << task.__build_commands(self.__tasks)
185
+ Runner.execute!(:task => task, :servers => self.__servers, :silent => self.__options[:silent], :verbose => self.__options[:verbose])
217
186
  end
218
187
 
219
188
  $stdout << "\033[0m"
220
- ret.flatten
189
+ ret.flatten # return this for tests
221
190
  end
222
191
 
223
192
  # ====Use will dynamically include another file into an existing configuration file.
data/lib/screwcap.rb CHANGED
@@ -16,7 +16,7 @@ require 'screwcap/sequence'
16
16
  require 'screwcap/task_manager'
17
17
 
18
18
  module Screwcap
19
- VERSION='0.6.3'
19
+ VERSION='0.7'
20
20
 
21
21
  class TaskNotFound < RuntimeError; end
22
22
  class NoServersDefined < Exception; end
data/screwcap.gemspec CHANGED
@@ -6,7 +6,7 @@ require 'bundler/version'
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "screwcap"
9
- s.version = "0.6.3"
9
+ s.version = "0.7"
10
10
  s.platform = Gem::Platform::RUBY
11
11
  s.author = "Grant Ammons"
12
12
  s.email = ["grant@pipelinedealsco.com"]
data/spec/runner_spec.rb CHANGED
@@ -8,15 +8,16 @@ describe "The Runner" do
8
8
  run "one"
9
9
  run "two"
10
10
  end
11
+ @task.__build_commands
12
+ @task.validate([@server])
11
13
  end
12
14
 
13
15
  it "should be able to execute commands on an address of a server" do
14
16
  Runner.stubs(:ssh_exec!).returns(["ok\n","",0,nil])
15
17
 
16
18
  commands = Runner.execute! :name => "test",
17
- :server => @server,
18
- :address => "fake.com",
19
- :commands => @task.__build_commands,
19
+ :servers => [@server],
20
+ :task => @task,
20
21
  :silent => true
21
22
 
22
23
  commands[0][:stderr].should == ""
@@ -27,25 +28,26 @@ describe "The Runner" do
27
28
  end
28
29
 
29
30
  it "should be able to handle error commands" do
30
- Runner.stubs(:ssh_exec!).returns(["ok\n","",0,nil]).then.returns(["","no\n",1,nil])
31
+ #Runner.stubs(:ssh_exec!).returns(["ok\n","",0,nil]).then.returns(["","no\n",1,nil])
32
+ Runner.stubs(:ssh_exec!).returns(["","no\n",1,nil])
31
33
  commands = Runner.execute! :name => "test",
32
- :server => @server,
33
- :address => "fake.com",
34
- :commands => @task.__build_commands,
34
+ :servers => [@server],
35
+ :task => @task,
35
36
  :silent => true
36
37
 
37
- commands[0][:stderr].should == ""
38
- commands[0][:stdout].should == "ok\n"
38
+ commands[0][:stderr].should == "no\n"
39
+ commands[0][:stdout].should == ""
39
40
 
40
41
  commands[1][:stderr].should == "no\n"
41
42
  commands[1][:stdout].should == ""
42
43
  end
43
44
 
44
45
  it "should be able to execute local commands" do
45
- task = Task.new :name => :localtest, :local => true do
46
- run "echo 'bongle'"
46
+ task = Task.new :name => :localtest do
47
+ local "echo 'bongle'"
47
48
  end
48
- commands = Runner.execute_locally! :name => :localtest, :commands => task.__build_commands, :silent => true
49
+ task.__build_commands
50
+ commands = Runner.execute! :name => :localtest, :task => task, :silent => true
49
51
  commands[0][:stdout].should == "bongle\n"
50
52
  end
51
53
 
@@ -54,11 +56,11 @@ describe "The Runner" do
54
56
  task = Task.new :name => :extest do
55
57
  ex { @@testvar = :bango }
56
58
  end
59
+ task.__build_commands
57
60
  @@testvar.should == :bingo
58
61
  commands = Runner.execute! :name => "test",
59
- :server => @server,
60
- :address => "fake.com",
61
- :commands => task.__build_commands,
62
+ :servers => [@server],
63
+ :task => task,
62
64
  :silent => true
63
65
  @@testvar.should == :bango
64
66
  end
data/spec/server_spec.rb CHANGED
@@ -27,6 +27,6 @@ describe "Servers" do
27
27
 
28
28
  it "should provide a connection to the server" do
29
29
  server = Server.new(:name => :test, :user => :root, :address => "abc.com")
30
- server.should respond_to(:__with_connection_for)
30
+ server.should respond_to(:connect!)
31
31
  end
32
32
  end
@@ -20,12 +20,6 @@ describe "Task Managers" do
20
20
  @tm.should have(1).__tasks
21
21
  end
22
22
 
23
- it "should validate tasks" do
24
- @tm = TaskManager.new
25
- @tm.server :server, :address => "test", :user => "root"
26
- lambda { @tm.task(:deploy, :server => :not_here) { run "test" } }.should raise_error(Screwcap::ConfigurationError)
27
- end
28
-
29
23
  it "should be able to define variables" do
30
24
  @tm.moon_pie= "moon pie"
31
25
  @tm.moon_pie.should == "moon pie"
@@ -46,14 +40,13 @@ describe "Task Managers" do
46
40
  run "test"
47
41
  end
48
42
 
49
- @tm.should have(1).__command_sets
43
+ @tm.should have(1).__tasks
50
44
  end
51
45
 
52
46
  it "should be able to load a recipe file" do
53
47
  @tm = TaskManager.new(:recipe_file => "test/config/super_simple_recipe.rb")
54
48
  @tm.pie.should == "moon pie"
55
- @tm.should have(1).__command_sets
56
- @tm.should have(1).__tasks
49
+ @tm.should have(2).__tasks
57
50
  end
58
51
 
59
52
  it "should be able to execute a recipe" do
@@ -70,13 +63,11 @@ describe "Task Managers" do
70
63
  it "should be able to include multiple recipe files in a single recipe" do
71
64
  @tm = TaskManager.new(:recipe_file => "test/config/use.rb")
72
65
  @tm.pie.should == "moon pie"
73
- @tm.should have(1).__command_sets
74
- @tm.should have(1).__tasks
66
+ @tm.should have(2).__tasks
75
67
 
76
68
  @tm = TaskManager.new(:recipe_file => "test/config/use2.rb")
77
69
  @tm.pie.should == "moon pie"
78
- @tm.should have(1).__command_sets
79
- @tm.should have(1).__tasks
70
+ @tm.should have(2).__tasks
80
71
  end
81
72
 
82
73
  it "will complain if it can't find the use file" do
data/spec/task_spec.rb CHANGED
@@ -27,6 +27,7 @@ describe "Tasks" do
27
27
  end
28
28
 
29
29
  commands = task.__build_commands([unknown])
30
+ task.__built_commands.should_not == []
30
31
  commands.size.should == 2
31
32
 
32
33
  commands[0][:type].should == :remote
@@ -133,21 +134,6 @@ describe "Tasks" do
133
134
  commands.map {|c| c[:command] }.should == ["deploy", "after"]
134
135
  end
135
136
 
136
- it "should validate" do
137
- task = Task.new :name => :test
138
- lambda { task.validate([]) }.should raise_error(Screwcap::ConfigurationError)
139
-
140
- server = Server.new :name => :server, :address => "none", :user => "yeah"
141
- other_server = Server.new :name => :server2, :address => "none", :user => "yeah"
142
- task = Task.new :name => :test, :server => :server
143
- lambda { task.validate([server]) }.should_not raise_error
144
- lambda { task.validate([other_server]) }.should raise_error(Screwcap::ConfigurationError)
145
- task = Task.new :name => :test, :servers => :server
146
- lambda { task.validate([server]) }.should_not raise_error
147
- task = Task.new :name => :test, :servers => [:server, :server2]
148
- lambda { task.validate([server,other_server]) }.should_not raise_error
149
- end
150
-
151
137
  it "should handle before and after inside a task" do
152
138
  do_other_task = Task.new :name => :other_task do
153
139
  run "task"
@@ -281,12 +267,30 @@ describe "Tasks" do
281
267
  end
282
268
 
283
269
  it "has an ex command" do
284
-
285
270
  task = Task.new :name => :task do
286
271
  @test = "asdf"
287
272
  ex { @test = "fdsa" }
288
273
  end
289
274
 
290
275
  commands = task.__build_commands([task])
276
+ commands[0][:type].should == :block
277
+ end
278
+
279
+ it "should be able to call other tasks" do
280
+ t1 = Task.new :name => :release_the_hounds do
281
+ run "release_the_hounds"
282
+ end
283
+
284
+ t2 = Task.new :name => :lock_the_gate do
285
+ run "lock_the_gate"
286
+ end
287
+
288
+ t3 = Task.new :name => :release_the_hounds_and_lock_the_gate do
289
+ release_the_hounds
290
+ lock_the_gate
291
+ end
292
+
293
+ commands = t3.__build_commands [t1, t2]
294
+ commands.map {|c| c[:command] }.should == %w(release_the_hounds lock_the_gate)
291
295
  end
292
296
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: screwcap
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
4
+ hash: 5
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 6
9
- - 3
10
- version: 0.6.3
8
+ - 7
9
+ version: "0.7"
11
10
  platform: ruby
12
11
  authors:
13
12
  - Grant Ammons
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2011-03-18 00:00:00 -04:00
17
+ date: 2011-03-29 00:00:00 -04:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency