chake 0.20 → 0.81

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.ackrc +2 -0
  3. data/.gitignore +22 -0
  4. data/.gitlab-ci.yml +24 -0
  5. data/.manifest +65 -0
  6. data/.rubocop.yml +55 -0
  7. data/.rubocop_todo.yml +40 -0
  8. data/ChangeLog.md +36 -0
  9. data/README.chef.md +70 -0
  10. data/README.itamae.md +58 -0
  11. data/README.md +118 -85
  12. data/README.shell.md +30 -0
  13. data/Rakefile +36 -10
  14. data/bin/chake +2 -2
  15. data/chake.gemspec +16 -16
  16. data/examples/test/.ssh_config +4 -0
  17. data/examples/test/Rakefile +1 -1
  18. data/examples/test/Vagrantfile +6 -0
  19. data/examples/test/config.rb +4 -4
  20. data/examples/test/cookbooks/basics/recipes/default.rb +1 -0
  21. data/examples/test/cookbooks/example/files/default/test +1 -0
  22. data/examples/test/cookbooks/example/files/{host-homer → host-lemur}/test.asc +0 -0
  23. data/lib/chake.rb +110 -154
  24. data/lib/chake/bootstrap/chef/01_installed.sh +4 -0
  25. data/lib/chake/bootstrap/{01_debian.sh → chef/02_debian.sh} +0 -0
  26. data/lib/chake/bootstrap/{99_unsupported.sh → chef/99_unsupported.sh} +0 -0
  27. data/lib/chake/config.rb +2 -7
  28. data/lib/chake/config_manager.rb +89 -0
  29. data/lib/chake/config_manager/chef.rb +35 -0
  30. data/lib/chake/config_manager/itamae.rb +57 -0
  31. data/lib/chake/config_manager/shell.rb +34 -0
  32. data/lib/chake/config_manager/skel/chef/Rakefile +1 -0
  33. data/lib/chake/config_manager/skel/chef/config.rb +4 -0
  34. data/lib/chake/config_manager/skel/chef/cookbooks/basics/recipes/default.rb +1 -0
  35. data/lib/chake/config_manager/skel/chef/nodes.yaml +3 -0
  36. data/lib/chake/config_manager/skel/itamae/Rakefile +1 -0
  37. data/lib/chake/config_manager/skel/itamae/cookbooks/basics/default.rb +1 -0
  38. data/lib/chake/config_manager/skel/itamae/nodes.yaml +3 -0
  39. data/lib/chake/config_manager/skel/itamae/roles/basic.rb +1 -0
  40. data/lib/chake/config_manager/skel/shell/Rakefile +1 -0
  41. data/lib/chake/config_manager/skel/shell/nodes.yaml +3 -0
  42. data/lib/chake/connection.rb +83 -0
  43. data/lib/chake/{backend → connection}/local.rb +2 -8
  44. data/lib/chake/{backend → connection}/ssh.rb +6 -14
  45. data/lib/chake/node.rb +49 -29
  46. data/lib/chake/readline.rb +6 -10
  47. data/lib/chake/version.rb +1 -1
  48. data/lib/chake/wipe.rb +18 -0
  49. data/man/.gitignore +2 -0
  50. data/man/Rakefile +28 -14
  51. data/man/readme2man.sed +5 -5
  52. data/spec/chake/backend/local_spec.rb +5 -6
  53. data/spec/chake/backend/ssh_spec.rb +8 -10
  54. data/spec/chake/backend_spec.rb +1 -2
  55. data/spec/chake/config_manager/chef_spec.rb +38 -0
  56. data/spec/chake/config_manager/itamae_spec.rb +87 -0
  57. data/spec/chake/config_manager/shell_spec.rb +54 -0
  58. data/spec/chake/config_manager_spec.rb +23 -0
  59. data/spec/chake/node_spec.rb +38 -15
  60. data/spec/spec_helper.rb +37 -17
  61. metadata +65 -39
  62. data/coverage/assets/0.10.0/application.css +0 -799
  63. data/coverage/assets/0.10.0/application.js +0 -34783
  64. data/coverage/assets/0.10.0/colorbox/border.png +0 -0
  65. data/coverage/assets/0.10.0/colorbox/controls.png +0 -0
  66. data/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
  67. data/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
  68. data/coverage/assets/0.10.0/favicon_green.png +0 -0
  69. data/coverage/assets/0.10.0/favicon_red.png +0 -0
  70. data/coverage/assets/0.10.0/favicon_yellow.png +0 -0
  71. data/coverage/assets/0.10.0/loading.gif +0 -0
  72. data/coverage/assets/0.10.0/magnify.png +0 -0
  73. data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  74. data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  75. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  76. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  77. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  78. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  79. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  80. data/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  81. data/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  82. data/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  83. data/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  84. data/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  85. data/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  86. data/coverage/index.html +0 -2326
  87. data/lib/chake/backend.rb +0 -80
