chef-provisioning 2.0.0 → 2.0.1

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +899 -885
  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 -35
  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 -156
  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 -29
  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 +5 -5
@@ -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, "powershell.exe -ExecutionPolicy Unrestricted -NoProfile \"& \"\"#{convergence_options[:install_script_path]}\"\"\"",
45
- :raw => true,
46
- :stream_stdout => stdout,
47
- :stream_stderr => stderr)
48
- end
49
- end
50
- end
51
-
52
- def converge(action_handler, machine)
53
- super
54
-
55
- action_handler.open_stream(machine.node['name']) do |stdout|
56
- action_handler.open_stream(machine.node['name']) do |stderr|
57
- command_line = "chef-client"
58
- command_line << " -l #{config[:log_level].to_s}" if config[:log_level]
59
- machine.execute(action_handler, command_line,
60
- :raw => true,
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