chake 0.21 → 0.81.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) 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 +37 -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 +111 -153
  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.11.0/application.css +0 -809
  63. data/coverage/assets/0.11.0/application.js +0 -43679
  64. data/coverage/assets/0.11.0/colorbox/border.png +0 -0
  65. data/coverage/assets/0.11.0/colorbox/controls.png +0 -0
  66. data/coverage/assets/0.11.0/colorbox/loading.gif +0 -0
  67. data/coverage/assets/0.11.0/colorbox/loading_background.png +0 -0
  68. data/coverage/assets/0.11.0/favicon_green.png +0 -0
  69. data/coverage/assets/0.11.0/favicon_red.png +0 -0
  70. data/coverage/assets/0.11.0/favicon_yellow.png +0 -0
  71. data/coverage/assets/0.11.0/loading.gif +0 -0
  72. data/coverage/assets/0.11.0/magnify.png +0 -0
  73. data/coverage/assets/0.11.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  74. data/coverage/assets/0.11.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  75. data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  76. data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  77. data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  78. data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  79. data/coverage/assets/0.11.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  80. data/coverage/assets/0.11.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  81. data/coverage/assets/0.11.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  82. data/coverage/assets/0.11.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  83. data/coverage/assets/0.11.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  84. data/coverage/assets/0.11.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  85. data/coverage/assets/0.11.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  86. data/coverage/index.html +0 -4158
  87. data/lib/chake/backend.rb +0 -80
  88. data/tags +0 -72
@@ -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