@@ -0,0 +1,4 @@
1
+ # chef-solo already installed
2
+ if which chef-solo >/dev/null 2>&1; then
3
+ exit
4
+ fi
@@ -2,20 +2,15 @@ require 'chake/node'
2
2
 
3
3
  module Chake
4
4
  class << self
5
- attr_accessor :chef_config
6
5
  attr_accessor :nodes
7
- attr_accessor :tmpdir
8
6
  end
9
7
  end
10
8
 
11
- chef_config = ENV['CHAKE_CHEF_CONFIG'] || 'config.rb'
12
9
  nodes_file = ENV['CHAKE_NODES'] || 'nodes.yaml'
13
10
  nodes_directory = ENV['CHAKE_NODES_D'] || 'nodes.d'
14
- node_data = File.exists?(nodes_file) && YAML.load_file(nodes_file) || {}
11
+ node_data = File.exist?(nodes_file) && YAML.load_file(nodes_file) || {}
15
12
  Dir.glob(File.join(nodes_directory, '*.yaml')).sort.each do |f|
16
13
  node_data.merge!(YAML.load_file(f))
17
14
  end
18
15
 
19
- Chake.chef_config = chef_config
20
- Chake.nodes = node_data.map { |node,data| Chake::Node.new(node, data) }.reject(&:skip?).uniq(&:hostname)
21
- Chake.tmpdir = Chake.tmpdir
16
+ Chake.nodes = node_data.map { |node, data| Chake::Node.new(node, data) }.reject(&:skip?).uniq(&:hostname)
@@ -0,0 +1,89 @@
1
+ require 'pathname'
2
+
3
+ module Chake
4
+ class ConfigManager
5
+ attr_reader :node
6
+
7
+ def initialize(node)
8
+ @node = node
9
+ end
10
+
11
+ def converge; end
12
+
13
+ def apply(config); end
14
+
15
+ def path
16
+ "/var/tmp/#{name}.#{node.username}"
17
+ end
18
+
19
+ def name
20
+ self.class.short_name
21
+ end
22
+
23
+ def to_s
24
+ name
25
+ end
26
+
27
+ def bootstrap_steps
28
+ base = File.join(File.absolute_path(File.dirname(__FILE__)), 'bootstrap')
29
+ steps = Dir[File.join(base, '*.sh')] + Dir[File.join(base, name, '*.sh')]
30
+ steps.sort_by { |f| File.basename(f) }
31
+ end
32
+
33
+ def needs_upload?
34
+ true
35
+ end
36
+
37
+ def self.short_name
38
+ name.split('::').last.downcase
39
+ end
40
+
41
+ def self.priority(new_prioriry = nil)
42
+ @priority ||= new_prioriry || 50
43
+ end
44
+
45
+ def self.inherited(klass)
46
+ super
47
+ @subclasses ||= []
48
+ @subclasses << klass
49
+ end
50
+
51
+ def self.get(node)
52
+ available = @subclasses.sort_by(&:priority)
53
+ manager = available.find { |c| c.short_name == node.data['config_manager'] }
54
+ manager ||= available.find { |c| c.accept?(node) }
55
+ raise ArgumentError, "Can't find configuration manager class for node #{node.hostname}. Available: #{available}.join(', ')}" unless manager
56
+
57
+ manager.new(node)
58
+ end
59
+
60
+ def self.accept?(_node)
61
+ false
62
+ end
63
+
64
+ def self.all
65
+ @subclasses
66
+ end
67
+
68
+ def self.init
69
+ skel = Pathname(__FILE__).parent / 'config_manager' / 'skel' / short_name
70
+ skel.glob('**/*').each do |source|
71
+ target = source.relative_path_from(skel)
72
+ if target.exist?
73
+ puts "exists: #{target}"
74
+ else
75
+ if source.directory?
76
+ FileUtils.mkdir_p target
77
+ else
78
+ FileUtils.cp source, target
79
+ end
80
+ puts "create: #{target}"
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ Dir["#{File.dirname(__FILE__)}/config_manager/*.rb"].sort.each do |f|
88
+ require f
89
+ end
@@ -0,0 +1,35 @@
1
+ require 'chake/config'
2
+ require 'chake/tmpdir'
3
+
4
+ module Chake
5
+ class ConfigManager
6
+ class Chef < ConfigManager
7
+ CONFIG = ENV['CHAKE_CHEF_CONFIG'] || 'config.rb'
8
+
9
+ def converge
10
+ node.run_as_root "sh -c 'rm -f #{node.path}/nodes/*.json && chef-solo -c #{node.path}/#{CONFIG} #{logging} -j #{json_config}'"
11
+ end
12
+
13
+ def apply(config)
14
+ node.run_as_root "sh -c 'rm -f #{node.path}/nodes/*.json && chef-solo -c #{node.path}/#{CONFIG} #{logging} -j #{json_config} --override-runlist recipe[#{config}]'"
15
+ end
16
+
17
+ priority 99
18
+
19
+ def self.accept?(_node)
20
+ true # this is the default, but after everything else
21
+ end
22
+
23
+ private
24
+
25
+ def json_config
26
+ parts = [node.path, Chake.tmpdir, "#{node.hostname}.json"].compact
27
+ File.join(parts)
28
+ end
29
+
30
+ def logging
31
+ node.silent && '-l fatal' || ''
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,57 @@
1
+ require 'shellwords'
2
+ require 'chake/config'
3
+ require 'chake/tmpdir'
4
+
5
+ module Chake
6
+ class ConfigManager
7
+ class Itamae < ConfigManager
8
+ def converge
9
+ run_itamae(*node.data['itamae'])
10
+ end
11
+
12
+ def apply(config)
13
+ run_itamae(config)
14
+ end
15
+
16
+ def needs_upload?
17
+ false
18
+ end
19
+
20
+ def self.accept?(node)
21
+ node.data.key?('itamae')
22
+ end
23
+
24
+ private
25
+
26
+ def run_itamae(*recipes)
27
+ cmd = ['itamae']
28
+ case node.connection
29
+ when Chake::Connection::Ssh
30
+ cmd << 'ssh' << "--user=#{node.username}" << "--host=#{node.hostname}"
31
+ cmd += ssh_config
32
+ when Chake::Connection::Local
33
+ cmd << 'local'
34
+ else
35
+ raise NotImplementedError, "Connection type #{node.connection.class} not supported for itamee"
36
+ end
37
+ cmd << "--node-json=#{json_config}"
38
+ if node.silent
39
+ cmd << '--log-level=warn'
40
+ end
41
+ cmd += recipes
42
+ node.log("$ #{cmd.join(' ')}")
43
+ io = IO.popen(cmd, 'r', err: %i[child out])
44
+ node.connection.read_output(io)
45
+ end
46
+
47
+ def json_config
48
+ File.join(Chake.tmpdir, "#{node.hostname}.json")
49
+ end
50
+
51
+ def ssh_config
52
+ ssh_config = node.connection.send(:ssh_config_file) # FIXME
53
+ File.exist?(ssh_config) ? ["--ssh-config=#{ssh_config}"] : []
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,34 @@
1
+ require 'shellwords'
2
+ require 'chake/config'
3
+
4
+ module Chake
5
+ class ConfigManager
6
+ class Shell < ConfigManager
7
+ def converge
8
+ commands = node.data['shell'].join(' && ')
9
+ node.run_as_root sh(commands)
10
+ end
11
+
12
+ def apply(config)
13
+ node.run_as_root sh(config)
14
+ end
15
+
16
+ def self.accept?(node)
17
+ node.data.key?('shell')
18
+ end
19
+
20
+ private
21
+
22
+ def sh(command)
23
+ if node.path
24
+ command = "cd #{node.path} && " + command
25
+ end
26
+ if node.silent
27
+ "sh -ec '#{command}' >/dev/null"
28
+ else
29
+ "sh -xec '#{command}'"
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1 @@
1
+ require 'chake'
@@ -0,0 +1,4 @@
1
+ root = __dir__
2
+ file_cache_path "#{root}/cache"
3
+ cookbook_path "#{root}/cookbooks"
4
+ role_path "#{root}/config/roles"
@@ -0,0 +1,3 @@
1
+ host1.mycompany.com:
2
+ run_list:
3
+ - recipe[basics]
@@ -0,0 +1 @@
1
+ require 'chake'
@@ -0,0 +1 @@
1
+ package 'openssh-server'
@@ -0,0 +1,3 @@
1
+ host1.mycompany.com:
2
+ itamae:
3
+ - roles/basic.rb
@@ -0,0 +1 @@
1
+ include_recipe '../cookbooks/basics'
@@ -0,0 +1 @@
1
+ require 'chake'
@@ -0,0 +1,3 @@
1
+ host1.mycompany.com:
2
+ shell:
3
+ - echo "HELLO WORLD"
@@ -0,0 +1,83 @@
1
+ module Chake
2
+ Connection = Struct.new(:node) do
3
+ class CommandFailed < RuntimeError
4
+ end
5
+
6
+ def scp
7
+ ['scp']
8
+ end
9
+
10
+ def scp_dest
11
+ ''
12
+ end
13
+
14
+ def rsync
15
+ ['rsync']
16
+ end
17
+
18
+ def rsync_dest
19
+ "#{node.path}/"
20
+ end
21
+
22
+ def run(cmd)
23
+ node.log('$ %<command>s' % { command: cmd })
24
+ io = IO.popen(command_runner + ['/bin/sh'], 'w+', err: %i[child out])
25
+ io.write(cmd)
26
+ io.close_write
27
+ read_output(io)
28
+ end
29
+
30
+ def read_output(io)
31
+ io.each_line do |line|
32
+ node.log(line.gsub(/\s*$/, ''))
33
+ end
34
+ io.close
35
+ if $CHILD_STATUS
36
+ status = $CHILD_STATUS.exitstatus
37
+ if status != 0
38
+ raise CommandFailed, [node.hostname, 'FAILED with exit status %<status>d' % { status: status }].join(': ')
39
+ end
40
+ end
41
+ end
42
+
43
+ def run_shell
44
+ system(*shell_command)
45
+ end
46
+
47
+ def run_as_root(cmd)
48
+ if node.remote_username == 'root'
49
+ run(cmd)
50
+ else
51
+ run("sudo #{cmd}")
52
+ end
53
+ end
54
+
55
+ def to_s
56
+ self.class.connection_name
57
+ end
58
+
59
+ def skip?
60
+ false
61
+ end
62
+
63
+ def self.connection_name
64
+ name.split('::').last.downcase
65
+ end
66
+
67
+ def self.inherited(subclass)
68
+ super
69
+ @connections ||= []
70
+ @connections << subclass
71
+ end
72
+
73
+ def self.get(name)
74
+ connection = @connections.find { |b| b.connection_name == name }
75
+ raise ArgumentError, "Invalid connection name: #{name}" unless connection
76
+
77
+ connection
78
+ end
79
+ end
80
+ end
81
+
82
+ require 'chake/connection/ssh'
83
+ require 'chake/connection/local'
@@ -1,11 +1,8 @@
1
1
  require 'socket'
