capistrano-paratrooper-chef 0.0.1
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 +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +131 -0
- data/Rakefile +2 -0
- data/capistrano-paratrooper-chef.gemspec +19 -0
- data/lib/capistrano-paratrooper-chef.rb +206 -0
- data/lib/capistrano-paratrooper-chef/install.rb +41 -0
- data/lib/capistrano-paratrooper-chef/version.rb +7 -0
- metadata +70 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Takeshi KOMIYA
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# Paratrooper-chef
|
2
|
+
|
3
|
+
A capistrano recipe to execute chef-solo in each server.
|
4
|
+
All of you can use chef-solo remotely without chef-server.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'capistrano-paratrooper-chef'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install capistrano-paratrooper-chef
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
This recipe will execute chef-solo through paratrooper:chef task.
|
23
|
+
|
24
|
+
To setup paratrooper-chef for your application, add following in you config/deploy.rb.
|
25
|
+
|
26
|
+
# in "config/deploy.rb"
|
27
|
+
require 'capistrano-paratrooper-chef'
|
28
|
+
|
29
|
+
And then, put your chef-kitchen files to config/ directory.
|
30
|
+
by default, paratrooper-chef uses following files and directories.
|
31
|
+
|
32
|
+
* config/solo.rb
|
33
|
+
* config/cookbooks
|
34
|
+
* config/site-cookbooks
|
35
|
+
* config/roles
|
36
|
+
* config/data_bags
|
37
|
+
|
38
|
+
Finally, run capistrano with paratrooper:chef task. Then chef-solo runs at remote host.
|
39
|
+
|
40
|
+
$ cap paratrooper:chef
|
41
|
+
|
42
|
+
|
43
|
+
## Setup chef-solo to remote hosts
|
44
|
+
|
45
|
+
Paratrooper-chef includes another task to setup chef-solo to remote hosts.
|
46
|
+
To enable it, add following in your config/deploy.rb.
|
47
|
+
|
48
|
+
# in "config/deploy.rb"
|
49
|
+
require "capistrano-paratrooper-chef/install"
|
50
|
+
|
51
|
+
This recipe will install chef-solo during deploy:setup task.
|
52
|
+
|
53
|
+
## Define attributes for specific host
|
54
|
+
|
55
|
+
Paratrooper-chef supports switching attributes for each host.
|
56
|
+
Put definition to config/nodes/#{hostname}.json.
|
57
|
+
|
58
|
+
If there are no defitions for host, paratrooper-chef uses config/solo.rb as attributes.
|
59
|
+
|
60
|
+
## Chef roles Auto discovery
|
61
|
+
|
62
|
+
Chef roles auto discovery appends roles of chef to run_list of each host.
|
63
|
+
To enable auto discovery, set :chef_roles_auto_discovery true (as defualt, it is disabled).
|
64
|
+
|
65
|
+
# in "config/deploy.rb"
|
66
|
+
set :chef_roles_auto_discovery, true
|
67
|
+
|
68
|
+
This feature makes name-based relations with role of capistrano and chef's one::
|
69
|
+
* Discovering role definitions of chef from role-names of capistrano that server is assigned
|
70
|
+
* Run chef with discovered roles at each server
|
71
|
+
* Be able to play different roles of chef for each server
|
72
|
+
|
73
|
+
|
74
|
+
For example, 'web.example.com' plays :web role:
|
75
|
+
|
76
|
+
set :web, 'web.example.com'
|
77
|
+
|
78
|
+
And, there is role defition named 'web.json'.
|
79
|
+
|
80
|
+
# config/roles/web.json
|
81
|
+
{
|
82
|
+
"nginx" : {
|
83
|
+
# ...
|
84
|
+
},
|
85
|
+
"run_list" : [
|
86
|
+
"recipe[nginx]",
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
Then, paratrooper-chef detects automatically these relation, and append 'role[web]' to run_list of web.example.com .
|
91
|
+
(do not effect to other hosts)
|
92
|
+
|
93
|
+
## Options
|
94
|
+
|
95
|
+
Following options are available.
|
96
|
+
|
97
|
+
* Settings for remote host
|
98
|
+
|
99
|
+
* `:chef_solo_path` - the path of `chef-solo` command. use `chef-solo` by default (search command from $PATH).
|
100
|
+
* `:chef_working_dir` - the path where chef-kitchen should installed. use `$HOME/chef-solo` by default.
|
101
|
+
* `:chef_cache_dir` - the path for caches. use `/var/chef/cache` by default.
|
102
|
+
|
103
|
+
* Settings for chef and paratrooper
|
104
|
+
|
105
|
+
* `:chef_roles_auto_discovery` - Enable "Chef roles Auto discovery". use `false` by default.
|
106
|
+
* `:chef_verbose_logging`, - Enable verbose logging mode of `chef-solo`. use `true` by default.
|
107
|
+
* `:chef_debug` - Enable debug mode of `chef-solo`. use `false` by default.
|
108
|
+
|
109
|
+
* Settings for directories
|
110
|
+
|
111
|
+
* `:chef_kitchen_path` - root directory of kitchen. use `config` by default.
|
112
|
+
* `:chef_default_solo_json_path` - default attribute file a.k.a solo.json. use `solo.json` by default.
|
113
|
+
* `:chef_cookbooks_path` - cookbooks directories list. use `["cookbooks", "site-cookbooks"]` by default.
|
114
|
+
* `:chef_nodes_path` - nodes directory. use `nodes` by default.
|
115
|
+
* `:chef_roles_path` - roles directory. use `roles` by default.
|
116
|
+
* `:chef_databagas_path` - data bags directory. use `data_bagas` by default.
|
117
|
+
|
118
|
+
## Support recipes
|
119
|
+
|
120
|
+
Following recipes work fine with paratrooper-chef.
|
121
|
+
|
122
|
+
* rvm-capistrano (https://github.com/wayneeseguin/rvm-capistrano)
|
123
|
+
* capistrano-rbenv (https://github.com/yyuu/capistrano-rbenv)
|
124
|
+
|
125
|
+
## Contributing
|
126
|
+
|
127
|
+
1. Fork it
|
128
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
129
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
130
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
131
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/capistrano-paratrooper-chef/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Takeshi KOMIYA"]
|
6
|
+
gem.email = ["i.tkomiya@gmail.com"]
|
7
|
+
gem.description = %q{A capistrano task to invoke chef-solo}
|
8
|
+
gem.summary = %q{A capistrano task to invoke chef-solo}
|
9
|
+
gem.homepage = "https://github.com/tk0miya/capistrano-paratrooper-chef"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "capistrano-paratrooper-chef"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Capistrano::Paratrooper::Chef::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency("capistrano")
|
19
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require "json"
|
2
|
+
require "tempfile"
|
3
|
+
require "capistrano-paratrooper-chef/version"
|
4
|
+
|
5
|
+
|
6
|
+
Capistrano::Configuration.instance.load do
|
7
|
+
namespace :paratrooper do
|
8
|
+
# directory structure of chef-kitchen
|
9
|
+
set :chef_kitchen_path, "config"
|
10
|
+
set :chef_default_solo_json_path, "solo.json"
|
11
|
+
set :chef_cookbooks_path, ["cookbooks", "site-cookbooks"]
|
12
|
+
set :chef_nodes_path, "nodes"
|
13
|
+
set :chef_roles_path, "roles"
|
14
|
+
set :chef_databags_path, "data_bags"
|
15
|
+
|
16
|
+
# remote chef settings
|
17
|
+
set :chef_solo_path, "chef-solo"
|
18
|
+
set :chef_working_dir, "chef-solo"
|
19
|
+
set :chef_cache_dir, "/var/chef/cache"
|
20
|
+
|
21
|
+
# chef settings
|
22
|
+
set :chef_roles_auto_discovery, false
|
23
|
+
set :chef_verbose_logging, true
|
24
|
+
set :chef_debug, false
|
25
|
+
|
26
|
+
def sudocmd
|
27
|
+
envvars = fetch(:default_environment, {}).collect{|k, v| "#{k}=#{v}"}
|
28
|
+
|
29
|
+
begin
|
30
|
+
old_sudo = self[:sudo]
|
31
|
+
if fetch(:rvm_type, nil) == :user
|
32
|
+
self[:sudo] = "rvmsudo_secure_path=1 #{File.join(rvm_bin_path, "rvmsudo")}"
|
33
|
+
end
|
34
|
+
|
35
|
+
if envvars
|
36
|
+
cmd = "#{top.sudo} env #{envvars.join(" ")}"
|
37
|
+
else
|
38
|
+
cmd = top.sudo
|
39
|
+
end
|
40
|
+
ensure
|
41
|
+
self[:sudo] = old_sudo if old_sudo
|
42
|
+
end
|
43
|
+
|
44
|
+
cmd
|
45
|
+
end
|
46
|
+
|
47
|
+
def sudo(command, *args)
|
48
|
+
run "#{sudocmd} #{command}", *args
|
49
|
+
end
|
50
|
+
|
51
|
+
def remote_path(*path)
|
52
|
+
File.join(fetch(:chef_working_dir), *path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def cookbooks_paths
|
56
|
+
fetch(:chef_cookbooks_path).collect{|path| File.join(fetch(:chef_kitchen_path), path)}
|
57
|
+
end
|
58
|
+
|
59
|
+
def roles_path
|
60
|
+
File.join(fetch(:chef_kitchen_path), fetch(:chef_roles_path))
|
61
|
+
end
|
62
|
+
|
63
|
+
def role_exists?(name)
|
64
|
+
File.exist?(File.join(roles_path, name.to_s + ".json")) ||
|
65
|
+
File.exist?(File.join(roles_path, name.to_s + ".rb"))
|
66
|
+
end
|
67
|
+
|
68
|
+
def databags_path
|
69
|
+
File.join(fetch(:chef_kitchen_path), fetch(:chef_databags_path))
|
70
|
+
end
|
71
|
+
|
72
|
+
def nodes_path
|
73
|
+
File.join(fetch(:chef_kitchen_path), fetch(:chef_nodes_path))
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
namespace :run_list do
|
78
|
+
def solo_json_path_for(name)
|
79
|
+
path = File.join(nodes_path, name.to_s + ".json")
|
80
|
+
if File.exist?(path)
|
81
|
+
path
|
82
|
+
else
|
83
|
+
File.join(fetch(:chef_kitchen_path), fetch(:chef_default_solo_json_path))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def discover
|
88
|
+
find_servers_for_task(current_task).each do |server|
|
89
|
+
begin
|
90
|
+
open(solo_json_path_for(server.host)) do |fd|
|
91
|
+
server.options[:chef_attributes] = JSON.load(fd)
|
92
|
+
|
93
|
+
if server.options[:chef_attributes]["run_list"].nil?
|
94
|
+
server.options[:chef_attributes]["run_list"] = []
|
95
|
+
end
|
96
|
+
end
|
97
|
+
rescue
|
98
|
+
server.options[:chef_attributes] = attrs = {"run_list" => []}
|
99
|
+
end
|
100
|
+
|
101
|
+
if fetch(:chef_roles_auto_discovery)
|
102
|
+
role_names_for_host(server).each do |role|
|
103
|
+
server.options[:chef_attributes]["run_list"] << "role[#{role}]" if role_exists?(role)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def discovered_attributes
|
110
|
+
find_servers_for_task(current_task).collect{|server| server.options[:chef_attributes]}.compact
|
111
|
+
end
|
112
|
+
|
113
|
+
def discovered_lists
|
114
|
+
discovered_attributes.collect{|attr| attr["run_list"]}
|
115
|
+
end
|
116
|
+
|
117
|
+
def unique?
|
118
|
+
if fetch(:chef_roles_auto_discovery)
|
119
|
+
discovered_lists.uniq.size == 1
|
120
|
+
else
|
121
|
+
true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def ensure
|
126
|
+
if discovered_lists.all?{|run_list| run_list.empty?}
|
127
|
+
abort "You must specify at least one recipe or role"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
namespace :chef do
|
133
|
+
task :default, :except => { :no_release => true } do
|
134
|
+
run_list.discover
|
135
|
+
run_list.ensure
|
136
|
+
kitchen.ensure_cookbooks
|
137
|
+
kitchen.ensure_working_dir
|
138
|
+
kitchen.upload
|
139
|
+
chef.generate_solo_rb
|
140
|
+
chef.generate_solo_json
|
141
|
+
chef.execute
|
142
|
+
end
|
143
|
+
|
144
|
+
task :solo, :except => { :no_release => true } do
|
145
|
+
chef.default
|
146
|
+
end
|
147
|
+
|
148
|
+
def generate_solo_rb
|
149
|
+
config = <<-CONF
|
150
|
+
root = File.expand_path(File.dirname(__FILE__))
|
151
|
+
file_cache_path #{fetch(:chef_cache_dir).inspect}
|
152
|
+
cookbook_path #{kitchen.cookbooks_paths.inspect}.collect{|dir| File.join(root, dir)}
|
153
|
+
role_path File.join(root, #{kitchen.roles_path.inspect})
|
154
|
+
data_bag_path File.join(root, #{kitchen.databags_path.inspect})
|
155
|
+
verbose_logging #{fetch(:chef_verbose_logging)}
|
156
|
+
CONF
|
157
|
+
put config, remote_path("solo.rb"), :via => :scp
|
158
|
+
end
|
159
|
+
|
160
|
+
def generate_solo_json
|
161
|
+
find_servers_for_task(current_task).each do |server|
|
162
|
+
put server.options[:chef_attributes].to_json, remote_path("solo.json"), :hosts => server.host, :via => :scp
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
desc "Run chef-solo"
|
167
|
+
task :execute, :except => { :no_release => true } do
|
168
|
+
logger.info "Now running chef-solo"
|
169
|
+
command = "#{chef_solo_path} -c #{remote_path("solo.rb")} -j #{remote_path("solo.json")}#{' -l debug' if fetch(:chef_debug)}"
|
170
|
+
if run_list.unique?
|
171
|
+
sudo command
|
172
|
+
else
|
173
|
+
parallel do |session|
|
174
|
+
session.when "options[:chef_attributes]['run_list'].size > 0",
|
175
|
+
"#{sudocmd} #{command}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
namespace :kitchen do
|
182
|
+
def ensure_cookbooks
|
183
|
+
abort "No cookbooks found in #{fetch(:cookbooks_directory).inspect}" if kitchen.cookbooks_paths.empty?
|
184
|
+
end
|
185
|
+
|
186
|
+
def ensure_working_dir
|
187
|
+
run "rm -rf #{fetch(:chef_working_dir)} && mkdir -p #{fetch(:chef_working_dir)}"
|
188
|
+
sudo "mkdir -p #{fetch(:chef_cache_dir)}"
|
189
|
+
end
|
190
|
+
|
191
|
+
desc "Upload files in kitchen"
|
192
|
+
task :upload, :except => { :no_release => true } do
|
193
|
+
kitchen_paths = [cookbooks_paths, roles_path, databags_path].flatten.compact.select{|d| File.exists?(d)}
|
194
|
+
tarball = Tempfile.new("kitchen.tar")
|
195
|
+
begin
|
196
|
+
tarball.close
|
197
|
+
system "tar -czf #{tarball.path} #{kitchen_paths.join(' ')}"
|
198
|
+
top.upload tarball.path, remote_path("kitchen.tar"), :via => :scp
|
199
|
+
run "cd #{fetch(:chef_working_dir)} && tar -xzf kitchen.tar"
|
200
|
+
ensure
|
201
|
+
tarball.unlink
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'capistrano-paratrooper-chef'
|
2
|
+
|
3
|
+
Capistrano::Configuration.instance.load do
|
4
|
+
namespace :paratrooper do
|
5
|
+
namespace :chef do
|
6
|
+
set :chef_version, ">= 11.0.0"
|
7
|
+
|
8
|
+
on :load do
|
9
|
+
if top.namespaces.key?(:rbenv)
|
10
|
+
after "rbenv:setup", "paratrooper:chef:setup"
|
11
|
+
elsif top.namespaces.key?(:rvm)
|
12
|
+
after "rvm:install_ruby", "paratrooper:chef:setup"
|
13
|
+
else
|
14
|
+
after "deploy:setup" "paratrooper:chef:setup"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Installs chef"
|
19
|
+
task :setup, :except => { :no_release => true } do
|
20
|
+
required_version = fetch(:chef_version).inspect
|
21
|
+
installed = capture("gem list -i chef -v #{required_version} || true").strip
|
22
|
+
|
23
|
+
if installed == "false"
|
24
|
+
if fetch(:rvm_type, nil) == :user or fetch(:rbenv_path, nil)
|
25
|
+
run "gem uninstall -xaI chef || true"
|
26
|
+
run "gem install chef -v #{fetch(:chef_version).inspect} --quiet --no-ri --no-rdoc"
|
27
|
+
run "gem install ruby-shadow --quiet --no-ri --no-rdoc"
|
28
|
+
|
29
|
+
if fetch(:rbenv_path, nil)
|
30
|
+
rbenv.rehash
|
31
|
+
end
|
32
|
+
else
|
33
|
+
sudo "gem uninstall -xaI chef || true"
|
34
|
+
sudo "gem install chef -v #{fetch(:chef_version).inspect} --quiet --no-ri --no-rdoc"
|
35
|
+
sudo "gem install ruby-shadow --quiet --no-ri --no-rdoc"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capistrano-paratrooper-chef
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Takeshi KOMIYA
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: capistrano
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: A capistrano task to invoke chef-solo
|
31
|
+
email:
|
32
|
+
- i.tkomiya@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- LICENSE
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- capistrano-paratrooper-chef.gemspec
|
43
|
+
- lib/capistrano-paratrooper-chef.rb
|
44
|
+
- lib/capistrano-paratrooper-chef/install.rb
|
45
|
+
- lib/capistrano-paratrooper-chef/version.rb
|
46
|
+
homepage: https://github.com/tk0miya/capistrano-paratrooper-chef
|
47
|
+
licenses: []
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.8.24
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: A capistrano task to invoke chef-solo
|
70
|
+
test_files: []
|