pawnee 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/docs/TODO.md +27 -3
- data/lib/pawnee/pawnee/actions/compile.rb +3 -1
- data/lib/pawnee/pawnee/actions/inject_into_file.rb +3 -0
- data/lib/pawnee/pawnee/actions/package.rb +3 -2
- data/lib/pawnee/pawnee/actions/user.rb +1 -1
- data/lib/pawnee/pawnee/base.rb +56 -45
- data/lib/pawnee/pawnee/cli.rb +2 -7
- data/lib/pawnee/pawnee/templates/newgem/lib/pawnee/newgem/base.rb.tt +1 -10
- data/lib/pawnee/pawnee/version.rb +1 -1
- data/spec/actions/compile_spec.rb +7 -3
- data/spec/actions/user_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +4 -6
- data/spec/vagrant/.vagrant +0 -1
data/.gitignore
CHANGED
data/docs/TODO.md
CHANGED
@@ -6,10 +6,7 @@ TODO: Add a as_user('user') do .. end option
|
|
6
6
|
- maybe have an option to run from within a shell, or we could get them into the right place every time
|
7
7
|
- maybe we should add a system to "get you to root, then get you to another user"
|
8
8
|
TODO: Need to make a clear way for pawnee gems (and recipes) to provide actions (example, git gem provides git actions)
|
9
|
-
TODO: Run actions in threads (across multiple servers)
|
10
9
|
TODO: Test to make sure arguments work directly as well (they probably don't right now)
|
11
|
-
TODO: System to check for and register updates/modifications
|
12
|
-
TODO: Add apt-get update to package stuff - make it only run update once per all jobs
|
13
10
|
TODO: Make it so copied files can be overridden in a rails project
|
14
11
|
TODO: Track modified on compile?
|
15
12
|
TODO: Should setup self.source_root to point to the templates dir in the gem
|
@@ -17,6 +14,33 @@ TODO: Add --verbose option that shows the output of any outputs (bundler for exa
|
|
17
14
|
- maybe show stderr by default?
|
18
15
|
- maybe option to show on run/exec
|
19
16
|
- show stderr when there's a non-0 exit status
|
17
|
+
TODO: Make sure it would print out any errors from bundler
|
18
|
+
TODO: Raise error on run error (with options to ignore during run, or options to always ignore (global config))
|
19
|
+
TODO: Allow ssh host strings user:pw@domain
|
20
|
+
TODO: Make thor-ssh local api compatible
|
21
|
+
TODO: Move to self namespacing - remove global_options
|
22
|
+
TODO: Work out dependency loading
|
23
|
+
TODO: Make the source_root work by default
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
THINK ABOUT:
|
28
|
+
|
29
|
+
---- logging system -----
|
30
|
+
|
31
|
+
Log levels
|
32
|
+
- error - stderr
|
33
|
+
- info - actions
|
34
|
+
- debug - stdout
|
35
|
+
|
36
|
+
State Changes (and colors):
|
37
|
+
- create (green)
|
38
|
+
- update (yellow)
|
39
|
+
- destroy (red?)
|
40
|
+
- identical (blue)
|
41
|
+
|
42
|
+
Log Actions
|
43
|
+
same, identical, update, add, run
|
20
44
|
|
21
45
|
|
22
46
|
def setup
|
@@ -35,7 +35,7 @@ module Pawnee
|
|
35
35
|
installed = false
|
36
36
|
if options[:bin_file]
|
37
37
|
# Check if the bin file is installed
|
38
|
-
installed = exec("which #{options[:bin_file]}").strip != ''
|
38
|
+
installed = exec("which #{options[:bin_file]}", :log_stderr => false).strip != ''
|
39
39
|
else
|
40
40
|
raise "You must pass :bin_file or a block to compile" unless block_given?
|
41
41
|
installed = yield()
|
@@ -45,6 +45,8 @@ module Pawnee
|
|
45
45
|
say_status :already_compiled, url, :blue
|
46
46
|
return true
|
47
47
|
else
|
48
|
+
|
49
|
+
track_modification!
|
48
50
|
# Compile and install
|
49
51
|
Compile.new(self, url, temp_dir, options)
|
50
52
|
end
|
@@ -10,6 +10,9 @@ module Pawnee
|
|
10
10
|
data, config = args.shift, args.shift
|
11
11
|
end
|
12
12
|
|
13
|
+
# Get the data if its a proc
|
14
|
+
data = data.call if data.is_a?(Proc)
|
15
|
+
|
13
16
|
if destination_files.binread(destination)[data]
|
14
17
|
say_status :identical, destination
|
15
18
|
# Don't run again, the text is already in place
|
@@ -74,8 +74,9 @@ module Pawnee
|
|
74
74
|
# to prevent this from happening too much.
|
75
75
|
def update_package_list
|
76
76
|
# TODO: this needs to be per server
|
77
|
-
unless defined?(@@packages_updated)
|
78
|
-
@@packages_updated
|
77
|
+
unless defined?(@@packages_updated) && @@packages_updated[server]
|
78
|
+
@@packages_updated ||= {}
|
79
|
+
@@packages_updated[server] = true
|
79
80
|
as_root do
|
80
81
|
exec('DEBIAN_FRONTEND=noninteractive apt-get -q -y update', :no_pty => true)
|
81
82
|
end
|
@@ -110,7 +110,7 @@ module Pawnee
|
|
110
110
|
|
111
111
|
# Reject any ones we just changed, so its as if we did a find with these
|
112
112
|
@changed_attributes = @changed_attributes.reject {|k,v| [:uid, :gid, :groups, :login].include?(k.to_sym) }
|
113
|
-
@original_groups_value = @groups
|
113
|
+
@original_groups_value = @groups.dup
|
114
114
|
else
|
115
115
|
# No user
|
116
116
|
@uid = nil
|
data/lib/pawnee/pawnee/base.rb
CHANGED
@@ -25,7 +25,7 @@ module Pawnee
|
|
25
25
|
include Pawnee::SshConnection
|
26
26
|
include Roles
|
27
27
|
|
28
|
-
attr_accessor :server
|
28
|
+
attr_accessor :server, :server_options, :setup_with_connection
|
29
29
|
|
30
30
|
# Creates an instance of the pawnee recipe
|
31
31
|
#
|
@@ -121,6 +121,7 @@ module Pawnee
|
|
121
121
|
no_tasks {
|
122
122
|
|
123
123
|
# # Invoke the given task if the given args.
|
124
|
+
# TODO: This method needs some refactoring
|
124
125
|
def invoke_task(task, *args) #:nodoc:
|
125
126
|
current = @_invocations[self.class]
|
126
127
|
|
@@ -130,6 +131,8 @@ module Pawnee
|
|
130
131
|
|
131
132
|
unless current.include?(task.name)
|
132
133
|
current << task.name
|
134
|
+
|
135
|
+
puts " Run task: #{self.class.class_role.to_s} - #{task.name} ".center(80, '*')
|
133
136
|
|
134
137
|
# Setup the server connections before we run the task
|
135
138
|
servers = options[:servers] || options['servers']
|
@@ -142,41 +145,71 @@ module Pawnee
|
|
142
145
|
# No servers, just run locally
|
143
146
|
task.run(self, *args)
|
144
147
|
else
|
148
|
+
first_invoke = true
|
149
|
+
# Create a list of instances that we want to run this task
|
150
|
+
instances = []
|
151
|
+
|
145
152
|
# Run the setup task, setting up the needed connections
|
146
153
|
servers.each do |server|
|
147
154
|
# Only run on this server if the server supports the current recipe's
|
148
155
|
# role.
|
149
156
|
next unless server.is_a?(String) || server.is_a?(Net::SSH::Connection::Session) || (server['roles'] && server['roles'].include?(self.class.class_role))
|
150
157
|
|
158
|
+
if first_invoke
|
159
|
+
instance = self
|
160
|
+
first_invoke = false
|
161
|
+
else
|
162
|
+
# Make a clone (since we want to run self on different threads)
|
163
|
+
# TODO: Look into how deep we need to make this clone (options may be
|
164
|
+
# shared right now)
|
165
|
+
instance = self.clone
|
166
|
+
end
|
151
167
|
# Setup the connection to the server
|
152
168
|
if server.is_a?(Net::SSH::Connection::Session)
|
153
|
-
|
154
|
-
|
169
|
+
instance.destination_connection = server
|
170
|
+
instance.server = server.host
|
171
|
+
instance.setup_with_connection = true
|
155
172
|
elsif server.is_a?(String)
|
156
173
|
# Server name is a string, asume ubuntu
|
157
|
-
|
158
|
-
|
174
|
+
instance.destination_connection = Net::SSH.start(server, 'ubuntu')
|
175
|
+
instance.server = server
|
159
176
|
else
|
160
177
|
# Server is a hash
|
161
|
-
|
162
|
-
|
178
|
+
instance.destination_connection = Net::SSH.start(server['domain'], server['user'] || 'ubuntu')
|
179
|
+
instance.server = server['domain']
|
180
|
+
instance.server_options = server
|
163
181
|
end
|
164
182
|
|
183
|
+
# Setup server options if not setup already
|
184
|
+
instance.server_options = instance.server_options || {}
|
185
|
+
|
186
|
+
# Add the instance to the list of instances to run on
|
187
|
+
instances << instance
|
188
|
+
end
|
189
|
+
|
190
|
+
# Take the list of instances and invoke the task on each one in a seperate thread
|
191
|
+
threads = []
|
192
|
+
|
193
|
+
instances.each do |instance|
|
194
|
+
threads << Thread.new do
|
195
|
+
# Run the task
|
196
|
+
task.run(instance, *args)
|
165
197
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
# Remove the server
|
170
|
-
self.server = nil
|
198
|
+
# Remove the server
|
199
|
+
instance.server = nil
|
171
200
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
201
|
+
# Close the connection
|
202
|
+
if instance.destination_connection
|
203
|
+
# Close the conection only if we created it. If it was passed in as a connection
|
204
|
+
# then the creator is responsible for closing it
|
205
|
+
instance.destination_connection.close unless instance.setup_with_connection
|
206
|
+
instance.destination_connection = nil
|
207
|
+
end
|
178
208
|
end
|
179
209
|
end
|
210
|
+
|
211
|
+
# Wait for threads to finish
|
212
|
+
threads.each(&:join)
|
180
213
|
end
|
181
214
|
end
|
182
215
|
end
|
@@ -184,45 +217,23 @@ module Pawnee
|
|
184
217
|
# Whenever say is used, also print out the server name
|
185
218
|
def say(*args)
|
186
219
|
text = args[0]
|
187
|
-
|
220
|
+
name = (server_options && server_options['name']) || server
|
221
|
+
text = "[#{name}]:\t" + text.to_s if name
|
188
222
|
super(text, *args[1..-1])
|
189
223
|
end
|
190
224
|
|
191
225
|
def say_status(*args)
|
192
226
|
text = args[0]
|
193
|
-
|
227
|
+
name = (server_options && server_options['name']) || server
|
228
|
+
text = "[#{name}]:\t" + text.to_s if name
|
194
229
|
super(text, *args[1..-1])
|
195
230
|
end
|
196
231
|
}
|
197
232
|
|
198
|
-
private
|
199
|
-
def self.global_options
|
200
|
-
@global_options = true
|
201
|
-
yield
|
202
|
-
@global_options = false
|
203
|
-
end
|
204
|
-
|
233
|
+
private
|
205
234
|
def self.check_unknown_options?(config)
|
206
235
|
false
|
207
236
|
end
|
208
|
-
|
209
|
-
|
210
|
-
# Add options to create global method_options, otherwise
|
211
|
-
# they are now prefixed by the recipe name by default
|
212
|
-
def self.method_option(name, options={})
|
213
|
-
scope = if options[:for]
|
214
|
-
find_and_refresh_task(options[:for]).options
|
215
|
-
else
|
216
|
-
method_options
|
217
|
-
end
|
218
|
-
|
219
|
-
unless @global_options
|
220
|
-
prefix = self.gem_name.gsub('-', '_')
|
221
|
-
name = "#{prefix}_#{name}".to_sym
|
222
|
-
end
|
223
|
-
|
224
|
-
build_option(name, options, scope)
|
225
|
-
end
|
226
237
|
|
227
238
|
|
228
239
|
# Inherited is called when a class inherits from Pawnee::Base, it then
|
data/lib/pawnee/pawnee/cli.rb
CHANGED
@@ -11,23 +11,18 @@ module Pawnee
|
|
11
11
|
namespace ''
|
12
12
|
|
13
13
|
desc "setup", "calls setup for each pawnee gem in bundler"
|
14
|
-
|
15
|
-
method_option :roles, :type => :array, :default => :all
|
16
|
-
end
|
14
|
+
method_option :roles, :type => :array, :default => :all
|
17
15
|
def setup
|
18
16
|
Pawnee::Base.invoke_roles(:setup, self.options[:roles], self.options)
|
19
17
|
end
|
20
18
|
|
21
19
|
|
22
20
|
desc "teardown", "calls teardown for each pawnee gem in bundler"
|
23
|
-
|
24
|
-
method_option :roles, :type => :array, :default => :all
|
25
|
-
end
|
21
|
+
method_option :roles, :type => :array, :default => :all
|
26
22
|
def teardown
|
27
23
|
Pawnee::Base.invoke_roles(:setup, self.options[:roles], self.options)
|
28
24
|
end
|
29
25
|
|
30
|
-
|
31
26
|
# Create a new gem (pulled from bundler and modified - MIT LICENSE)
|
32
27
|
desc "gem GEM", "Creates a skeleton recipie"
|
33
28
|
method_option :bin, :type => :boolean, :default => false, :aliases => '-b', :banner => "Generate a binary for your library."
|
@@ -6,21 +6,12 @@ require 'pawnee/base'
|
|
6
6
|
<%- end -%>
|
7
7
|
<%- j = config[:constant_array].size -%>
|
8
8
|
<%= ' '*j %>class Base < Pawnee::Base
|
9
|
-
<%= ' '*j %>
|
10
|
-
<%= ' '*j %> method_option :servers, :type => :array, :required => true
|
11
|
-
<%= ' '*j %> end
|
9
|
+
<%= ' '*j %> method_option :servers, :type => :array, :required => true
|
12
10
|
<%= ' '*j %> desc "setup", 'setup on the destination server'
|
13
11
|
<%= ' '*j %> def setup
|
14
12
|
<%= ' '*j %> # Add your setup code here
|
15
13
|
<%= ' '*j %> end
|
16
14
|
<%= ' '*j %>
|
17
|
-
<%= ' '*j %> global_options do
|
18
|
-
<%= ' '*j %> method_option :servers, :type => :array, :required => true
|
19
|
-
<%= ' '*j %> end
|
20
|
-
<%= ' '*j %> desc "teardown", 'teardown on the destination server'
|
21
|
-
<%= ' '*j %> def teardown
|
22
|
-
<%= ' '*j %> # Add your teardown code here
|
23
|
-
<%= ' '*j %> end
|
24
15
|
<%= ' '*j %>end
|
25
16
|
<%- (config[:constant_array].size-1).downto(0) do |i| -%>
|
26
17
|
<%= ' '*i %>end
|
@@ -9,16 +9,20 @@ describe "compile actions" do
|
|
9
9
|
@base.destination_connection = VagrantManager.connect
|
10
10
|
end
|
11
11
|
|
12
|
-
it 'should install a package' do
|
12
|
+
it 'should install a package and track modification' do
|
13
13
|
@base.as_root do
|
14
14
|
@base.remove_file("/usr/local/bin/redis-server")
|
15
15
|
end
|
16
|
-
@base.exec('which redis-server').should == ''
|
16
|
+
@base.exec('which redis-server', :log_stderr => false).should == ''
|
17
|
+
@base.modified?.should == false
|
17
18
|
|
18
19
|
@base.compile('http://redis.googlecode.com/files/redis-2.4.15.tar.gz', '/home/vagrant/redis-server/', {:skip_configure => true, :bin_file => 'redis-server'})
|
19
20
|
|
20
|
-
@base.exec('which redis-server').should_not == ''
|
21
|
+
@base.exec('which redis-server', :log_stderr => false).should_not == ''
|
22
|
+
|
23
|
+
@base.modified?.should == true
|
21
24
|
end
|
22
25
|
|
26
|
+
|
23
27
|
end
|
24
28
|
|
data/spec/actions/user_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe "user actions" do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def user_exists?(login)
|
13
|
-
_, _, exit_code, _ = @base.exec("id -u #{login}", :with_codes => true)
|
13
|
+
_, _, exit_code, _ = @base.exec("id -u #{login}", :with_codes => true, :log_stderr => false)
|
14
14
|
return exit_code == 0
|
15
15
|
end
|
16
16
|
|
data/spec/spec_helper.rb
CHANGED
@@ -20,7 +20,7 @@ RSpec.configure do |config|
|
|
20
20
|
unless ENV['TRAVIS']
|
21
21
|
# Rollback the server
|
22
22
|
puts "Roll back test server"
|
23
|
-
|
23
|
+
`cd spec/vagrant/ ; BUNDLE_GEMFILE=../../Gemfile bundle exec vagrant sandbox rollback`
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pawnee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
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-
|
12
|
+
date: 2012-07-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -293,7 +293,6 @@ files:
|
|
293
293
|
- spec/base_spec.rb
|
294
294
|
- spec/modified_spec.rb
|
295
295
|
- spec/spec_helper.rb
|
296
|
-
- spec/vagrant/.vagrant
|
297
296
|
- spec/vagrant/Vagrantfile
|
298
297
|
- spec/vagrant/vagrant.rb
|
299
298
|
homepage: ''
|
@@ -310,7 +309,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
310
309
|
version: '0'
|
311
310
|
segments:
|
312
311
|
- 0
|
313
|
-
hash:
|
312
|
+
hash: 4195585264786359942
|
314
313
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
315
314
|
none: false
|
316
315
|
requirements:
|
@@ -319,7 +318,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
319
318
|
version: '0'
|
320
319
|
segments:
|
321
320
|
- 0
|
322
|
-
hash:
|
321
|
+
hash: 4195585264786359942
|
323
322
|
requirements: []
|
324
323
|
rubyforge_project:
|
325
324
|
rubygems_version: 1.8.22
|
@@ -335,6 +334,5 @@ test_files:
|
|
335
334
|
- spec/base_spec.rb
|
336
335
|
- spec/modified_spec.rb
|
337
336
|
- spec/spec_helper.rb
|
338
|
-
- spec/vagrant/.vagrant
|
339
337
|
- spec/vagrant/Vagrantfile
|
340
338
|
- spec/vagrant/vagrant.rb
|
data/spec/vagrant/.vagrant
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"active":{"default":"c90bb8aa-bba5-4bdf-98e8-5097a58829c8"}}
|