chake 0.21 → 0.81.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ackrc +2 -0
- data/.gitignore +22 -0
- data/.gitlab-ci.yml +24 -0
- data/.manifest +65 -0
- data/.rubocop.yml +55 -0
- data/.rubocop_todo.yml +40 -0
- data/ChangeLog.md +37 -0
- data/README.chef.md +70 -0
- data/README.itamae.md +58 -0
- data/README.md +118 -85
- data/README.shell.md +30 -0
- data/Rakefile +36 -10
- data/bin/chake +2 -2
- data/chake.gemspec +16 -16
- data/examples/test/.ssh_config +4 -0
- data/examples/test/Rakefile +1 -1
- data/examples/test/Vagrantfile +6 -0
- data/examples/test/config.rb +4 -4
- data/examples/test/cookbooks/basics/recipes/default.rb +1 -0
- data/examples/test/cookbooks/example/files/default/test +1 -0
- data/examples/test/cookbooks/example/files/{host-homer → host-lemur}/test.asc +0 -0
- data/lib/chake.rb +111 -153
- data/lib/chake/bootstrap/chef/01_installed.sh +4 -0
- data/lib/chake/bootstrap/{01_debian.sh → chef/02_debian.sh} +0 -0
- data/lib/chake/bootstrap/{99_unsupported.sh → chef/99_unsupported.sh} +0 -0
- data/lib/chake/config.rb +2 -7
- data/lib/chake/config_manager.rb +89 -0
- data/lib/chake/config_manager/chef.rb +35 -0
- data/lib/chake/config_manager/itamae.rb +57 -0
- data/lib/chake/config_manager/shell.rb +34 -0
- data/lib/chake/config_manager/skel/chef/Rakefile +1 -0
- data/lib/chake/config_manager/skel/chef/config.rb +4 -0
- data/lib/chake/config_manager/skel/chef/cookbooks/basics/recipes/default.rb +1 -0
- data/lib/chake/config_manager/skel/chef/nodes.yaml +3 -0
- data/lib/chake/config_manager/skel/itamae/Rakefile +1 -0
- data/lib/chake/config_manager/skel/itamae/cookbooks/basics/default.rb +1 -0
- data/lib/chake/config_manager/skel/itamae/nodes.yaml +3 -0
- data/lib/chake/config_manager/skel/itamae/roles/basic.rb +1 -0
- data/lib/chake/config_manager/skel/shell/Rakefile +1 -0
- data/lib/chake/config_manager/skel/shell/nodes.yaml +3 -0
- data/lib/chake/connection.rb +83 -0
- data/lib/chake/{backend → connection}/local.rb +2 -8
- data/lib/chake/{backend → connection}/ssh.rb +6 -14
- data/lib/chake/node.rb +49 -29
- data/lib/chake/readline.rb +6 -10
- data/lib/chake/version.rb +1 -1
- data/lib/chake/wipe.rb +18 -0
- data/man/.gitignore +2 -0
- data/man/Rakefile +28 -14
- data/man/readme2man.sed +5 -5
- data/spec/chake/backend/local_spec.rb +5 -6
- data/spec/chake/backend/ssh_spec.rb +8 -10
- data/spec/chake/backend_spec.rb +1 -2
- data/spec/chake/config_manager/chef_spec.rb +38 -0
- data/spec/chake/config_manager/itamae_spec.rb +87 -0
- data/spec/chake/config_manager/shell_spec.rb +54 -0
- data/spec/chake/config_manager_spec.rb +23 -0
- data/spec/chake/node_spec.rb +38 -15
- data/spec/spec_helper.rb +37 -17
- metadata +65 -39
- data/coverage/assets/0.11.0/application.css +0 -809
- data/coverage/assets/0.11.0/application.js +0 -43679
- data/coverage/assets/0.11.0/colorbox/border.png +0 -0
- data/coverage/assets/0.11.0/colorbox/controls.png +0 -0
- data/coverage/assets/0.11.0/colorbox/loading.gif +0 -0
- data/coverage/assets/0.11.0/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.11.0/favicon_green.png +0 -0
- data/coverage/assets/0.11.0/favicon_red.png +0 -0
- data/coverage/assets/0.11.0/favicon_yellow.png +0 -0
- data/coverage/assets/0.11.0/loading.gif +0 -0
- data/coverage/assets/0.11.0/magnify.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.11.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/index.html +0 -4158
- data/lib/chake/backend.rb +0 -80
- data/tags +0 -72
data/README.shell.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
chake-shell(7) -- configure chake nodes with shell
|
2
|
+
==================================================
|
3
|
+
|
4
|
+
## Description
|
5
|
+
|
6
|
+
This configuration manager is a simpler wrapper for running a list of shell
|
7
|
+
commands on the nodes.
|
8
|
+
|
9
|
+
## Configuration
|
10
|
+
|
11
|
+
The _shell_ configuration manager requires one key called `shell`, and the
|
12
|
+
value must be a list of strings representing the list of commands to run on the
|
13
|
+
node when converging.
|
14
|
+
|
15
|
+
```yaml
|
16
|
+
host1.mycompany.com:
|
17
|
+
shell:
|
18
|
+
- echo "HELLO WORLD"
|
19
|
+
```
|
20
|
+
|
21
|
+
## Bootstrapping
|
22
|
+
|
23
|
+
Very little bootstrapping is required for this configuration manager, as we
|
24
|
+
hope every node you could possibly want to manage with it already has a POSIX
|
25
|
+
shell as `/bin/sh`. During bootstrapping, only the node hostname will be set
|
26
|
+
according to your chake configuration.
|
27
|
+
|
28
|
+
## See also
|
29
|
+
|
30
|
+
* **chake(1)**
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
namespace :bundler do
|
2
|
-
require
|
2
|
+
require 'bundler/gem_tasks'
|
3
3
|
end
|
4
4
|
|
5
5
|
task :test do
|
@@ -8,6 +8,8 @@ end
|
|
8
8
|
|
9
9
|
pkg = Gem::Specification.load('chake.gemspec')
|
10
10
|
|
11
|
+
task 'bundler:build' => :manifest
|
12
|
+
|
11
13
|
task 'build:tarball' => 'bundler:build' do
|
12
14
|
chdir 'pkg' do
|
13
15
|
sh 'gem2tgz', "#{pkg.name}-#{pkg.version}.gem"
|
@@ -17,7 +19,7 @@ end
|
|
17
19
|
desc 'Create Debian source package'
|
18
20
|
task 'build:debsrc' => ['bundler:clobber', 'build:tarball'] do
|
19
21
|
dirname = "#{pkg.name}-#{pkg.version}"
|
20
|
-
v = `git describe`.strip.
|
22
|
+
v = `git describe`.strip.tr('-', '.').sub(/^v/, '')
|
21
23
|
chdir 'pkg' do
|
22
24
|
sh 'gem2deb', '--no-wnpp-check', '-s', '-p', pkg.name, "#{dirname}.tar.gz"
|
23
25
|
sh "rename s/#{pkg.version}/#{v}/ *.orig.tar.gz"
|
@@ -31,7 +33,7 @@ task 'build:debsrc' => ['bundler:clobber', 'build:tarball'] do
|
|
31
33
|
end
|
32
34
|
|
33
35
|
desc 'Builds and installs Debian package'
|
34
|
-
task 'deb:install' => 'build:debsrc'do
|
36
|
+
task 'deb:install' => 'build:debsrc' do
|
35
37
|
chdir "pkg/#{pkg.name}-#{pkg.version}" do
|
36
38
|
sh 'dpkg-buildpackage --diff-ignore=version.rb -us -uc'
|
37
39
|
sh 'debi'
|
@@ -48,7 +50,7 @@ end
|
|
48
50
|
file 'pkg/chake.spec' => ['chake.spec.erb', 'lib/chake/version.rb'] do |t|
|
49
51
|
require 'erb'
|
50
52
|
pkg = Gem::Specification.load('chake.gemspec')
|
51
|
-
template =
|
53
|
+
template = ERB.new(File.read('chake.spec.erb'))
|
52
54
|
File.open(t.name, 'w') do |f|
|
53
55
|
f.puts(template.result(binding))
|
54
56
|
end
|
@@ -60,27 +62,51 @@ task 'build:all' => ['build:debsrc', 'build:rpmsrc']
|
|
60
62
|
desc 'lists changes since last release'
|
61
63
|
task :changelog do
|
62
64
|
last_tag = `git tag | sort -V`.split.last
|
63
|
-
sh 'git', 'shortlog', last_tag
|
65
|
+
sh 'git', 'shortlog', "#{last_tag}.."
|
64
66
|
end
|
65
67
|
|
66
68
|
task :check_tag do
|
67
69
|
last_tag = `git tag | sort -V`.split.last
|
68
70
|
if last_tag == "v#{pkg.version}"
|
69
|
-
|
71
|
+
raise "Version #{pkg.version} was already released!"
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
73
75
|
desc 'checks if the latest release is properly documented in ChangeLog.md'
|
74
76
|
task :check_changelog do
|
75
77
|
begin
|
76
|
-
sh 'grep',
|
77
|
-
rescue
|
78
|
+
sh 'grep', "^#\\s*#{pkg.version}", 'ChangeLog.md'
|
79
|
+
rescue StandardError
|
78
80
|
puts "Version #{pkg.version} not documented in ChangeLog.md!"
|
79
81
|
raise
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
85
|
+
desc 'Updates manifest file'
|
86
|
+
task :manifest do
|
87
|
+
manifest = File.read('.manifest')
|
88
|
+
git = `git ls-files`
|
89
|
+
if manifest != git
|
90
|
+
File.open('.manifest', 'w') { |f| f.write(git) }
|
91
|
+
sh 'git commit .manifest -m "Update manifest"'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
83
95
|
desc 'Makes a release'
|
84
|
-
task :
|
96
|
+
task release: [:check_tag, :check_changelog, :test, 'bundler:release']
|
97
|
+
|
98
|
+
desc 'Check coding style'
|
99
|
+
task :style do
|
100
|
+
sh 'rubocop'
|
101
|
+
end
|
102
|
+
|
103
|
+
desc 'Check spelling in the source code'
|
104
|
+
task :codespell do
|
105
|
+
sh 'codespell', '--skip=.git', '--skip=coverage', '--skip=*.asc', '--skip=*.swp'
|
106
|
+
end
|
107
|
+
|
108
|
+
task default: [:test, :style, :codespell]
|
109
|
+
|
110
|
+
task clean: 'bundler:clobber'
|
85
111
|
|
86
|
-
|
112
|
+
load './man/Rakefile'
|
data/bin/chake
CHANGED
@@ -4,7 +4,7 @@ require 'rake'
|
|
4
4
|
|
5
5
|
rakefiles = %w[rakefile Rakefile rakefile.rb Rakefile.rb]
|
6
6
|
|
7
|
-
if
|
7
|
+
if rakefiles.none? { |f| File.exist?(f) } && !ARGV.include?('-f') && !ARGV.include?('--rakefile')
|
8
8
|
require 'tmpdir'
|
9
9
|
require 'fileutils'
|
10
10
|
|
@@ -24,7 +24,7 @@ end
|
|
24
24
|
|
25
25
|
class Rake::Application
|
26
26
|
alias orig_thread_pool thread_pool
|
27
|
-
def thread_pool
|
27
|
+
def thread_pool # :nodoc:
|
28
28
|
if Chake.respond_to?(:nodes)
|
29
29
|
@thread_pool ||= Rake::ThreadPool.new(Chake.nodes.size + 1)
|
30
30
|
else
|
data/chake.gemspec
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'chake/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
6
|
+
spec.name = 'chake'
|
8
7
|
spec.version = Chake::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
8
|
+
spec.authors = ['Antonio Terceiro']
|
9
|
+
spec.email = ['terceiro@softwarelivre.org']
|
10
|
+
spec.summary = 'serverless configuration management tool for chef'
|
11
|
+
spec.description = "chake allows one to manage a number of hosts via SSH by combining chef (solo) and rake. It doesn't require a chef server; all you need is a workstation from where you can SSH into all your hosts. chake automates copying the configuration management repository to the target host (including managing encrypted files), running chef on them, and running arbitrary commands on the hosts."
|
12
|
+
spec.homepage = 'https://gitlab.com/terceiro/chake'
|
13
|
+
spec.license = 'MIT'
|
15
14
|
|
16
|
-
spec.files =
|
15
|
+
spec.files = File.read('.manifest').split("\n") + ['.manifest']
|
17
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
18
|
+
spec.require_paths = ['lib']
|
20
19
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
21
|
+
spec.add_development_dependency 'ronn-ng'
|
22
|
+
spec.add_development_dependency 'rspec'
|
23
|
+
spec.add_development_dependency 'rubocop'
|
24
|
+
spec.add_development_dependency 'simplecov'
|
25
25
|
|
26
|
-
spec.add_dependency
|
26
|
+
spec.add_dependency 'rake'
|
27
27
|
end
|
data/examples/test/Rakefile
CHANGED
data/examples/test/config.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
root =
|
2
|
-
file_cache_path root
|
3
|
-
cookbook_path root
|
4
|
-
role_path root
|
1
|
+
root = __dir__
|
2
|
+
file_cache_path "#{root}/cache"
|
3
|
+
cookbook_path "#{root}/cookbooks"
|
4
|
+
role_path "#{root}/config/roles"
|
@@ -0,0 +1 @@
|
|
1
|
+
package 'openssh-server'
|
@@ -0,0 +1 @@
|
|
1
|
+
test
|
File without changes
|
data/lib/chake.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
require 'yaml'
|
4
2
|
require 'json'
|
5
3
|
require 'tmpdir'
|
@@ -7,159 +5,117 @@ require 'tmpdir'
|
|
7
5
|
require 'chake/config'
|
8
6
|
require 'chake/version'
|
9
7
|
require 'chake/readline'
|
10
|
-
require 'chake/
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
File.open('nodes.yaml', 'w') do |f|
|
19
|
-
sample_nodes = <<EOF
|
20
|
-
host1.mycompany.com:
|
21
|
-
run_list:
|
22
|
-
- recipe[basics]
|
23
|
-
EOF
|
24
|
-
f.write(sample_nodes)
|
25
|
-
puts "[create] nodes.yaml"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
if File.exist?('nodes.d')
|
30
|
-
puts '[exists] nodes.d/'
|
31
|
-
else
|
32
|
-
FileUtils.mkdir_p 'nodes.d'
|
33
|
-
puts '[ mkdir] nodes.d/'
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
if File.exists?('config.rb')
|
38
|
-
puts '[exists] config.rb'
|
39
|
-
else
|
40
|
-
File.open('config.rb', 'w') do |f|
|
41
|
-
f.puts "root = File.expand_path(File.dirname(__FILE__))"
|
42
|
-
f.puts "file_cache_path root + '/cache'"
|
43
|
-
f.puts "cookbook_path root + '/cookbooks'"
|
44
|
-
f.puts "role_path root + '/config/roles'"
|
45
|
-
end
|
46
|
-
puts "[create] config.rb"
|
47
|
-
end
|
48
|
-
|
49
|
-
if !File.exist?('config/roles')
|
50
|
-
FileUtils.mkdir_p 'config/roles'
|
51
|
-
puts '[ mkdir] config/roles'
|
52
|
-
end
|
53
|
-
if !File.exist?('cookbooks/basics/recipes')
|
54
|
-
FileUtils.mkdir_p 'cookbooks/basics/recipes/'
|
55
|
-
puts '[ mkdir] cookbooks/basics/recipes/'
|
56
|
-
end
|
57
|
-
recipe = 'cookbooks/basics/recipes/default.rb'
|
58
|
-
if File.exists?(recipe)
|
59
|
-
puts "[exists] #{recipe}"
|
60
|
-
else
|
61
|
-
File.open(recipe, 'w') do |f|
|
62
|
-
f.puts "package 'openssh-server'"
|
63
|
-
end
|
64
|
-
puts "[create] #{recipe}"
|
65
|
-
end
|
66
|
-
if File.exists?('Rakefile')
|
67
|
-
puts '[exists] Rakefile'
|
68
|
-
else
|
69
|
-
File.open('Rakefile', 'w') do |f|
|
70
|
-
f.puts 'require "chake"'
|
71
|
-
puts '[create] Rakefile'
|
72
|
-
end
|
8
|
+
require 'chake/wipe'
|
9
|
+
|
10
|
+
desc 'Initializes current directory with sample structure'
|
11
|
+
task init: 'init:itamae'
|
12
|
+
Chake::ConfigManager.all.map do |cfgmgr|
|
13
|
+
desc "Initializes current directory for #{cfgmgr.short_name}"
|
14
|
+
task "init:#{cfgmgr.short_name}" do
|
15
|
+
cfgmgr.init
|
73
16
|
end
|
74
17
|
end
|
75
18
|
|
76
19
|
desc 'list nodes'
|
77
20
|
task :nodes do
|
21
|
+
fields = %i[hostname connection config_manager]
|
22
|
+
lengths = fields.map do |f|
|
23
|
+
[f.length, Chake.nodes.map { |n| n.send(f).to_s.length }.max].max
|
24
|
+
end
|
25
|
+
columns = lengths.map { |l| "%-#{l}s"}.join(" ")
|
26
|
+
puts(columns % fields)
|
27
|
+
puts(columns % lengths.map { |l| '-' * l })
|
78
28
|
Chake.nodes.each do |node|
|
79
|
-
puts
|
29
|
+
puts(columns % fields.map { |f| node.send(f) })
|
80
30
|
end
|
81
31
|
end
|
82
32
|
|
83
33
|
def encrypted_for(node)
|
84
|
-
encrypted_files = Dir.glob("**/files/{default,host-#{node}}/*.{asc,gpg}") + Dir.glob(
|
85
|
-
encrypted_files.
|
34
|
+
encrypted_files = Dir.glob("**/files/{default,host-#{node}}/*.{asc,gpg}") + Dir.glob('**/files/*.{asc,gpg}')
|
35
|
+
encrypted_files.each_with_object({}) do |key, hash|
|
86
36
|
hash[key] = key.sub(/\.(asc|gpg)$/, '')
|
87
|
-
hash
|
88
37
|
end
|
89
38
|
end
|
90
39
|
|
91
|
-
def
|
92
|
-
if
|
93
|
-
return
|
40
|
+
def maybe_decrypt(node)
|
41
|
+
if node.needs_upload?
|
42
|
+
return yield
|
43
|
+
end
|
44
|
+
|
45
|
+
files = encrypted_for(node.hostname)
|
46
|
+
files.each do |encrypted, target|
|
47
|
+
sh "gpg --use-agent --quiet --decrypt --output #{target} #{encrypted}"
|
48
|
+
end
|
49
|
+
begin
|
50
|
+
yield
|
51
|
+
ensure
|
52
|
+
files.each do |_, target|
|
53
|
+
Chake::Wipe.instance.wipe(target)
|
54
|
+
end
|
94
55
|
end
|
95
|
-
|
56
|
+
end
|
57
|
+
|
58
|
+
def if_files_changed(node, group_name, files)
|
59
|
+
return if files.empty?
|
60
|
+
|
61
|
+
hash_io = IO.popen(%w[xargs sha1sum], 'w+')
|
96
62
|
files.sort.each { |f| hash_io.puts(f) }
|
97
63
|
hash_io.close_write
|
98
64
|
current_hash = hash_io.read
|
99
65
|
|
100
|
-
hash_file = File.join(Chake.tmpdir, node
|
66
|
+
hash_file = File.join(Chake.tmpdir, "#{node}.#{group_name}.sha1sum")
|
101
67
|
hash_on_disk = nil
|
102
|
-
if File.
|
103
|
-
hash_on_disk = File.read(hash_file)
|
104
|
-
end
|
68
|
+
hash_on_disk = File.read(hash_file) if File.exist?(hash_file)
|
105
69
|
|
106
|
-
if current_hash != hash_on_disk
|
107
|
-
yield
|
108
|
-
end
|
70
|
+
yield if current_hash != hash_on_disk
|
109
71
|
FileUtils.mkdir_p(File.dirname(hash_file))
|
110
72
|
File.open(hash_file, 'w') do |f|
|
111
73
|
f.write(current_hash)
|
112
74
|
end
|
113
75
|
end
|
114
76
|
|
115
|
-
|
116
77
|
def write_json_file(file, data)
|
117
|
-
File.chmod(
|
118
|
-
File.open(file, 'w',
|
78
|
+
File.chmod(0o600, file) if File.exist?(file)
|
79
|
+
File.open(file, 'w', 0o600) do |f|
|
119
80
|
f.write(JSON.pretty_generate(data))
|
120
81
|
f.write("\n")
|
121
82
|
end
|
122
83
|
end
|
123
84
|
|
124
|
-
bootstrap_steps = Dir.glob(File.expand_path('chake/bootstrap/*.sh', File.dirname(__FILE__))).sort
|
125
|
-
|
126
85
|
desc 'Executed before bootstrapping'
|
127
|
-
task :
|
86
|
+
task bootstrap_common: :connect_common
|
128
87
|
|
129
88
|
desc 'Executed before uploading'
|
130
|
-
task :
|
89
|
+
task upload_common: :connect_common
|
131
90
|
|
132
91
|
desc 'Executed before uploading'
|
133
|
-
task :
|
92
|
+
task converge_common: :connect_common
|
134
93
|
|
135
94
|
desc 'Executed before connecting to any host'
|
136
95
|
task :connect_common
|
137
96
|
|
138
97
|
Chake.nodes.each do |node|
|
98
|
+
node.silent = Rake.application.options.silent
|
139
99
|
|
140
100
|
hostname = node.hostname
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
f.puts 'set -eu'
|
148
|
-
bootstrap_steps.each do |platform|
|
149
|
-
f.puts(File.read(platform))
|
150
|
-
end
|
151
|
-
end
|
152
|
-
chmod 0755, t.name
|
153
|
-
end
|
101
|
+
|
102
|
+
bootstrap_script = File.join(Chake.tmpdir, "#{hostname}.bootstrap")
|
103
|
+
|
104
|
+
bootstrap_steps = node.bootstrap_steps
|
105
|
+
|
106
|
+
bootstrap_code = (["#!/bin/sh\n", "set -eu\n"] + bootstrap_steps.map { |f| File.read(f) }).join
|
154
107
|
|
155
108
|
desc "bootstrap #{hostname}"
|
156
|
-
task "bootstrap:#{hostname}" =>
|
157
|
-
|
109
|
+
task "bootstrap:#{hostname}" => :bootstrap_common do
|
110
|
+
mkdir_p Chake.tmpdir unless File.directory?(Chake.tmpdir)
|
111
|
+
if !File.exist?(bootstrap_script) || File.read(bootstrap_script) != bootstrap_code
|
112
|
+
|
113
|
+
# create bootstrap script
|
114
|
+
File.open(bootstrap_script, 'w') do |f|
|
115
|
+
f.write(bootstrap_code)
|
116
|
+
end
|
117
|
+
chmod 0o755, bootstrap_script
|
158
118
|
|
159
|
-
if File.exists?(config)
|
160
|
-
# already bootstrapped, just overwrite
|
161
|
-
write_json_file(config, node.data)
|
162
|
-
else
|
163
119
|
# copy bootstrap script over
|
164
120
|
scp = node.scp
|
165
121
|
target = "/tmp/.chake-bootstrap.#{Etc.getpwuid.name}"
|
@@ -167,28 +123,29 @@ Chake.nodes.each do |node|
|
|
167
123
|
|
168
124
|
# run bootstrap script
|
169
125
|
node.run_as_root("#{target} #{hostname}")
|
170
|
-
|
171
|
-
# overwrite config with current contents
|
172
|
-
mkdir_p File.dirname(config)
|
173
|
-
write_json_file(config, node.data)
|
174
126
|
end
|
175
127
|
|
128
|
+
# overwrite config with current contents
|
129
|
+
config = File.join(Chake.tmpdir, "#{hostname}.json")
|
130
|
+
write_json_file(config, node.data)
|
176
131
|
end
|
177
132
|
|
178
133
|
desc "upload data to #{hostname}"
|
179
134
|
task "upload:#{hostname}" => :upload_common do
|
135
|
+
next unless node.needs_upload?
|
136
|
+
|
180
137
|
encrypted = encrypted_for(hostname)
|
181
|
-
rsync_excludes = (encrypted.values + encrypted.keys).map { |f| [
|
182
|
-
rsync_excludes <<
|
183
|
-
rsync_excludes <<
|
184
|
-
rsync_excludes <<
|
185
|
-
rsync_excludes <<
|
138
|
+
rsync_excludes = (encrypted.values + encrypted.keys).map { |f| ['--exclude', f] }.flatten
|
139
|
+
rsync_excludes << '--exclude' << '.git/'
|
140
|
+
rsync_excludes << '--exclude' << 'cache/'
|
141
|
+
rsync_excludes << '--exclude' << 'nodes/'
|
142
|
+
rsync_excludes << '--exclude' << 'local-mode-cache/'
|
186
143
|
|
187
|
-
rsync = node.rsync + [
|
144
|
+
rsync = node.rsync + ['-avp'] + ENV.fetch('CHAKE_RSYNC_OPTIONS', '').split
|
188
145
|
rsync_logging = Rake.application.options.silent && '--quiet' || '--verbose'
|
189
146
|
|
190
147
|
hash_files = Dir.glob(File.join(Chake.tmpdir, '*.sha1sum'))
|
191
|
-
files = Dir.glob(
|
148
|
+
files = Dir.glob('**/*').reject { |f| File.directory?(f) } - encrypted.keys - encrypted.values - hash_files
|
192
149
|
if_files_changed(hostname, 'plain', files) do
|
193
150
|
sh *rsync, '--delete', rsync_logging, *rsync_excludes, './', node.rsync_dest
|
194
151
|
end
|
@@ -199,14 +156,14 @@ Chake.nodes.each do |node|
|
|
199
156
|
target = File.join(tmpdir, target_file)
|
200
157
|
mkdir_p(File.dirname(target))
|
201
158
|
rm_f target
|
202
|
-
File.open(target, 'w',
|
159
|
+
File.open(target, 'w', 0o400) do |output|
|
203
160
|
IO.popen(['gpg', '--quiet', '--batch', '--use-agent', '--decrypt', encrypted_file]) do |data|
|
204
161
|
output.write(data.read)
|
205
162
|
end
|
206
163
|
end
|
207
164
|
puts "#{target} (decrypted)"
|
208
165
|
end
|
209
|
-
sh *rsync, rsync_logging, tmpdir
|
166
|
+
sh *rsync, rsync_logging, "#{tmpdir}/", node.rsync_dest
|
210
167
|
end
|
211
168
|
end
|
212
169
|
end
|
@@ -215,19 +172,21 @@ Chake.nodes.each do |node|
|
|
215
172
|
|
216
173
|
desc "converge #{hostname}"
|
217
174
|
task "converge:#{hostname}" => converge_dependencies do
|
218
|
-
|
219
|
-
|
175
|
+
maybe_decrypt(node) do
|
176
|
+
node.converge
|
177
|
+
end
|
220
178
|
end
|
221
179
|
|
222
180
|
desc 'apply <recipe> on #{hostname}'
|
223
|
-
task "apply:#{hostname}", [:recipe] => [
|
224
|
-
|
225
|
-
|
181
|
+
task "apply:#{hostname}", [:recipe] => %i[recipe_input connect_common] do |_task, _args|
|
182
|
+
maybe_decrypt(node) do
|
183
|
+
node.apply($recipe_to_apply)
|
184
|
+
end
|
226
185
|
end
|
227
186
|
task "apply:#{hostname}" => converge_dependencies
|
228
187
|
|
229
188
|
desc "run a command on #{hostname}"
|
230
|
-
task "run:#{hostname}", [:command] => [
|
189
|
+
task "run:#{hostname}", [:command] => %i[run_input connect_common] do
|
231
190
|
node.run($cmd_to_run)
|
232
191
|
end
|
233
192
|
|
@@ -240,32 +199,31 @@ Chake.nodes.each do |node|
|
|
240
199
|
task "check:#{hostname}" => :connect_common do
|
241
200
|
node.run('sudo echo OK')
|
242
201
|
end
|
243
|
-
|
244
202
|
end
|
245
203
|
|
246
|
-
task :run_input, :command do |
|
204
|
+
task :run_input, :command do |_task, args|
|
247
205
|
$cmd_to_run = args[:command]
|
248
|
-
|
249
|
-
puts
|
206
|
+
unless $cmd_to_run
|
207
|
+
puts '# Enter command to run (use arrow keys for history):'
|
250
208
|
$cmd_to_run = Chake::Readline::Commands.readline
|
251
209
|
end
|
252
210
|
if !$cmd_to_run || $cmd_to_run.strip == ''
|
253
211
|
puts
|
254
|
-
puts
|
212
|
+
puts 'I: no command provided, operation aborted.'
|
255
213
|
exit(1)
|
256
214
|
end
|
257
215
|
end
|
258
216
|
|
259
|
-
task :recipe_input, :recipe do |
|
217
|
+
task :recipe_input, :recipe do |_task, args|
|
260
218
|
$recipe_to_apply = args[:recipe]
|
261
219
|
|
262
|
-
|
220
|
+
unless $recipe_to_apply
|
263
221
|
recipes = Dir['**/*/recipes/*.rb'].map do |f|
|
264
222
|
f =~ %r{(.*/)?(.*)/recipes/(.*).rb$}
|
265
|
-
cookbook =
|
266
|
-
recipe =
|
223
|
+
cookbook = Regexp.last_match(2)
|
224
|
+
recipe = Regexp.last_match(3)
|
267
225
|
recipe = nil if recipe == 'default'
|
268
|
-
[cookbook,recipe].compact.join('::')
|
226
|
+
[cookbook, recipe].compact.join('::')
|
269
227
|
end.sort
|
270
228
|
puts 'Available recipes:'
|
271
229
|
|
@@ -276,43 +234,43 @@ task :recipe_input, :recipe do |task,args|
|
|
276
234
|
$recipe_to_apply = Chake::Readline::Recipes.readline
|
277
235
|
if !$recipe_to_apply || $recipe_to_apply.empty?
|
278
236
|
puts
|
279
|
-
puts
|
237
|
+
puts 'I: no recipe provided, operation aborted.'
|
280
238
|
exit(1)
|
281
239
|
end
|
282
|
-
|
240
|
+
unless recipes.include?($recipe_to_apply)
|
283
241
|
abort "E: no such recipe: #{$recipe_to_apply}"
|
284
242
|
end
|
285
243
|
end
|
286
244
|
end
|
287
245
|
|
288
|
-
desc
|
289
|
-
multitask :
|
246
|
+
desc 'upload to all nodes'
|
247
|
+
multitask upload: Chake.nodes.map { |node| "upload:#{node.hostname}" }
|
290
248
|
|
291
|
-
desc
|
292
|
-
multitask :
|
249
|
+
desc 'bootstrap all nodes'
|
250
|
+
multitask bootstrap: Chake.nodes.map { |node| "bootstrap:#{node.hostname}" }
|
293
251
|
|
294
|
-
desc
|
295
|
-
multitask
|
252
|
+
desc 'converge all nodes (default)'
|
253
|
+
multitask 'converge' => Chake.nodes.map { |node| "converge:#{node.hostname}" }
|
296
254
|
|
297
|
-
desc
|
298
|
-
multitask
|
255
|
+
desc 'Apply <recipe> on all nodes'
|
256
|
+
multitask 'apply', [:recipe] => Chake.nodes.map { |node| "apply:#{node.hostname}" }
|
299
257
|
|
300
|
-
desc
|
258
|
+
desc 'run <command> on all nodes'
|
301
259
|
multitask :run, [:command] => Chake.nodes.map { |node| "run:#{node.hostname}" }
|
302
260
|
|
303
|
-
task :
|
261
|
+
task default: :converge
|
304
262
|
|
305
263
|
desc 'checks connectivity and setup on all nodes'
|
306
|
-
multitask :
|
307
|
-
puts
|
308
|
-
puts
|
309
|
-
puts
|
264
|
+
multitask check: (Chake.nodes.map { |node| "check:#{node.hostname}" }) do
|
265
|
+
puts '✓ all hosts OK'
|
266
|
+
puts ' - ssh connection works'
|
267
|
+
puts ' - password-less sudo works'
|
310
268
|
end
|
311
269
|
|
312
270
|
desc 'runs a Ruby console in the chake environment'
|
313
271
|
task :console do
|
314
272
|
require 'irb'
|
315
|
-
IRB.setup(
|
273
|
+
IRB.setup('__FILE__', argv: [])
|
316
274
|
workspace = IRB::WorkSpace.new(self)
|
317
275
|
|
318
276
|
puts 'chake - interactive console'
|