capistrano-knife-solo 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +85 -0
- data/Rakefile +1 -0
- data/capistrano-knife-solo.gemspec +27 -0
- data/lib/capistrano-knife-solo/tasks/tasks.rake +86 -0
- data/lib/capistrano-knife-solo/version.rb +3 -0
- data/lib/capistrano-knife-solo.rb +74 -0
- metadata +135 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Robert Coleman
|
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,85 @@
|
|
1
|
+
# Capistrano-Knife-Solo
|
2
|
+
|
3
|
+
Integrates Capistrano (v3.1+) with [Knife Solo](http://matschaffer.github.io/knife-solo/)
|
4
|
+
to automate the preparation and provisioning of nodes via Chef Solo.
|
5
|
+
|
6
|
+
Capistrano-Knife-Solo uses the configured servers and roles from Capistrano,
|
7
|
+
it feeds them directly into Knife Solo/Chef for node deployment.
|
8
|
+
|
9
|
+
This assumes that a Chef role exists to match the defined Capistrano roles (excluding `:all`).
|
10
|
+
|
11
|
+
Should work with other Capistrano plugins that dynamically add servers
|
12
|
+
such as [Cap-EC2](https://github.com/forward3d/cap-ec2)
|
13
|
+
|
14
|
+
Note:
|
15
|
+
By default Capistrano-Knife-Solo ignores any existing Chef/Knife role definitions.
|
16
|
+
A role is automatically assinged to match the Capistrano roles and these are
|
17
|
+
programatically inserted into each node's run list.
|
18
|
+
|
19
|
+
|
20
|
+
## Limitations (PRs welcome)
|
21
|
+
|
22
|
+
* Capistrano (SSHKit) supports multiple SSH key files. Knife Solo only accepts
|
23
|
+
one identity file. Make sure that the correct key is the first configured in Cap.
|
24
|
+
|
25
|
+
* Chef Environments are not supported.
|
26
|
+
|
27
|
+
|
28
|
+
## Installation
|
29
|
+
|
30
|
+
* `gem install capistrano-knife-solo` or add the gem to your project's Gemfile.
|
31
|
+
|
32
|
+
* Add this line to your Capfile: `require 'capistrano-knife-solo'`
|
33
|
+
|
34
|
+
|
35
|
+
## Usage
|
36
|
+
|
37
|
+
Some tasks are added to Capistrano - these are scoped by stage:
|
38
|
+
|
39
|
+
```
|
40
|
+
$ bundle exec cap -T
|
41
|
+
...
|
42
|
+
cap knife:bootstrap # Prepare then cook a node/role with Chef
|
43
|
+
cap knife:clean # Clean a node/role with Chef
|
44
|
+
cap knife:cook # Cook a node/role with Chef
|
45
|
+
cap knife:prepare # Prepare a node/role with Chef
|
46
|
+
```
|
47
|
+
|
48
|
+
e.g. to run Chef on all staging servers
|
49
|
+
`cap staging knife:cook`
|
50
|
+
|
51
|
+
All the [Capistrano filtering options](http://capistranorb.com/documentation/advanced-features/host-filtering/) are supported.
|
52
|
+
|
53
|
+
If you wanted to automatically run Chef before each deploy you could add `before 'deploy:starting', 'knife:cook'` to your `deploy.rb` tasks.
|
54
|
+
|
55
|
+
|
56
|
+
## Configuration
|
57
|
+
|
58
|
+
Several configuration values exist, the defaults are listed below.
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
set :knife_check_disable, false # Check for chef-solo before deploy:check
|
62
|
+
set :knife_args, nil # the equivalent of command line arguments to knife solo
|
63
|
+
|
64
|
+
set :knife_startup_script, nil # The startup script on the remote server containing variable definitions
|
65
|
+
set :knife_sudo_command, nil # remote sudo command, if not sudo
|
66
|
+
set :knife_host_key_verify, false # don't verify ssh key
|
67
|
+
set :knife_cookbook_path, %w{cookbooks site-cookbooks} # cookbook path relative to Capfile
|
68
|
+
set :knife_berkshelf, true # use Berkshelf to update cookbooks if present
|
69
|
+
set :knife_librarian, true # use librarian-chef to update cookbooks if present
|
70
|
+
```
|
71
|
+
|
72
|
+
|
73
|
+
## Contributing
|
74
|
+
|
75
|
+
1. Fork it ( http://github.com/<my-github-username>/capistrano-knife-solo/fork )
|
76
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
77
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
78
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
79
|
+
5. Create new Pull Request
|
80
|
+
|
81
|
+
|
82
|
+
## Similar
|
83
|
+
|
84
|
+
* [https://github.com/bmuller/toquen/](https://github.com/bmuller/toquen/)
|
85
|
+
* [http://lee.hambley.name/2013/06/11/using-capistrano-v3-with-chef.html](http://lee.hambley.name/2013/06/11/using-capistrano-v3-with-chef.html)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'capistrano-knife-solo/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'capistrano-knife-solo'
|
8
|
+
spec.version = CapistranoKnifeSolo::VERSION
|
9
|
+
spec.authors = ['Robert Coleman']
|
10
|
+
spec.email = ['github@robert.net.nz']
|
11
|
+
spec.summary = %q{Use knife solo with Capistrano.}
|
12
|
+
spec.description = %q{Use knife solo with Capistrano.}
|
13
|
+
spec.homepage = 'https://github.com/rjocoleman/capistrano-knife-solo'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'pry'
|
24
|
+
|
25
|
+
spec.add_dependency 'capistrano', '~> 3.1.0'
|
26
|
+
spec.add_dependency 'knife-solo', '~> 0.4'
|
27
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
namespace :knife do
|
2
|
+
desc 'Prepare a node/role with Chef Solo'
|
3
|
+
task :prepare do
|
4
|
+
on roles(:all), in: :parallel do |host|
|
5
|
+
run_locally do
|
6
|
+
solo = Chef::Knife::SoloPrepare.new
|
7
|
+
Chef::Knife::SoloPrepare.load_deps
|
8
|
+
CapistranoKnifeSolo::Helpers.chef_config
|
9
|
+
solo.name_args = CapistranoKnifeSolo::Helpers.knife_args(host)
|
10
|
+
solo.config = CapistranoKnifeSolo::Helpers.knife_config(host)
|
11
|
+
solo.run
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Cook a node/role with Chef Solo'
|
17
|
+
task :cook => [:check] do
|
18
|
+
Rake::Task['knife:cookbook_managers'].invoke
|
19
|
+
on roles(:all), in: :parallel do |host|
|
20
|
+
run_locally do
|
21
|
+
solo = Chef::Knife::SoloCook.new
|
22
|
+
Chef::Knife::SoloCook.load_deps
|
23
|
+
CapistranoKnifeSolo::Helpers.chef_config
|
24
|
+
solo.name_args = CapistranoKnifeSolo::Helpers.knife_args(host)
|
25
|
+
solo.config = CapistranoKnifeSolo::Helpers.knife_config(host)
|
26
|
+
solo.run
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Clean a node/role with Chef Solo'
|
32
|
+
task :clean do
|
33
|
+
on roles(:all), in: :parallel do |host|
|
34
|
+
run_locally do
|
35
|
+
solo = Chef::Knife::SoloClean.new
|
36
|
+
Chef::Knife::SoloClean.load_deps
|
37
|
+
CapistranoKnifeSolo::Helpers.chef_config
|
38
|
+
solo.name_args = CapistranoKnifeSolo::Helpers.knife_args(host)
|
39
|
+
solo.config = CapistranoKnifeSolo::Helpers.knife_config(host)
|
40
|
+
solo.run
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# cookbook managers want to run for each knife solo run, for each node.
|
46
|
+
# this task runs them manually first once, if they're enabled, and then disables them for future knife runs in this session.
|
47
|
+
task :cookbook_managers do
|
48
|
+
manager = Chef::Knife::SoloCook.new
|
49
|
+
CapistranoKnifeSolo::Helpers.chef_config
|
50
|
+
manager.berkshelf_install if fetch(:knife_berkshelf)
|
51
|
+
set :knife_berkshelf, false
|
52
|
+
manager.librarian_install if fetch(:knife_librarian)
|
53
|
+
set :knife_librarian, false
|
54
|
+
end
|
55
|
+
|
56
|
+
# check if `chef-solo` is an executable command on the path of remote server
|
57
|
+
task :check do
|
58
|
+
unless fetch(:knife_check_disable)
|
59
|
+
on roles(:all), in: :parallel do |host|
|
60
|
+
unless test "command -v chef-solo >/dev/null 2>&1"
|
61
|
+
error "#{host}: chef-solo not found, aborting."
|
62
|
+
abort "chef-solo was not present on atleast one server. Run 'cap #{fetch(:stage)} knife:prepare'"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
before 'deploy:check', 'knife:check'
|
68
|
+
|
69
|
+
desc 'Prepare then cook a node/role with Chef'
|
70
|
+
task :bootstrap => [:prepare, :cook]
|
71
|
+
end
|
72
|
+
|
73
|
+
namespace :load do
|
74
|
+
task :defaults do
|
75
|
+
set :knife_check_disable, false
|
76
|
+
set :knife_args, nil
|
77
|
+
|
78
|
+
set :knife_startup_script, nil
|
79
|
+
set :knife_sudo_command, nil
|
80
|
+
set :knife_host_key_verify, false
|
81
|
+
set :knife_cookbook_path, %w{cookbooks site-cookbooks}
|
82
|
+
set :knife_node_path, "#{fetch(:tmp_dir)}/capistrano-knife-solo"
|
83
|
+
set :knife_berkshelf, true
|
84
|
+
set :knife_librarian, true
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'chef/knife/solo_prepare'
|
2
|
+
require 'chef/knife/solo_cook'
|
3
|
+
require 'chef/knife/solo_clean'
|
4
|
+
require 'knife-solo/librarian'
|
5
|
+
require 'knife-solo/berkshelf'
|
6
|
+
|
7
|
+
load File.expand_path('../capistrano-knife-solo/tasks/tasks.rake', __FILE__)
|
8
|
+
|
9
|
+
module CapistranoKnifeSolo
|
10
|
+
class Helpers
|
11
|
+
|
12
|
+
def self.chef_config
|
13
|
+
Chef::Config[:knife][:librarian] = fetch(:knife_librarian)
|
14
|
+
Chef::Config[:knife][:berkshelf] = fetch(:knife_berkshelf)
|
15
|
+
Chef::Config[:node_path] = fetch(:knife_node_path)
|
16
|
+
Chef::Config.cookbook_path = fetch(:knife_cookbook_path)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.knife_config(host)
|
20
|
+
ssh_options = fetch(:ssh_options)
|
21
|
+
options = {}
|
22
|
+
options[:ssh_user] = ssh_options[:user] if ssh_options[:user]
|
23
|
+
options[:ssh_password] = ssh_options[:password] if ssh_options[:password]
|
24
|
+
options[:ssh_port] = ssh_options[:port] if ssh_options[:port]
|
25
|
+
options[:identity_file] = ssh_options[:keys][0] if ssh_options[:keys][0]
|
26
|
+
options[:forward_agent] = ssh_options[:forward_agent] if ssh_options[:forward_agent]
|
27
|
+
options[:startup_script] = fetch(:knife_startup_script) if fetch(:knife_startup_script)
|
28
|
+
options[:sudo_command] = fetch(:knife_sudo_command) if fetch(:knife_sudo_command)
|
29
|
+
options[:host_key_verify] = fetch(:knife_host_key_verify) if fetch(:knife_host_key_verify)
|
30
|
+
options[:run_list] = roles_to_runlist(host)
|
31
|
+
return options
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.knife_args(host)
|
35
|
+
args = []
|
36
|
+
args << host.hostname
|
37
|
+
args << "#{fetch(:knife_args)}" if fetch(:knife_args)
|
38
|
+
return args
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.roles_to_runlist(host)
|
42
|
+
roles = host.properties.roles.reject { |r| r.to_s.start_with?('server-') or r == :all }
|
43
|
+
roles.map! {|r| "role[#{r}]"}
|
44
|
+
return roles
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# monkey patches to avoid the permanent creation of a node config
|
51
|
+
class Chef
|
52
|
+
class Knife
|
53
|
+
class SoloCook
|
54
|
+
|
55
|
+
alias vendor_cook cook
|
56
|
+
|
57
|
+
def cook
|
58
|
+
# run the knife-solo cook command
|
59
|
+
vendor_cook
|
60
|
+
# clean up after the config we created
|
61
|
+
ui.msg "Removing temporary Node config '#{node_config}'..."
|
62
|
+
FileUtils.rm_r node_config
|
63
|
+
end
|
64
|
+
|
65
|
+
def node_config
|
66
|
+
# create the directory first as it's tmp and may not exist
|
67
|
+
FileUtils.mkdir_p Pathname.new(Chef::Config[:node_path])
|
68
|
+
# don't default to using args for the path
|
69
|
+
Pathname.new("#{nodes_path}/#{node_name}.json")
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capistrano-knife-solo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Robert Coleman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-02-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.5'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.5'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: pry
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: capistrano
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 3.1.0
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 3.1.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: knife-solo
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0.4'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.4'
|
94
|
+
description: Use knife solo with Capistrano.
|
95
|
+
email:
|
96
|
+
- github@robert.net.nz
|
97
|
+
executables: []
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- .gitignore
|
102
|
+
- Gemfile
|
103
|
+
- LICENSE
|
104
|
+
- README.md
|
105
|
+
- Rakefile
|
106
|
+
- capistrano-knife-solo.gemspec
|
107
|
+
- lib/capistrano-knife-solo.rb
|
108
|
+
- lib/capistrano-knife-solo/tasks/tasks.rake
|
109
|
+
- lib/capistrano-knife-solo/version.rb
|
110
|
+
homepage: https://github.com/rjocoleman/capistrano-knife-solo
|
111
|
+
licenses:
|
112
|
+
- MIT
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
none: false
|
125
|
+
requirements:
|
126
|
+
- - ! '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
requirements: []
|
130
|
+
rubyforge_project:
|
131
|
+
rubygems_version: 1.8.23
|
132
|
+
signing_key:
|
133
|
+
specification_version: 3
|
134
|
+
summary: Use knife solo with Capistrano.
|
135
|
+
test_files: []
|