chef-provisioning 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +906 -899
  3. data/Gemfile +17 -17
  4. data/LICENSE +201 -201
  5. data/README.md +312 -312
  6. data/Rakefile +55 -55
  7. data/chef-provisioning.gemspec +38 -38
  8. data/lib/chef/provider/load_balancer.rb +75 -75
  9. data/lib/chef/provider/machine.rb +219 -219
  10. data/lib/chef/provider/machine_batch.rb +224 -224
  11. data/lib/chef/provider/machine_execute.rb +36 -36
  12. data/lib/chef/provider/machine_file.rb +55 -55
  13. data/lib/chef/provider/machine_image.rb +105 -105
  14. data/lib/chef/provisioning.rb +110 -110
  15. data/lib/chef/provisioning/action_handler.rb +68 -68
  16. data/lib/chef/provisioning/add_prefix_action_handler.rb +35 -35
  17. data/lib/chef/provisioning/chef_managed_entry_store.rb +128 -128
  18. data/lib/chef/provisioning/chef_provider_action_handler.rb +74 -74
  19. data/lib/chef/provisioning/chef_run_data.rb +132 -132
  20. data/lib/chef/provisioning/convergence_strategy.rb +28 -28
  21. data/lib/chef/provisioning/convergence_strategy/ignore_convergence_failure.rb +54 -54
  22. data/lib/chef/provisioning/convergence_strategy/install_cached.rb +188 -188
  23. data/lib/chef/provisioning/convergence_strategy/install_msi.rb +71 -71
  24. data/lib/chef/provisioning/convergence_strategy/install_sh.rb +71 -71
  25. data/lib/chef/provisioning/convergence_strategy/no_converge.rb +35 -35
  26. data/lib/chef/provisioning/convergence_strategy/precreate_chef_objects.rb +255 -255
  27. data/lib/chef/provisioning/driver.rb +323 -323
  28. data/lib/chef/provisioning/load_balancer_spec.rb +14 -14
  29. data/lib/chef/provisioning/machine.rb +112 -112
  30. data/lib/chef/provisioning/machine/basic_machine.rb +84 -84
  31. data/lib/chef/provisioning/machine/unix_machine.rb +288 -288
  32. data/lib/chef/provisioning/machine/windows_machine.rb +108 -108
  33. data/lib/chef/provisioning/machine_image_spec.rb +34 -34
  34. data/lib/chef/provisioning/machine_spec.rb +58 -58
  35. data/lib/chef/provisioning/managed_entry.rb +121 -121
  36. data/lib/chef/provisioning/managed_entry_store.rb +136 -136
  37. data/lib/chef/provisioning/recipe_dsl.rb +99 -99
  38. data/lib/chef/provisioning/rspec.rb +27 -27
  39. data/lib/chef/provisioning/transport.rb +100 -100
  40. data/lib/chef/provisioning/transport/ssh.rb +403 -403
  41. data/lib/chef/provisioning/transport/winrm.rb +144 -144
  42. data/lib/chef/provisioning/version.rb +5 -5
  43. data/lib/chef/resource/chef_data_bag_resource.rb +146 -146
  44. data/lib/chef/resource/load_balancer.rb +57 -57
  45. data/lib/chef/resource/machine.rb +128 -128
  46. data/lib/chef/resource/machine_batch.rb +78 -78
  47. data/lib/chef/resource/machine_execute.rb +30 -30
  48. data/lib/chef/resource/machine_file.rb +34 -34
  49. data/lib/chef/resource/machine_image.rb +35 -35
  50. data/lib/chef_metal.rb +1 -1
  51. data/spec/chef/provisioning/convergence_strategy/ignore_convergence_failure_spec.rb +86 -86
  52. data/spec/spec_helper.rb +27 -27
  53. metadata +10 -4
