pawnee 0.1.4 → 0.1.5
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/.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"}}
|