chake 0.21.2 → 0.80
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ackrc +1 -0
- data/.gitignore +22 -0
- data/.gitlab-ci.yml +24 -0
- data/.manifest +63 -0
- data/.rubocop.yml +53 -0
- data/.rubocop_todo.yml +40 -0
- data/ChangeLog.md +15 -0
- data/README.chef.md +70 -0
- data/README.itamae.md +58 -0
- data/README.md +110 -85
- data/README.shell.md +30 -0
- data/Rakefile +34 -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 +86 -153
- data/lib/chake/bootstrap/{01_debian.sh → chef/01_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 +93 -0
- data/lib/chake/config_manager/chef.rb +35 -0
- data/lib/chake/config_manager/itamae.rb +58 -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/man/.gitignore +2 -0
- data/man/Rakefile +27 -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 +69 -0
- data/spec/chake/config_manager/shell_spec.rb +54 -0
- data/spec/chake/config_manager_spec.rb +24 -0
- data/spec/chake/node_spec.rb +38 -15
- data/spec/spec_helper.rb +20 -18
- metadata +63 -43
- 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/examples/test/nodes.yaml +0 -7
- data/examples/test/tmp/chake/test.local.bootstrap +0 -21
- data/examples/test/tmp/chake/test.local.json +0 -7
- data/examples/test/tmp/chake/test.local.plain.sha1sum +0 -9
- data/lib/chake/backend.rb +0 -80
- data/tags +0 -103
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,49 @@ 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]
|
85
109
|
|
86
|
-
|
110
|
+
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,96 @@ require 'tmpdir'
|
|
7
5
|
require 'chake/config'
|
8
6
|
require 'chake/version'
|
9
7
|
require 'chake/readline'
|
10
|
-
require 'chake/tmpdir'
|
11
|
-
|
12
|
-
|
13
|
-
desc "Initializes current directory with sample structure"
|
14
|
-
task :init do
|
15
|
-
if File.exists?('nodes.yaml')
|
16
|
-
puts '[exists] nodes.yaml'
|
17
|
-
else
|
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
8
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
9
|
+
desc 'Initializes current directory with sample structure'
|
10
|
+
task init: 'init:itamae'
|
11
|
+
Chake::ConfigManager.all.map do |cfgmgr|
|
12
|
+
desc "Initializes current directory for #{cfgmgr.short_name}"
|
13
|
+
task "init:#{cfgmgr.short_name}" do
|
14
|
+
cfgmgr.init
|
73
15
|
end
|
74
16
|
end
|
75
17
|
|
76
18
|
desc 'list nodes'
|
77
19
|
task :nodes do
|
78
|
-
|
79
|
-
|
20
|
+
fields = %i[hostname connection config_manager]
|
21
|
+
IO.popen(['column', '-t'], mode: 'w') do |table|
|
22
|
+
table.puts(fields.join(' '))
|
23
|
+
table.puts(fields.map { |f| '-' * f.length }.join(' '))
|
24
|
+
Chake.nodes.each do |node|
|
25
|
+
table.puts fields.map { |f| node.send(f) }.join(' ')
|
26
|
+
end
|
80
27
|
end
|
81
28
|
end
|
82
29
|
|
83
30
|
def encrypted_for(node)
|
84
|
-
encrypted_files = Dir.glob("**/files/{default,host-#{node}}/*.{asc,gpg}") + Dir.glob(
|
85
|
-
encrypted_files.
|
31
|
+
encrypted_files = Dir.glob("**/files/{default,host-#{node}}/*.{asc,gpg}") + Dir.glob('**/files/*.{asc,gpg}')
|
32
|
+
encrypted_files.each_with_object({}) do |key, hash|
|
86
33
|
hash[key] = key.sub(/\.(asc|gpg)$/, '')
|
87
|
-
hash
|
88
34
|
end
|
89
35
|
end
|
90
36
|
|
91
37
|
def if_files_changed(node, group_name, files)
|
92
|
-
if files.empty?
|
93
|
-
|
94
|
-
|
95
|
-
hash_io = IO.popen(['xargs', 'sha1sum'], 'w+')
|
38
|
+
return if files.empty?
|
39
|
+
|
40
|
+
hash_io = IO.popen(%w[xargs sha1sum], 'w+')
|
96
41
|
files.sort.each { |f| hash_io.puts(f) }
|
97
42
|
hash_io.close_write
|
98
43
|
current_hash = hash_io.read
|
99
44
|
|
100
|
-
hash_file = File.join(Chake.tmpdir, node
|
45
|
+
hash_file = File.join(Chake.tmpdir, "#{node}.#{group_name}.sha1sum")
|
101
46
|
hash_on_disk = nil
|
102
|
-
if File.
|
103
|
-
hash_on_disk = File.read(hash_file)
|
104
|
-
end
|
47
|
+
hash_on_disk = File.read(hash_file) if File.exist?(hash_file)
|
105
48
|
|
106
|
-
if current_hash != hash_on_disk
|
107
|
-
yield
|
108
|
-
end
|
49
|
+
yield if current_hash != hash_on_disk
|
109
50
|
FileUtils.mkdir_p(File.dirname(hash_file))
|
110
51
|
File.open(hash_file, 'w') do |f|
|
111
52
|
f.write(current_hash)
|
112
53
|
end
|
113
54
|
end
|
114
55
|
|
115
|
-
|
116
56
|
def write_json_file(file, data)
|
117
|
-
File.chmod(
|
118
|
-
File.open(file, 'w',
|
57
|
+
File.chmod(0o600, file) if File.exist?(file)
|
58
|
+
File.open(file, 'w', 0o600) do |f|
|
119
59
|
f.write(JSON.pretty_generate(data))
|
120
60
|
f.write("\n")
|
121
61
|
end
|
122
62
|
end
|
123
63
|
|
124
|
-
bootstrap_steps = Dir.glob(File.expand_path('chake/bootstrap/*.sh', File.dirname(__FILE__))).sort
|
125
|
-
|
126
64
|
desc 'Executed before bootstrapping'
|
127
|
-
task :
|
65
|
+
task bootstrap_common: :connect_common
|
128
66
|
|
129
67
|
desc 'Executed before uploading'
|
130
|
-
task :
|
68
|
+
task upload_common: :connect_common
|
131
69
|
|
132
70
|
desc 'Executed before uploading'
|
133
|
-
task :
|
71
|
+
task converge_common: :connect_common
|
134
72
|
|
135
73
|
desc 'Executed before connecting to any host'
|
136
74
|
task :connect_common
|
137
75
|
|
138
76
|
Chake.nodes.each do |node|
|
77
|
+
node.silent = Rake.application.options.silent
|
139
78
|
|
140
79
|
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
|
80
|
+
|
81
|
+
bootstrap_script = File.join(Chake.tmpdir, "#{hostname}.bootstrap")
|
82
|
+
|
83
|
+
bootstrap_steps = node.bootstrap_steps
|
84
|
+
|
85
|
+
bootstrap_code = (["#!/bin/sh\n", "set -eu\n"] + bootstrap_steps.map { |f| File.read(f) }).join
|
154
86
|
|
155
87
|
desc "bootstrap #{hostname}"
|
156
|
-
task "bootstrap:#{hostname}" =>
|
157
|
-
|
88
|
+
task "bootstrap:#{hostname}" => :bootstrap_common do
|
89
|
+
mkdir_p Chake.tmpdir unless File.directory?(Chake.tmpdir)
|
90
|
+
if node.needs_bootstrap? && (!File.exist?(bootstrap_script) || File.read(bootstrap_script) != bootstrap_code)
|
91
|
+
|
92
|
+
# create bootstrap script
|
93
|
+
File.open(bootstrap_script, 'w') do |f|
|
94
|
+
f.write(bootstrap_code)
|
95
|
+
end
|
96
|
+
chmod 0o755, bootstrap_script
|
158
97
|
|
159
|
-
if File.exists?(config)
|
160
|
-
# already bootstrapped, just overwrite
|
161
|
-
write_json_file(config, node.data)
|
162
|
-
else
|
163
98
|
# copy bootstrap script over
|
164
99
|
scp = node.scp
|
165
100
|
target = "/tmp/.chake-bootstrap.#{Etc.getpwuid.name}"
|
@@ -167,28 +102,29 @@ Chake.nodes.each do |node|
|
|
167
102
|
|
168
103
|
# run bootstrap script
|
169
104
|
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
105
|
end
|
175
106
|
|
107
|
+
# overwrite config with current contents
|
108
|
+
config = File.join(Chake.tmpdir, "#{hostname}.json")
|
109
|
+
write_json_file(config, node.data)
|
176
110
|
end
|
177
111
|
|
178
112
|
desc "upload data to #{hostname}"
|
179
113
|
task "upload:#{hostname}" => :upload_common do
|
114
|
+
next unless node.needs_upload?
|
115
|
+
|
180
116
|
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 <<
|
117
|
+
rsync_excludes = (encrypted.values + encrypted.keys).map { |f| ['--exclude', f] }.flatten
|
118
|
+
rsync_excludes << '--exclude' << '.git/'
|
119
|
+
rsync_excludes << '--exclude' << 'cache/'
|
120
|
+
rsync_excludes << '--exclude' << 'nodes/'
|
121
|
+
rsync_excludes << '--exclude' << 'local-mode-cache/'
|
186
122
|
|
187
|
-
rsync = node.rsync + [
|
123
|
+
rsync = node.rsync + ['-avp'] + ENV.fetch('CHAKE_RSYNC_OPTIONS', '').split
|
188
124
|
rsync_logging = Rake.application.options.silent && '--quiet' || '--verbose'
|
189
125
|
|
190
126
|
hash_files = Dir.glob(File.join(Chake.tmpdir, '*.sha1sum'))
|
191
|
-
files = Dir.glob(
|
127
|
+
files = Dir.glob('**/*').reject { |f| File.directory?(f) } - encrypted.keys - encrypted.values - hash_files
|
192
128
|
if_files_changed(hostname, 'plain', files) do
|
193
129
|
sh *rsync, '--delete', rsync_logging, *rsync_excludes, './', node.rsync_dest
|
194
130
|
end
|
@@ -199,14 +135,14 @@ Chake.nodes.each do |node|
|
|
199
135
|
target = File.join(tmpdir, target_file)
|
200
136
|
mkdir_p(File.dirname(target))
|
201
137
|
rm_f target
|
202
|
-
File.open(target, 'w',
|
138
|
+
File.open(target, 'w', 0o400) do |output|
|
203
139
|
IO.popen(['gpg', '--quiet', '--batch', '--use-agent', '--decrypt', encrypted_file]) do |data|
|
204
140
|
output.write(data.read)
|
205
141
|
end
|
206
142
|
end
|
207
143
|
puts "#{target} (decrypted)"
|
208
144
|
end
|
209
|
-
sh *rsync, rsync_logging, tmpdir
|
145
|
+
sh *rsync, rsync_logging, "#{tmpdir}/", node.rsync_dest
|
210
146
|
end
|
211
147
|
end
|
212
148
|
end
|
@@ -215,19 +151,17 @@ Chake.nodes.each do |node|
|
|
215
151
|
|
216
152
|
desc "converge #{hostname}"
|
217
153
|
task "converge:#{hostname}" => converge_dependencies do
|
218
|
-
|
219
|
-
node.run_as_root "sh -c 'rm -f #{node.path}/nodes/*.json && chef-solo -c #{node.path}/#{Chake.chef_config} #{chef_logging} -j #{node.path}/#{Chake.tmpdir}/#{hostname}.json'"
|
154
|
+
node.converge
|
220
155
|
end
|
221
156
|
|
222
157
|
desc 'apply <recipe> on #{hostname}'
|
223
|
-
task "apply:#{hostname}", [:recipe] => [
|
224
|
-
|
225
|
-
node.run_as_root "sh -c 'rm -f #{node.path}/nodes/*.json && chef-solo -c #{node.path}/#{Chake.chef_config} #{chef_logging} -j #{node.path}/#{Chake.tmpdir}/#{hostname}.json --override-runlist recipe[#{$recipe_to_apply}]'"
|
158
|
+
task "apply:#{hostname}", [:recipe] => %i[recipe_input connect_common] do |_task, _args|
|
159
|
+
node.apply($recipe_to_apply)
|
226
160
|
end
|
227
161
|
task "apply:#{hostname}" => converge_dependencies
|
228
162
|
|
229
163
|
desc "run a command on #{hostname}"
|
230
|
-
task "run:#{hostname}", [:command] => [
|
164
|
+
task "run:#{hostname}", [:command] => %i[run_input connect_common] do
|
231
165
|
node.run($cmd_to_run)
|
232
166
|
end
|
233
167
|
|
@@ -240,32 +174,31 @@ Chake.nodes.each do |node|
|
|
240
174
|
task "check:#{hostname}" => :connect_common do
|
241
175
|
node.run('sudo echo OK')
|
242
176
|
end
|
243
|
-
|
244
177
|
end
|
245
178
|
|
246
|
-
task :run_input, :command do |
|
179
|
+
task :run_input, :command do |_task, args|
|
247
180
|
$cmd_to_run = args[:command]
|
248
|
-
|
249
|
-
puts
|
181
|
+
unless $cmd_to_run
|
182
|
+
puts '# Enter command to run (use arrow keys for history):'
|
250
183
|
$cmd_to_run = Chake::Readline::Commands.readline
|
251
184
|
end
|
252
185
|
if !$cmd_to_run || $cmd_to_run.strip == ''
|
253
186
|
puts
|
254
|
-
puts
|
187
|
+
puts 'I: no command provided, operation aborted.'
|
255
188
|
exit(1)
|
256
189
|
end
|
257
190
|
end
|
258
191
|
|
259
|
-
task :recipe_input, :recipe do |
|
192
|
+
task :recipe_input, :recipe do |_task, args|
|
260
193
|
$recipe_to_apply = args[:recipe]
|
261
194
|
|
262
|
-
|
195
|
+
unless $recipe_to_apply
|
263
196
|
recipes = Dir['**/*/recipes/*.rb'].map do |f|
|
264
197
|
f =~ %r{(.*/)?(.*)/recipes/(.*).rb$}
|
265
|
-
cookbook =
|
266
|
-
recipe =
|
198
|
+
cookbook = Regexp.last_match(2)
|
199
|
+
recipe = Regexp.last_match(3)
|
267
200
|
recipe = nil if recipe == 'default'
|
268
|
-
[cookbook,recipe].compact.join('::')
|
201
|
+
[cookbook, recipe].compact.join('::')
|
269
202
|
end.sort
|
270
203
|
puts 'Available recipes:'
|
271
204
|
|
@@ -276,43 +209,43 @@ task :recipe_input, :recipe do |task,args|
|
|
276
209
|
$recipe_to_apply = Chake::Readline::Recipes.readline
|
277
210
|
if !$recipe_to_apply || $recipe_to_apply.empty?
|
278
211
|
puts
|
279
|
-
puts
|
212
|
+
puts 'I: no recipe provided, operation aborted.'
|
280
213
|
exit(1)
|
281
214
|
end
|
282
|
-
|
215
|
+
unless recipes.include?($recipe_to_apply)
|
283
216
|
abort "E: no such recipe: #{$recipe_to_apply}"
|
284
217
|
end
|
285
218
|
end
|
286
219
|
end
|
287
220
|
|
288
|
-
desc
|
289
|
-
multitask :
|
221
|
+
desc 'upload to all nodes'
|
222
|
+
multitask upload: Chake.nodes.map { |node| "upload:#{node.hostname}" }
|
290
223
|
|
291
|
-
desc
|
292
|
-
multitask :
|
224
|
+
desc 'bootstrap all nodes'
|
225
|
+
multitask bootstrap: Chake.nodes.map { |node| "bootstrap:#{node.hostname}" }
|
293
226
|
|
294
|
-
desc
|
295
|
-
multitask
|
227
|
+
desc 'converge all nodes (default)'
|
228
|
+
multitask 'converge' => Chake.nodes.map { |node| "converge:#{node.hostname}" }
|
296
229
|
|
297
|
-
desc
|
298
|
-
multitask
|
230
|
+
desc 'Apply <recipe> on all nodes'
|
231
|
+
multitask 'apply', [:recipe] => Chake.nodes.map { |node| "apply:#{node.hostname}" }
|
299
232
|
|
300
|
-
desc
|
233
|
+
desc 'run <command> on all nodes'
|
301
234
|
multitask :run, [:command] => Chake.nodes.map { |node| "run:#{node.hostname}" }
|
302
235
|
|
303
|
-
task :
|
236
|
+
task default: :converge
|
304
237
|
|
305
238
|
desc 'checks connectivity and setup on all nodes'
|
306
|
-
multitask :
|
307
|
-
puts
|
308
|
-
puts
|
309
|
-
puts
|
239
|
+
multitask check: (Chake.nodes.map { |node| "check:#{node.hostname}" }) do
|
240
|
+
puts '✓ all hosts OK'
|
241
|
+
puts ' - ssh connection works'
|
242
|
+
puts ' - password-less sudo works'
|
310
243
|
end
|
311
244
|
|
312
245
|
desc 'runs a Ruby console in the chake environment'
|
313
246
|
task :console do
|
314
247
|
require 'irb'
|
315
|
-
IRB.setup(
|
248
|
+
IRB.setup('__FILE__', argv: [])
|
316
249
|
workspace = IRB::WorkSpace.new(self)
|
317
250
|
|
318
251
|
puts 'chake - interactive console'
|