@@ -1,71 +1,71 @@
1
- require 'chef/provisioning/convergence_strategy/precreate_chef_objects'
2
- require 'mixlib/install/script_generator'
3
- require 'pathname'
4
-
5
- class Chef
6
- module Provisioning
7
- class ConvergenceStrategy
8
- class InstallMsi < PrecreateChefObjects
9
- def initialize(convergence_options, config)
10
- super
11
- @chef_version ||= convergence_options[:chef_version]
12
- @prerelease ||= convergence_options[:prerelease]
13
- @chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
14
- end
15
-
16
- attr_reader :chef_version
17
- attr_reader :prerelease
18
- attr_reader :install_msi_url
19
- attr_reader :install_msi_path
20
-
21
- def setup_convergence(action_handler, machine)
22
- if !convergence_options.has_key?(:client_rb_path) || !convergence_options.has_key?(:client_pem_path)
23
- system_drive = machine.system_drive
24
- @convergence_options = Cheffish::MergedConfig.new(convergence_options, {
25
- :client_rb_path => "#{system_drive}\\chef\\client.rb",
26
- :client_pem_path => "#{system_drive}\\chef\\client.pem",
27
- :install_script_path => "#{system_drive}\\chef\\\install.ps1"
28
- })
29
- end
30
-
31
- opts = {"prerelease" => prerelease}
32
- if convergence_options[:bootstrap_proxy]
33
- opts["http_proxy"] = convergence_options[:bootstrap_proxy]
34
- opts["https_proxy"] = convergence_options[:bootstrap_proxy]
35
- end
36
- opts["install_msi_url"] = convergence_options[:install_msi_url] if convergence_options[:install_msi_url]
37
- super
38
-
39
- install_command = Mixlib::Install::ScriptGenerator.new(chef_version, true, opts).install_command
40
- machine.write_file(action_handler, convergence_options[:install_script_path], install_command)
41
-
42
- action_handler.open_stream(machine.node['name']) do |stdout|
43
- action_handler.open_stream(machine.node['name']) do |stderr|
44
- machine.execute(action_handler, "& \"#{convergence_options[:install_script_path]}\"",
45
- :stream_stdout => stdout,
46
- :stream_stderr => stderr)
47
- end
48
- end
49
- end
50
-
51
- def converge(action_handler, machine)
52
- super
53
-
54
- action_handler.open_stream(machine.node['name']) do |stdout|
55
- action_handler.open_stream(machine.node['name']) do |stderr|
56
- # We just installed chef in this shell so refresh PATH from System.Environment
57
- command_line = "$env:path = [System.Environment]::GetEnvironmentVariable('PATH', 'MACHINE');"
58
- command_line << "chef-client"
59
- command_line << " -l #{config[:log_level].to_s}" if config[:log_level]
60
- machine.execute(action_handler, command_line,
61
- :stream_stdout => stdout,
62
- :stream_stderr => stderr,
63
- :timeout => @chef_client_timeout)
64
- end
65
- end
66
- end
67
-
68
- end
69
- end
70
- end
71
- end
1
+ require 'chef/provisioning/convergence_strategy/precreate_chef_objects'
2
+ require 'mixlib/install/script_generator'
3
+ require 'pathname'
4
+
5
+ class Chef
6
+ module Provisioning
7
+ class ConvergenceStrategy
8
+ class InstallMsi < PrecreateChefObjects
9
+ def initialize(convergence_options, config)
10
+ super
11
+ @chef_version ||= convergence_options[:chef_version]
12
+ @prerelease ||= convergence_options[:prerelease]
13
+ @chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
14
+ end
15
+
16
+ attr_reader :chef_version
17
+ attr_reader :prerelease
18
+ attr_reader :install_msi_url
19
+ attr_reader :install_msi_path
20
+
21
+ def setup_convergence(action_handler, machine)
22
+ if !convergence_options.has_key?(:client_rb_path) || !convergence_options.has_key?(:client_pem_path)
23
+ system_drive = machine.system_drive
24
+ @convergence_options = Cheffish::MergedConfig.new(convergence_options, {
25
+ :client_rb_path => "#{system_drive}\\chef\\client.rb",
26
+ :client_pem_path => "#{system_drive}\\chef\\client.pem",
27
+ :install_script_path => "#{system_drive}\\chef\\\install.ps1"
28
+ })
29
+ end
30
+
31
+ opts = {"prerelease" => prerelease}
32
+ if convergence_options[:bootstrap_proxy]
33
+ opts["http_proxy"] = convergence_options[:bootstrap_proxy]
34
+ opts["https_proxy"] = convergence_options[:bootstrap_proxy]
35
+ end
36
+ opts["install_msi_url"] = convergence_options[:install_msi_url] if convergence_options[:install_msi_url]
37
+ super
38
+
39
+ install_command = Mixlib::Install::ScriptGenerator.new(chef_version, true, opts).install_command
40
+ machine.write_file(action_handler, convergence_options[:install_script_path], install_command)
41
+
42
+ action_handler.open_stream(machine.node['name']) do |stdout|
43
+ action_handler.open_stream(machine.node['name']) do |stderr|
44
+ machine.execute(action_handler, "& \"#{convergence_options[:install_script_path]}\"",
45
+ :stream_stdout => stdout,
46
+ :stream_stderr => stderr)
47
+ end
48
+ end
49
+ end
50
+
51
+ def converge(action_handler, machine)
52
+ super
53
+
54
+ action_handler.open_stream(machine.node['name']) do |stdout|
55
+ action_handler.open_stream(machine.node['name']) do |stderr|
56
+ # We just installed chef in this shell so refresh PATH from System.Environment
57
+ command_line = "$env:path = [System.Environment]::GetEnvironmentVariable('PATH', 'MACHINE');"
58
+ command_line << "chef-client"
59
+ command_line << " -l #{config[:log_level].to_s}" if config[:log_level]
60
+ machine.execute(action_handler, command_line,
61
+ :stream_stdout => stdout,
62
+ :stream_stderr => stderr,
63
+ :timeout => @chef_client_timeout)
64
+ end
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,71 +1,71 @@
1
- require 'chef/provisioning/convergence_strategy/precreate_chef_objects'
2
- require 'pathname'
3
- require 'mixlib/install/script_generator'
4
-
5
- class Chef
6
- module Provisioning
7
- class ConvergenceStrategy
8
- class InstallSh < PrecreateChefObjects
9
- @@install_sh_cache = {}
10
-
11
- def initialize(convergence_options, config)
12
- convergence_options = Cheffish::MergedConfig.new(convergence_options, {
13
- :client_rb_path => '/etc/chef/client.rb',
14
- :client_pem_path => '/etc/chef/client.pem'
15
- })
16
- super(convergence_options, config)
17
- @client_rb_path ||= convergence_options[:client_rb_path]
18
- @install_sh_path = convergence_options[:install_sh_path] || '/tmp/chef-install.sh'
19
- @chef_version = convergence_options[:chef_version]
20
- @prerelease = convergence_options[:prerelease]
21
- @install_sh_arguments = convergence_options[:install_sh_arguments]
22
- @bootstrap_env = convergence_options[:bootstrap_proxy] ? "http_proxy=#{convergence_options[:bootstrap_proxy]} https_proxy=$http_proxy " : ""
23
- @chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
24
- end
25
-
26
- attr_reader :client_rb_path
27
- attr_reader :chef_version
28
- attr_reader :prerelease
29
- attr_reader :install_sh_path
30
- attr_reader :install_sh_arguments
31
- attr_reader :bootstrap_env
32
-
33
- def setup_convergence(action_handler, machine)
34
- super
35
-
36
- opts = {"prerelease" => prerelease}
37
- if convergence_options[:bootstrap_proxy]
38
- opts["http_proxy"] = convergence_options[:bootstrap_proxy]
39
- opts["https_proxy"] = convergence_options[:bootstrap_proxy]
40
- end
41
-
42
- opts["omnibus_url"] = convergence_options[:install_sh_url] if convergence_options[:install_sh_url]
43
-
44
- if convergence_options[:install_sh_arguments]
45
- opts['install_flags'] = convergence_options[:install_sh_arguments]
46
- end
47
-
48
- install_command = Mixlib::Install::ScriptGenerator.new(chef_version, false, opts).install_command
49
- machine.write_file(action_handler, install_sh_path, install_command, :ensure_dir => true)
50
- machine.set_attributes(action_handler, install_sh_path, :mode => '0755')
51
- machine.execute(action_handler, "sh -c #{install_sh_path}")
52
- end
53
-
54
- def converge(action_handler, machine)
55
- super
56
-
57
- action_handler.open_stream(machine.node['name']) do |stdout|
58
- action_handler.open_stream(machine.node['name']) do |stderr|
59
- command_line = "chef-client"
60
- command_line << " -c #{@client_rb_path} -l #{config[:log_level].to_s}" if config[:log_level]
61
- machine.execute(action_handler, command_line,
62
- :stream_stdout => stdout,
63
- :stream_stderr => stderr,
64
- :timeout => @chef_client_timeout)
65
- end
66
- end
67
- end
68
- end
69
- end
70
- end
71
- end
1
+ require 'chef/provisioning/convergence_strategy/precreate_chef_objects'
2
+ require 'pathname'
3
+ require 'mixlib/install/script_generator'
4
+
5
+ class Chef
6
+ module Provisioning
7
+ class ConvergenceStrategy
8
+ class InstallSh < PrecreateChefObjects
9
+ @@install_sh_cache = {}
10
+
11
+ def initialize(convergence_options, config)
12
+ convergence_options = Cheffish::MergedConfig.new(convergence_options, {
13
+ :client_rb_path => '/etc/chef/client.rb',
14
+ :client_pem_path => '/etc/chef/client.pem'
15
+ })
16
+ super(convergence_options, config)
17
+ @client_rb_path ||= convergence_options[:client_rb_path]
18
+ @install_sh_path = convergence_options[:install_sh_path] || '/tmp/chef-install.sh'
19
+ @chef_version = convergence_options[:chef_version]
20
+ @prerelease = convergence_options[:prerelease]
21
+ @install_sh_arguments = convergence_options[:install_sh_arguments]
22
+ @bootstrap_env = convergence_options[:bootstrap_proxy] ? "http_proxy=#{convergence_options[:bootstrap_proxy]} https_proxy=$http_proxy " : ""
23
+ @chef_client_timeout = convergence_options.has_key?(:chef_client_timeout) ? convergence_options[:chef_client_timeout] : 120*60 # Default: 2 hours
24
+ end
25
+
26
+ attr_reader :client_rb_path
27
+ attr_reader :chef_version
28
+ attr_reader :prerelease
29
+ attr_reader :install_sh_path
30
+ attr_reader :install_sh_arguments
31
+ attr_reader :bootstrap_env
32
+
33
+ def setup_convergence(action_handler, machine)
34
+ super
35
+
36
+ opts = {"prerelease" => prerelease}
37
+ if convergence_options[:bootstrap_proxy]
38
+ opts["http_proxy"] = convergence_options[:bootstrap_proxy]
39
+ opts["https_proxy"] = convergence_options[:bootstrap_proxy]
40
+ end
41
+
42
+ opts["omnibus_url"] = convergence_options[:install_sh_url] if convergence_options[:install_sh_url]
43
+
44
+ if convergence_options[:install_sh_arguments]
45
+ opts['install_flags'] = convergence_options[:install_sh_arguments]
46
+ end
47
+
48
+ install_command = Mixlib::Install::ScriptGenerator.new(chef_version, false, opts).install_command
49
+ machine.write_file(action_handler, install_sh_path, install_command, :ensure_dir => true)
50
+ machine.set_attributes(action_handler, install_sh_path, :mode => '0755')
51
+ machine.execute(action_handler, "sh -c #{install_sh_path}")
52
+ end
53
+
54
+ def converge(action_handler, machine)
55
+ super
56
+
57
+ action_handler.open_stream(machine.node['name']) do |stdout|
58
+ action_handler.open_stream(machine.node['name']) do |stderr|
59
+ command_line = "chef-client"
60
+ command_line << " -c #{@client_rb_path} -l #{config[:log_level].to_s}" if config[:log_level]
61
+ machine.execute(action_handler, command_line,
62
+ :stream_stdout => stdout,
63
+ :stream_stderr => stderr,
64
+ :timeout => @chef_client_timeout)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,35 +1,35 @@
1
- require 'chef/provisioning/convergence_strategy'
2
- require 'pathname'
3
- require 'cheffish'
4
-
5
- class Chef
6
- module Provisioning
7
- class ConvergenceStrategy
8
- class NoConverge < ConvergenceStrategy
9
- def chef_server
10
- @chef_server ||= convergence_options[:chef_server] || Cheffish.default_chef_server(config)
11
- end
12
-
13
- def setup_convergence(action_handler, machine)
14
- end
15
-
16
- def converge(action_handler, machine)
17
- end
18
-
19
- def cleanup_convergence(action_handler, machine_spec)
20
- _self = self
21
- Chef::Provisioning.inline_resource(action_handler) do
22
- chef_node machine_spec.name do
23
- chef_server _self.chef_server
24
- action :delete
25
- end
26
- chef_client machine_spec.name do
27
- chef_server _self.chef_server
28
- action :delete
29
- end
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
1
+ require 'chef/provisioning/convergence_strategy'
2
+ require 'pathname'
3
+ require 'cheffish'
4
+
5
+ class Chef
6
+ module Provisioning
7
+ class ConvergenceStrategy
8
+ class NoConverge < ConvergenceStrategy
9
+ def chef_server
10
+ @chef_server ||= convergence_options[:chef_server] || Cheffish.default_chef_server(config)
11
+ end
12
+
13
+ def setup_convergence(action_handler, machine)
14
+ end
15
+
16
+ def converge(action_handler, machine)
17
+ end
18
+
19
+ def cleanup_convergence(action_handler, machine_spec)
20
+ _self = self
21
+ Chef::Provisioning.inline_resource(action_handler) do
22
+ chef_node machine_spec.name do
23
+ chef_server _self.chef_server
24
+ action :delete
25
+ end
26
+ chef_client machine_spec.name do
27
+ chef_server _self.chef_server
28
+ action :delete
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,255 +1,255 @@
1
- require 'chef/provisioning/convergence_strategy'
2
- require 'pathname'
3
- require 'cheffish'
4
- require 'chef_zero/socketless_server_map'
5
- require_relative 'ignore_convergence_failure'
6
-
7
- class Chef
8
- module Provisioning
9
- class ConvergenceStrategy
10
- class PrecreateChefObjects < ConvergenceStrategy
11
-
12
- def initialize(convergence_options, config)
13
- super
14
- if convergence_options[:ignore_failure]
15
- extend IgnoreConvergenceFailure
16
- end
17
- end
18
-
19
- def chef_server
20
- @chef_server ||= convergence_options[:chef_server] || Cheffish.default_chef_server(config)
21
- end
22
-
23
- def setup_convergence(action_handler, machine)
24
- # Create keys on machine
25
- private_key, public_key = create_keys(action_handler, machine)
26
- # Create node and client on chef server
27
- create_chef_objects(action_handler, machine, private_key, public_key)
28
-
29
- # If the chef server lives on localhost, tunnel the port through to the guest
30
- # (we need to know what got tunneled!)
31
- chef_server_url = chef_server[:chef_server_url]
32
- chef_server_url = machine.make_url_available_to_remote(chef_server_url)
33
-
34
- # Support for multiple ohai hints, required on some platforms
35
- create_ohai_files(action_handler, machine)
36
-
37
- # Create client.rb and client.pem on machine
38
- content = client_rb_content(chef_server_url, machine.node['name'])
39
- machine.write_file(action_handler, convergence_options[:client_rb_path], content, :ensure_dir => true)
40
- end
41
-
42
- def converge(action_handler, machine)
43
- machine.make_url_available_to_remote(chef_server[:chef_server_url])
44
- end
45
-
46
- def cleanup_convergence(action_handler, machine_spec)
47
- _self = self
48
- Chef::Provisioning.inline_resource(action_handler) do
49
- chef_node machine_spec.name do
50
- chef_server _self.chef_server
51
- action :delete
52
- end
53
- chef_client machine_spec.name do
54
- chef_server _self.chef_server
55
- action :delete
56
- end
57
- end
58
- end
59
-
60
- protected
61
-
62
- def create_keys(action_handler, machine)
63
- server_private_key = machine.read_file(convergence_options[:client_pem_path])
64
- if server_private_key
65
- begin
66
- server_private_key, format = Cheffish::KeyFormatter.decode(server_private_key)
67
- rescue
68
- server_private_key = nil
69
- end
70
- end
71
-
72
- if server_private_key
73
- if source_key && server_private_key.to_pem != source_key.to_pem
74
- # If the server private key does not match our source key, overwrite it
75
- server_private_key = source_key
76
- if convergence_options[:allow_overwrite_keys]
77
- machine.write_file(action_handler, convergence_options[:client_pem_path], server_private_key.to_pem, :ensure_dir => true)
78
- else
79
- raise "Private key on machine #{machine.name} does not match desired input key."
80
- end
81
- end
82
-
83
- else
84
-
85
- # If the server does not already have keys, create them and upload
86
- _convergence_options = convergence_options
87
- Chef::Provisioning.inline_resource(action_handler) do
88
- private_key 'in_memory' do
89
- path :none
90
- if _convergence_options[:private_key_options]
91
- _convergence_options[:private_key_options].each_pair do |key,value|
92
- send(key, value)
93
- end
94
- end
95
- after { |resource, private_key| server_private_key = private_key }
96
- end
97
- end
98
-
99
- machine.write_file(action_handler, convergence_options[:client_pem_path], server_private_key.to_pem, :ensure_dir => true)
100
- end
101
-
102
- # We shouldn't be returning this: see https://github.com/chef/chef-provisioning/issues/292
103
- [ server_private_key, server_private_key.public_key ]
104
- end
105
-
106
- def is_localhost(host)
107
- host == '127.0.0.1' || host == 'localhost' || host == '[::1]'
108
- end
109
-
110
- def source_key
111
- if convergence_options[:source_key].is_a?(String)
112
- key, format = Cheffish::KeyFormatter.decode(convergence_options[:source_key], convergence_options[:source_key_pass_phrase])
113
- key
114
- elsif convergence_options[:source_key]
115
- convergence_options[:source_key]
116
- elsif convergence_options[:source_key_path]
117
- key, format = Cheffish::KeyFormatter.decode(IO.read(convergence_options[:source_key_path]), convergence_options[:source_key_pass_phrase], convergence_options[:source_key_path])
118
- key
119
- else
120
- nil
121
- end
122
- end
123
-
124
- # Create the ohai file(s)
125
- def create_ohai_files(action_handler, machine)
126
- if convergence_options[:ohai_hints]
127
- convergence_options[:ohai_hints].each_pair do |hint, data|
128
- # The location of the ohai hint
129
- ohai_hint = "/etc/chef/ohai/hints/#{hint}.json"
130
- # It's in a different path on windows
131
- if machine.machine_spec.reference['is_windows']
132
- ohai_hint = [machine.system_drive, ohai_hint.split('/')[2..-1]].join('\\')
133
- end
134
- machine.write_file(action_handler, ohai_hint, data.to_json, :ensure_dir => true)
135
- end
136
- end
137
- end
138
-
139
- def create_chef_objects(action_handler, machine, private_key, public_key)
140
- _convergence_options = convergence_options
141
- _chef_server = chef_server
142
- _format = _convergence_options[:public_key_format]
143
- # Save the node and create the client keys and client.
144
- Chef::Provisioning.inline_resource(action_handler) do
145
- # Create client
146
- chef_client machine.name do
147
- chef_server _chef_server
148
- source_key public_key
149
- output_key_path _convergence_options[:public_key_path]
150
- output_key_format _format if _format
151
- admin _convergence_options[:admin]
152
- validator _convergence_options[:validator]
153
- end
154
-
155
- # Create node
156
- # TODO strip automatic attributes first so we don't race with "current state"
157
- chef_node machine.name do
158
- chef_server _chef_server
159
- raw_json machine.node
160
- end
161
- end
162
-
163
- # If using enterprise/hosted chef, fix acls
164
- if chef_server[:chef_server_url] =~ /\/+organizations\/.+/
165
- grant_client_node_permissions(action_handler, chef_server, machine, ["read", "update"], private_key)
166
- end
167
- end
168
-
169
- # Grant the client permissions to the node
170
- # This procedure assumes that the client name and node name are the same
171
- def grant_client_node_permissions(action_handler, chef_server, machine, perms, private_key)
172
- node_name = machine.name
173
- api = Cheffish.chef_server_api(chef_server)
174
- node_perms = api.get("/nodes/#{node_name}/_acl")
175
-
176
- begin
177
- perms.each do |p|
178
- if !node_perms[p]['actors'].include?(node_name)
179
- action_handler.perform_action "Add #{node_name} to client #{p} ACLs" do
180
- node_perms[p]['actors'] << node_name
181
- api.put("/nodes/#{node_name}/_acl/#{p}", p => node_perms[p])
182
- end
183
- end
184
- end
185
- rescue Net::HTTPServerException => e
186
- if e.response.code == "400"
187
- action_handler.perform_action "Delete #{node_name} and recreate as client #{node_name}" do
188
- api.delete("/nodes/#{node_name}")
189
- as_user = chef_server.dup
190
- as_user[:options] = as_user[:options].merge(
191
- client_name: node_name,
192
- signing_key_filename: nil,
193
- raw_key: private_key.to_pem
194
- )
195
- as_user_api = Cheffish.chef_server_api(as_user)
196
- as_user_api.post("/nodes", machine.node)
197
- end
198
- else
199
- raise
200
- end
201
- end
202
- end
203
-
204
- def client_rb_content(chef_server_url, node_name)
205
- # Chef stores a 'port registry' of chef zero URLs. If we set the remote host's
206
- # chef_server_url to a `chefzero` url it will fail because it does not know
207
- # about the workstation's chef zero server
208
- uri = URI.parse(chef_server_url)
209
- if uri.scheme == 'chefzero' && uri.host == 'localhost'
210
- if !Chef::Config[:listen]
211
- raise "The remote host is configured to access the local chefzero host, but " +
212
- "the local chefzero host is not configured to listen. Provide --listen or " +
213
- "set `listen true` in the chef config."
214
- end
215
- # Once chef and chef-dk are using chef-zero which supports this, we can
216
- # remove the else block and the if check
217
- if ChefZero::SocketlessServerMap.respond_to?(:server_on_port)
218
- chef_server_url = ChefZero::SocketlessServerMap.server_on_port(uri.port).url
219
- else
220
- chef_server_url = chef_server_url.gsub(/^chefzero/, 'http')
221
- end
222
- end
223
-
224
- ssl_verify_mode = convergence_options[:ssl_verify_mode]
225
- ssl_verify_mode ||= if chef_server_url.downcase.start_with?("https")
226
- :verify_peer
227
- else
228
- :verify_none
229
- end
230
-
231
- content = <<-EOM
232
- chef_server_url #{chef_server_url.inspect}
233
- node_name #{node_name.inspect}
234
- client_key #{convergence_options[:client_pem_path].inspect}
235
- ssl_verify_mode #{ssl_verify_mode.to_sym.inspect}
236
- EOM
237
- if convergence_options[:bootstrap_proxy]
238
- content << <<-EOM
239
- http_proxy #{convergence_options[:bootstrap_proxy].inspect}
240
- https_proxy #{convergence_options[:bootstrap_proxy].inspect}
241
- EOM
242
- end
243
- if convergence_options[:bootstrap_no_proxy]
244
- content << <<-EOM
245
- no_proxy #{convergence_options[:bootstrap_no_proxy].inspect}
246
- EOM
247
- end
248
- content.gsub!(/^\s+/, "")
249
- content << convergence_options[:chef_config] if convergence_options[:chef_config]
250
- content
251
- end
252
- end
253
- end
254
- end
255
- end
1
+ require 'chef/provisioning/convergence_strategy'
2
+ require 'pathname'
3
+ require 'cheffish'
4
+ require 'chef_zero/socketless_server_map'
5
+ require_relative 'ignore_convergence_failure'
6
+
7
+ class Chef
8
+ module Provisioning
9
+ class ConvergenceStrategy
10
+ class PrecreateChefObjects < ConvergenceStrategy
11
+
12
+ def initialize(convergence_options, config)
13
+ super
14
+ if convergence_options[:ignore_failure]
15
+ extend IgnoreConvergenceFailure
16
+ end
17
+ end
18
+
19
+ def chef_server
20
+ @chef_server ||= convergence_options[:chef_server] || Cheffish.default_chef_server(config)
21
+ end
22
+
23
+ def setup_convergence(action_handler, machine)
24
+ # Create keys on machine
25
+ private_key, public_key = create_keys(action_handler, machine)
26
+ # Create node and client on chef server
27
+ create_chef_objects(action_handler, machine, private_key, public_key)
28
+
29
+ # If the chef server lives on localhost, tunnel the port through to the guest
30
+ # (we need to know what got tunneled!)
31
+ chef_server_url = chef_server[:chef_server_url]
32
+ chef_server_url = machine.make_url_available_to_remote(chef_server_url)
33
+
34
+ # Support for multiple ohai hints, required on some platforms
35
+ create_ohai_files(action_handler, machine)
36
+
37
+ # Create client.rb and client.pem on machine
38
+ content = client_rb_content(chef_server_url, machine.node['name'])
39
+ machine.write_file(action_handler, convergence_options[:client_rb_path], content, :ensure_dir => true)
40
+ end
41
+
42
+ def converge(action_handler, machine)
43
+ machine.make_url_available_to_remote(chef_server[:chef_server_url])
44
+ end
45
+
46
+ def cleanup_convergence(action_handler, machine_spec)
47
+ _self = self
48
+ Chef::Provisioning.inline_resource(action_handler) do
49
+ chef_node machine_spec.name do
50
+ chef_server _self.chef_server
51
+ action :delete
52
+ end
53
+ chef_client machine_spec.name do
54
+ chef_server _self.chef_server
55
+ action :delete
56
+ end
57
+ end
58
+ end
59
+
60
+ protected
61
+
62
+ def create_keys(action_handler, machine)
63
+ server_private_key = machine.read_file(convergence_options[:client_pem_path])
64
+ if server_private_key
65
+ begin
66
+ server_private_key, format = Cheffish::KeyFormatter.decode(server_private_key)
67
+ rescue
68
+ server_private_key = nil
69
+ end
70
+ end
71
+
72
+ if server_private_key
73
+ if source_key && server_private_key.to_pem != source_key.to_pem
74
+ # If the server private key does not match our source key, overwrite it
75
+ server_private_key = source_key
76
+ if convergence_options[:allow_overwrite_keys]
77
+ machine.write_file(action_handler, convergence_options[:client_pem_path], server_private_key.to_pem, :ensure_dir => true)
78
+ else
79
+ raise "Private key on machine #{machine.name} does not match desired input key."
80
+ end
81
+ end
82
+
83
+ else
84
+
85
+ # If the server does not already have keys, create them and upload
86
+ _convergence_options = convergence_options
87
+ Chef::Provisioning.inline_resource(action_handler) do
88
+ private_key 'in_memory' do
89
+ path :none
90
+ if _convergence_options[:private_key_options]
91
+ _convergence_options[:private_key_options].each_pair do |key,value|
92
+ send(key, value)
93
+ end
94
+ end
95
+ after { |resource, private_key| server_private_key = private_key }
96
+ end
97
+ end
98
+
99
+ machine.write_file(action_handler, convergence_options[:client_pem_path], server_private_key.to_pem, :ensure_dir => true)
100
+ end
101
+
102
+ # We shouldn't be returning this: see https://github.com/chef/chef-provisioning/issues/292
103
+ [ server_private_key, server_private_key.public_key ]
104
+ end
105
+
106
+ def is_localhost(host)
107
+ host == '127.0.0.1' || host == 'localhost' || host == '[::1]'
108
+ end
109
+
110
+ def source_key
111
+ if convergence_options[:source_key].is_a?(String)
112
+ key, format = Cheffish::KeyFormatter.decode(convergence_options[:source_key], convergence_options[:source_key_pass_phrase])
113
+ key
114
+ elsif convergence_options[:source_key]
115
+ convergence_options[:source_key]
116
+ elsif convergence_options[:source_key_path]
117
+ key, format = Cheffish::KeyFormatter.decode(IO.read(convergence_options[:source_key_path]), convergence_options[:source_key_pass_phrase], convergence_options[:source_key_path])
118
+ key
119
+ else
120
+ nil
121
+ end
122
+ end
123
+
124
+ # Create the ohai file(s)
125
+ def create_ohai_files(action_handler, machine)
126
+ if convergence_options[:ohai_hints]
127
+ convergence_options[:ohai_hints].each_pair do |hint, data|
128
+ # The location of the ohai hint
129
+ ohai_hint = "/etc/chef/ohai/hints/#{hint}.json"
130
+ # It's in a different path on windows
131
+ if machine.machine_spec.reference['is_windows']
132
+ ohai_hint = [machine.system_drive, ohai_hint.split('/')[2..-1]].join('\\')
133
+ end
134
+ machine.write_file(action_handler, ohai_hint, data.to_json, :ensure_dir => true)
135
+ end
136
+ end
137
+ end
138
+
139
+ def create_chef_objects(action_handler, machine, private_key, public_key)
140
+ _convergence_options = convergence_options
141
+ _chef_server = chef_server
142
+ _format = _convergence_options[:public_key_format]
143
+ # Save the node and create the client keys and client.
144
+ Chef::Provisioning.inline_resource(action_handler) do
145
+ # Create client
146
+ chef_client machine.name do
147
+ chef_server _chef_server
148
+ source_key public_key
149
+ output_key_path _convergence_options[:public_key_path]
150
+ output_key_format _format if _format
151
+ admin _convergence_options[:admin]
152
+ validator _convergence_options[:validator]
153
+ end
154
+
155
+ # Create node
156
+ # TODO strip automatic attributes first so we don't race with "current state"
157
+ chef_node machine.name do
158
+ chef_server _chef_server
159
+ raw_json machine.node
160
+ end
161
+ end
162
+
163
+ # If using enterprise/hosted chef, fix acls
164
+ if chef_server[:chef_server_url] =~ /\/+organizations\/.+/
165
+ grant_client_node_permissions(action_handler, chef_server, machine, ["read", "update"], private_key)
166
+ end
167
+ end
168
+
169
+ # Grant the client permissions to the node
170
+ # This procedure assumes that the client name and node name are the same
171
+ def grant_client_node_permissions(action_handler, chef_server, machine, perms, private_key)
172
+ node_name = machine.name
173
+ api = Cheffish.chef_server_api(chef_server)
174
+ node_perms = api.get("/nodes/#{node_name}/_acl")
175
+
176
+ begin
177
+ perms.each do |p|
178
+ if !node_perms[p]['actors'].include?(node_name)
179
+ action_handler.perform_action "Add #{node_name} to client #{p} ACLs" do
180
+ node_perms[p]['actors'] << node_name
181
+ api.put("/nodes/#{node_name}/_acl/#{p}", p => node_perms[p])
182
+ end
183
+ end
184
+ end
185
+ rescue Net::HTTPServerException => e
186
+ if e.response.code == "400"
187
+ action_handler.perform_action "Delete #{node_name} and recreate as client #{node_name}" do
188
+ api.delete("/nodes/#{node_name}")
189
+ as_user = chef_server.dup
190
+ as_user[:options] = as_user[:options].merge(
191
+ client_name: node_name,
192
+ signing_key_filename: nil,
193
+ raw_key: private_key.to_pem
194
+ )
195
+ as_user_api = Cheffish.chef_server_api(as_user)
196
+ as_user_api.post("/nodes", machine.node)
197
+ end
198
+ else
199
+ raise
200
+ end
201
+ end
202
+ end
203
+
204
+ def client_rb_content(chef_server_url, node_name)
205
+ # Chef stores a 'port registry' of chef zero URLs. If we set the remote host's
206
+ # chef_server_url to a `chefzero` url it will fail because it does not know
207
+ # about the workstation's chef zero server
208
+ uri = URI.parse(chef_server_url)
209
+ if uri.scheme == 'chefzero' && uri.host == 'localhost'
210
+ if !Chef::Config[:listen]
211
+ raise "The remote host is configured to access the local chefzero host, but " +
212
+ "the local chefzero host is not configured to listen. Provide --listen or " +
213
+ "set `listen true` in the chef config."
214
+ end
215
+ # Once chef and chef-dk are using chef-zero which supports this, we can
216
+ # remove the else block and the if check
217
+ if ChefZero::SocketlessServerMap.respond_to?(:server_on_port)
218
+ chef_server_url = ChefZero::SocketlessServerMap.server_on_port(uri.port).url
219
+ else
220
+ chef_server_url = chef_server_url.gsub(/^chefzero/, 'http')
221
+ end
222
+ end
223
+
224
+ ssl_verify_mode = convergence_options[:ssl_verify_mode]
225
+ ssl_verify_mode ||= if chef_server_url.downcase.start_with?("https")
226
+ :verify_peer
227
+ else
228
+ :verify_none
229
+ end
230
+
231
+ content = <<-EOM
232
+ chef_server_url #{chef_server_url.inspect}
233
+ node_name #{node_name.inspect}
234
+ client_key #{convergence_options[:client_pem_path].inspect}
235
+ ssl_verify_mode #{ssl_verify_mode.to_sym.inspect}
236
+ EOM
237
+ if convergence_options[:bootstrap_proxy]
238
+ content << <<-EOM
239
+ http_proxy #{convergence_options[:bootstrap_proxy].inspect}
240
+ https_proxy #{convergence_options[:bootstrap_proxy].inspect}
241
+ EOM
242
+ end
243
+ if convergence_options[:bootstrap_no_proxy]
244
+ content << <<-EOM
245
+ no_proxy #{convergence_options[:bootstrap_no_proxy].inspect}
246
+ EOM
247
+ end
248
+ content.gsub!(/^\s+/, "")
249
+ content << convergence_options[:chef_config] if convergence_options[:chef_config]
250
+ content
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end