spatula 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +13 -3
- data/bin/spatula +1 -1
- data/lib/spatula/cook.rb +31 -0
- data/lib/spatula/prepare.rb +27 -0
- data/lib/spatula/search.rb +26 -0
- data/lib/spatula.rb +115 -44
- metadata +15 -5
data/README.textile
CHANGED
@@ -4,16 +4,26 @@ Spatula is a command line helper app for use with "Chef":http://www.opscode.com/
|
|
4
4
|
|
5
5
|
Spatula is really, really alpha. It does not handle errors at all, but it works pretty well given that you hand it the correct input. Please give it a try and pretty please fork it and make it better.
|
6
6
|
|
7
|
+
h1. Installation
|
8
|
+
|
9
|
+
You can get spatula from gemcutter.
|
10
|
+
|
11
|
+
<pre>
|
12
|
+
# Gemcutter:
|
13
|
+
# Follow the instructions on http://gemcutter.org/ then...
|
14
|
+
gem install spatula
|
15
|
+
</pre>
|
16
|
+
|
7
17
|
h1. Usage
|
8
18
|
|
9
19
|
Spatula currently supports 3 commands: search, show, and install.
|
10
20
|
|
11
21
|
<pre>
|
12
|
-
$
|
22
|
+
$ spatula search apache2
|
13
23
|
apache2 Installs and configures all aspects of apache2 using Debian style symlinks with helper definitions
|
14
24
|
... more output ...
|
15
25
|
|
16
|
-
$
|
26
|
+
$ spatula show apache2
|
17
27
|
name: apache2
|
18
28
|
average_rating:
|
19
29
|
category: Web Servers
|
@@ -25,7 +35,7 @@ external_url:
|
|
25
35
|
versions: http://cookbooks.opscode.com/api/v1/cookbooks/apache2/versions/0_9_1
|
26
36
|
description: Installs and configures all aspects of apache2 using Debian style symlinks with helper definitions
|
27
37
|
|
28
|
-
$
|
38
|
+
$ spatula install apache2
|
29
39
|
... downloads the apache2 cookbook and installs it into $(pwd)/cookbooks ...
|
30
40
|
... also creates a $(pwd)/cookbook_tarballs dir to store the download ...
|
31
41
|
</pre>
|
data/bin/spatula
CHANGED
data/lib/spatula/cook.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Spatula
|
2
|
+
# TODO: Set REMOTE_CHEF_PATH using value for file_cache_path
|
3
|
+
REMOTE_CHEF_PATH = "/tmp/chef-solo" # Where to find upstream cookbooks
|
4
|
+
|
5
|
+
class Cook
|
6
|
+
Spatula.register("cook", self)
|
7
|
+
|
8
|
+
def self.run(*args)
|
9
|
+
new(*args).run
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(server, node, port=22)
|
13
|
+
@server = server
|
14
|
+
@node = node
|
15
|
+
@port = port
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
sh "rake test"
|
20
|
+
sh "rsync -rlP --rsh=\"ssh -p#@port\" --delete --exclude '.*' ./ #@server:#{REMOTE_CHEF_PATH}"
|
21
|
+
sh "ssh -t -p #@port -A #@server \"cd #{REMOTE_CHEF_PATH}; sudo /var/lib/gems/1.8/bin/chef-solo -c config/solo.rb -j config/#@node.json \""
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def sh(command)
|
26
|
+
stdout = `#{command}`
|
27
|
+
puts stdout
|
28
|
+
stdout
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Prepare :server: for chef solo to run on it
|
2
|
+
module Spatula
|
3
|
+
class Prepare
|
4
|
+
Spatula.register("prepare", self)
|
5
|
+
|
6
|
+
def self.run(*args)
|
7
|
+
new(*args).run
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(server, port=22)
|
11
|
+
@server = server
|
12
|
+
@port = port
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
sh %Q|ssh -t -p #@port #@server sudo aptitude -y install ruby rubygems rubygems1.8 irb ri libopenssl-ruby1.8 libshadow-ruby1.8 ruby1.8-dev gcc g++ rsync |
|
17
|
+
sh %Q|ssh -t -p #@port #@server sudo gem install rdoc chef ohai --no-ri --no-rdoc --source http://gems.opscode.com --source http://gems.rubyforge.org|
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def sh(command)
|
22
|
+
stdout = `#{command}`
|
23
|
+
puts stdout
|
24
|
+
stdout
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Search for cookbooks matching :query:
|
2
|
+
module Spatula
|
3
|
+
class Search
|
4
|
+
Spatula.register("search", self)
|
5
|
+
|
6
|
+
def self.run(*args)
|
7
|
+
new(*args).run
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(query, start=0, count=10)
|
11
|
+
@query = query
|
12
|
+
@start = start
|
13
|
+
@count = count
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
url = URI.parse("%s/search?q=%s&start=%s&items=%s" % [BASE_URL, @query, @start, @count])
|
18
|
+
response = Net::HTTP.get(url)
|
19
|
+
items = JSON.parse(response)["items"]
|
20
|
+
items.each do |item|
|
21
|
+
puts [item["cookbook_name"], item["cookbook_description"], item["cookbook_maintainer"]].join("\t")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
data/lib/spatula.rb
CHANGED
@@ -3,63 +3,134 @@ require 'net/http'
|
|
3
3
|
require 'uri'
|
4
4
|
require 'json'
|
5
5
|
|
6
|
-
|
6
|
+
module Spatula
|
7
7
|
BASE_URL = "http://cookbooks.opscode.com/api/v1"
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
Spatula.new.send(command, *ARGV)
|
12
|
-
end
|
9
|
+
class Spatula
|
10
|
+
@commands = {}
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
url = URI.parse("%s/search?q=%s&start=%s&items=%s" % [BASE_URL, query, start, items])
|
17
|
-
response = Net::HTTP.get(url)
|
18
|
-
items = JSON.parse(response)["items"]
|
19
|
-
items.each do |item|
|
20
|
-
puts [item["cookbook_name"], item["cookbook_description"], item["cookbook_maintainer"]].join("\t")
|
12
|
+
def self.register(command, klass)
|
13
|
+
@commands[command] = klass
|
21
14
|
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Show the cookbook named :name:
|
25
|
-
def show(name)
|
26
|
-
print_response(get_cookbook_info(name))
|
27
|
-
end
|
28
15
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
16
|
+
def self.run
|
17
|
+
command = ARGV.shift
|
18
|
+
if klass = @commands[command]
|
19
|
+
klass.run(*ARGV)
|
20
|
+
else
|
21
|
+
Spatula.new.send(command, *ARGV)
|
22
|
+
end
|
23
|
+
end
|
33
24
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
filename = File.basename(file)
|
39
|
-
FileUtils.mkdir_p("cookbook_tarballs")
|
40
|
-
`curl #{file} -o cookbook_tarballs/#{filename}`
|
41
|
-
`tar xzvf cookbook_tarballs/#{filename} -C cookbooks`
|
42
|
-
end
|
25
|
+
# Show the cookbook named :name:
|
26
|
+
def show(name)
|
27
|
+
print_response(get_cookbook_info(name))
|
28
|
+
end
|
43
29
|
|
44
|
-
|
45
|
-
def
|
46
|
-
|
47
|
-
Net::HTTP.get(url)
|
30
|
+
# Show the latest version of the cookbook named :name:
|
31
|
+
def show_latest_version(name)
|
32
|
+
print_response(get_version_info(name))
|
48
33
|
end
|
49
34
|
|
50
|
-
|
51
|
-
|
52
|
-
|
35
|
+
# Install the cookbook :name: into cwd/cookbooks
|
36
|
+
# Will create a cookbook_tarballs dir for storing downloaded tarballs
|
37
|
+
def install(name)
|
38
|
+
file = JSON.parse(get_version_info(name))["file"]
|
39
|
+
filename = File.basename(file)
|
40
|
+
FileUtils.mkdir_p("cookbook_tarballs")
|
41
|
+
`curl #{file} -o cookbook_tarballs/#{filename}`
|
42
|
+
`tar xzvf cookbook_tarballs/#{filename} -C cookbooks`
|
53
43
|
end
|
54
44
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
45
|
+
private
|
46
|
+
def strict_system *cmd
|
47
|
+
cmd.map! &:to_s
|
48
|
+
result = []
|
49
|
+
|
50
|
+
trace = cmd.join(' ')
|
51
|
+
warn trace if $TRACE
|
52
|
+
|
53
|
+
pid, inn, out, err = popen4(*cmd)
|
54
|
+
|
55
|
+
inn.sync = true
|
56
|
+
streams = [out, err]
|
57
|
+
out_stream = {
|
58
|
+
out => $stdout,
|
59
|
+
err => $stderr,
|
60
|
+
}
|
61
|
+
|
62
|
+
out_stream_buffers = {
|
63
|
+
out => "",
|
64
|
+
err => ""
|
65
|
+
}
|
66
|
+
|
67
|
+
# Handle process termination ourselves
|
68
|
+
status = nil
|
69
|
+
Thread.start do
|
70
|
+
status = Process.waitpid2(pid).last
|
71
|
+
end
|
72
|
+
|
73
|
+
until streams.empty? do
|
74
|
+
# don't busy loop
|
75
|
+
selected, = select streams, nil, nil, 0.1
|
76
|
+
|
77
|
+
next if selected.nil? or selected.empty?
|
78
|
+
|
79
|
+
selected.each do |stream|
|
80
|
+
if stream.eof? then
|
81
|
+
streams.delete stream if status # we've quit, so no more writing
|
82
|
+
next
|
83
|
+
end
|
84
|
+
|
85
|
+
data = stream.readpartial(1024)
|
86
|
+
out_stream[stream].write data
|
87
|
+
out_stream_buffers[stream] << data
|
88
|
+
|
89
|
+
if stream == err and out_stream_buffers[stream] =~ /password(?:for)?.*:/i then
|
90
|
+
out_stream_buffers[stream] = ""
|
91
|
+
inn.puts @password
|
92
|
+
data << "\n"
|
93
|
+
$stderr.write "\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
result << data
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
unless status.success? then
|
101
|
+
raise "execution failed with status #{status.exitstatus}: #{cmd.join ' '}"
|
102
|
+
end
|
103
|
+
|
104
|
+
result.join
|
105
|
+
ensure
|
106
|
+
inn.close rescue nil
|
107
|
+
out.close rescue nil
|
108
|
+
err.close rescue nil
|
59
109
|
end
|
60
|
-
|
110
|
+
|
111
|
+
def get_cookbook_info(name)
|
112
|
+
url = URI.parse("%s/cookbooks/%s" % [BASE_URL, name])
|
113
|
+
Net::HTTP.get(url)
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_version_info(name)
|
117
|
+
latest = JSON.parse(get_cookbook_info(name))["latest_version"]
|
118
|
+
response = Net::HTTP.get(URI.parse(latest))
|
119
|
+
end
|
120
|
+
|
121
|
+
def print_response(response)
|
122
|
+
item = JSON.parse(response)
|
123
|
+
item.each_pair do |k, v|
|
124
|
+
puts "#{k}:\t#{v}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
61
128
|
end
|
62
129
|
|
130
|
+
require 'spatula/search'
|
131
|
+
require 'spatula/prepare'
|
132
|
+
require 'spatula/cook'
|
133
|
+
|
63
134
|
if __FILE__ == $0
|
64
|
-
Spatula.run
|
135
|
+
Spatula::Spatula.run
|
65
136
|
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spatula
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Trotter Cashion
|
@@ -9,7 +14,7 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date:
|
17
|
+
date: 2010-02-21 00:00:00 -05:00
|
13
18
|
default_executable:
|
14
19
|
dependencies: []
|
15
20
|
|
@@ -24,6 +29,9 @@ extra_rdoc_files: []
|
|
24
29
|
files:
|
25
30
|
- README.textile
|
26
31
|
- bin/spatula
|
32
|
+
- lib/spatula/cook.rb
|
33
|
+
- lib/spatula/prepare.rb
|
34
|
+
- lib/spatula/search.rb
|
27
35
|
- lib/spatula.rb
|
28
36
|
has_rdoc: true
|
29
37
|
homepage: http://trottercashion.com
|
@@ -38,18 +46,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
38
46
|
requirements:
|
39
47
|
- - ">="
|
40
48
|
- !ruby/object:Gem::Version
|
49
|
+
segments:
|
50
|
+
- 0
|
41
51
|
version: "0"
|
42
|
-
version:
|
43
52
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
53
|
requirements:
|
45
54
|
- - ">="
|
46
55
|
- !ruby/object:Gem::Version
|
56
|
+
segments:
|
57
|
+
- 0
|
47
58
|
version: "0"
|
48
|
-
version:
|
49
59
|
requirements: []
|
50
60
|
|
51
61
|
rubyforge_project:
|
52
|
-
rubygems_version: 1.3.
|
62
|
+
rubygems_version: 1.3.6
|
53
63
|
signing_key:
|
54
64
|
specification_version: 3
|
55
65
|
summary: Command line helper app for use with Chef
|