2
2
 
3
3
  module Chake
4
-
5
- class Backend
6
-
7
- class Local < Backend
8
-
4
+ class Connection
5
+ class Local < Connection
9
6
  def command_runner
10
7
  ['sh', '-c']
11
8
  end
@@ -17,9 +14,6 @@ module Chake
17
14
  def skip?
18
15
  node.hostname != Socket.gethostname
19
16
  end
20
-
21
17
  end
22
-
23
18
  end
24
-
25
19
  end
@@ -1,15 +1,12 @@
1
1
  module Chake
2
-
3
- class Backend
4
-
5
- class Ssh < Backend
6
-
2
+ class Connection
3
+ class Ssh < Connection
7
4
  def scp
8
5
  ['scp', ssh_config, scp_options].flatten.compact
9
6
  end
10
7
 
11
8
  def scp_dest
12
- ssh_target + ':'
9
+ "#{ssh_target}:"
13
10
  end
14
11
 
15
12
  def rsync
@@ -17,7 +14,7 @@ module Chake
17
14
  end
18
15
 
19
16
  def rsync_dest
20
- [ssh_target, node.path + '/'].join(':')
17
+ [ssh_target, "#{node.path}/"].join(':')
21
18
  end
22
19
 
23
20
  def command_runner
@@ -35,11 +32,9 @@ module Chake
35
32
  begin
36
33
  ssh_command = 'ssh'
37
34
  if File.exist?(ssh_config_file)
38
- ssh_command += ' -F ' + ssh_config_file
39
- end
40
- if node.port
41
- ssh_command += ' -p ' + node.port.to_s
35
+ ssh_command += " -F #{ssh_config_file}"
42
36
  end
37
+ ssh_command += " -p #{node.port}" if node.port
43
38
  if ssh_command == 'ssh'
44
39
  []
45
40
  else
@@ -71,9 +66,6 @@ module Chake
71
66
  def scp_options
72
67
  node.port && ['-P', node.port.to_s] || []
73
68
  end
74
-
75
69
  end
76
-
77
70
  end
78
-
79
71
  end