chef 17.2.29-universal-mingw32 → 17.3.48-universal-mingw32

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -3
  3. data/chef.gemspec +1 -0
  4. data/lib/chef/client.rb +1 -1
  5. data/lib/chef/data_bag.rb +1 -2
  6. data/lib/chef/data_bag_item.rb +1 -2
  7. data/lib/chef/deprecated.rb +10 -4
  8. data/lib/chef/dsl.rb +1 -0
  9. data/lib/chef/dsl/render_helpers.rb +44 -0
  10. data/lib/chef/dsl/secret.rb +64 -0
  11. data/lib/chef/dsl/toml.rb +116 -0
  12. data/lib/chef/dsl/universal.rb +5 -0
  13. data/lib/chef/exceptions.rb +22 -0
  14. data/lib/chef/handler/slow_report.rb +1 -1
  15. data/lib/chef/json_compat.rb +1 -1
  16. data/lib/chef/policy_builder/policyfile.rb +88 -45
  17. data/lib/chef/provider/file.rb +2 -2
  18. data/lib/chef/provider/lwrp_base.rb +1 -1
  19. data/lib/chef/provider/package/habitat.rb +168 -0
  20. data/lib/chef/provider/package/powershell.rb +5 -0
  21. data/lib/chef/providers.rb +1 -0
  22. data/lib/chef/resource/chef_client_config.rb +7 -2
  23. data/lib/chef/resource/chef_client_cron.rb +1 -1
  24. data/lib/chef/resource/chef_client_launchd.rb +1 -1
  25. data/lib/chef/resource/chef_client_scheduled_task.rb +1 -1
  26. data/lib/chef/resource/chef_client_systemd_timer.rb +1 -1
  27. data/lib/chef/resource/chef_client_trusted_certificate.rb +2 -2
  28. data/lib/chef/resource/chef_vault_secret.rb +2 -2
  29. data/lib/chef/resource/dsc_resource.rb +1 -1
  30. data/lib/chef/resource/execute.rb +3 -3
  31. data/lib/chef/resource/gem_package.rb +2 -1
  32. data/lib/chef/resource/habitat/_habitat_shared.rb +28 -0
  33. data/lib/chef/resource/habitat/habitat_package.rb +129 -0
  34. data/lib/chef/resource/habitat/habitat_sup.rb +329 -0
  35. data/lib/chef/resource/habitat/habitat_sup_systemd.rb +67 -0
  36. data/lib/chef/resource/habitat/habitat_sup_windows.rb +90 -0
  37. data/lib/chef/resource/habitat_config.rb +107 -0
  38. data/lib/chef/resource/habitat_install.rb +247 -0
  39. data/lib/chef/resource/habitat_service.rb +451 -0
  40. data/lib/chef/resource/habitat_user_toml.rb +92 -0
  41. data/lib/chef/resource/lwrp_base.rb +1 -1
  42. data/lib/chef/resource/support/HabService.dll.config.erb +19 -0
  43. data/lib/chef/resource/support/client.erb +8 -1
  44. data/lib/chef/resource/support/sup.toml.erb +179 -0
  45. data/lib/chef/resource/windows_defender.rb +163 -0
  46. data/lib/chef/resource/windows_defender_exclusion.rb +125 -0
  47. data/lib/chef/resource/windows_printer.rb +78 -44
  48. data/lib/chef/resource/windows_printer_port.rb +1 -1
  49. data/lib/chef/resource/windows_update_settings.rb +259 -0
  50. data/lib/chef/resources.rb +12 -1
  51. data/lib/chef/secret_fetcher.rb +54 -0
  52. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +53 -0
  53. data/lib/chef/secret_fetcher/azure_key_vault.rb +56 -0
  54. data/lib/chef/secret_fetcher/base.rb +72 -0
  55. data/lib/chef/secret_fetcher/example.rb +46 -0
  56. data/lib/chef/version.rb +1 -1
  57. data/spec/functional/mixin/from_file_spec.rb +1 -1
  58. data/spec/integration/recipes/recipe_dsl_spec.rb +1 -1
  59. data/spec/integration/recipes/resource_action_spec.rb +4 -4
  60. data/spec/support/shared/unit/provider/file.rb +2 -8
  61. data/spec/unit/data_bag_item_spec.rb +2 -2
  62. data/spec/unit/data_bag_spec.rb +1 -1
  63. data/spec/unit/dsl/render_helpers_spec.rb +102 -0
  64. data/spec/unit/dsl/secret_spec.rb +65 -0
  65. data/spec/unit/policy_builder/dynamic_spec.rb +0 -5
  66. data/spec/unit/policy_builder/policyfile_spec.rb +144 -56
  67. data/spec/unit/provider/apt_update_spec.rb +3 -1
  68. data/spec/unit/provider/mount/aix_spec.rb +1 -1
  69. data/spec/unit/provider/package/powershell_spec.rb +74 -12
  70. data/spec/unit/resource/windows_defender_exclusion_spec.rb +62 -0
  71. data/spec/unit/resource/windows_defender_spec.rb +71 -0
  72. data/spec/unit/resource/windows_update_settings_spec.rb +64 -0
  73. data/spec/unit/secret_fetcher/azure_key_vault_spec.rb +63 -0
  74. data/spec/unit/secret_fetcher_spec.rb +82 -0
  75. metadata +51 -7
@@ -0,0 +1,107 @@
1
+ # Copyright:: Chef Software Inc.
2
+ # License:: Apache License, Version 2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ require_relative "../http"
17
+ require_relative "../json_compat"
18
+ require_relative "../resource"
19
+
20
+ class Chef
21
+ class Resource
22
+ class HabitatConfig < Chef::Resource
23
+ unified_mode true
24
+
25
+ provides :habitat_config
26
+
27
+ description "Use the **habitat_config** resource to apply a configuration to a Chef Habitat service."
28
+ introduced "17.3"
29
+ examples <<~DOC
30
+ **Configure your nginx defaults**
31
+
32
+ ```ruby
33
+ habitat_config 'nginx.default' do
34
+ config({
35
+ worker_count: 2,
36
+ http: {
37
+ keepalive_timeout: 120
38
+ }
39
+ })
40
+ end
41
+ ```
42
+ DOC
43
+
44
+ property :config, Mash, required: true, coerce: proc { |m| m.is_a?(Hash) ? Mash.new(m) : m },
45
+ description: "The configuration to apply as a ruby hash, for example, `{ worker_count: 2, http: { keepalive_timeout: 120 } }`."
46
+
47
+ property :service_group, String, name_property: true, desired_state: false,
48
+ description: "The service group to apply the configuration to. For example, `nginx.default`"
49
+
50
+ property :remote_sup, String, default: "127.0.0.1:9632", desired_state: false,
51
+ description: "Address to a remote supervisor's control gateway."
52
+
53
+ # Http port needed for querying/comparing current config value
54
+ property :remote_sup_http, String, default: "127.0.0.1:9631", desired_state: false,
55
+ description: "Address for remote supervisor http port. Used to pull existing."
56
+
57
+ property :gateway_auth_token, String, desired_state: false,
58
+ description: "Auth token for accessing the remote supervisor's http port."
59
+
60
+ property :user, String, desired_state: false,
61
+ description: "Name of user key to use for encryption. Passes `--user` to `hab config apply`."
62
+
63
+ load_current_value do
64
+ http_uri = "http://#{remote_sup_http}"
65
+
66
+ begin
67
+ headers = {}
68
+ headers["Authorization"] = "Bearer #{gateway_auth_token}" if property_is_set?(:gateway_auth_token)
69
+ census = Mash.new(Chef::HTTP::SimpleJSON.new(http_uri).get("/census", headers))
70
+ sc = census["census_groups"][service_group]["service_config"]["value"]
71
+ rescue
72
+ # Default to a blank config if anything (http error, json parsing, finding
73
+ # the config object) goes wrong
74
+ sc = {}
75
+ end
76
+ config sc
77
+ end
78
+
79
+ action :apply, description: "applies the given configuration" do
80
+ converge_if_changed do
81
+ # Use the current timestamp as the serial number/incarnation
82
+ incarnation = Time.now.tv_sec
83
+
84
+ opts = []
85
+ # opts gets flattened by shell_out_compact later
86
+ opts << ["--remote-sup", new_resource.remote_sup] if new_resource.remote_sup
87
+ opts << ["--user", new_resource.user] if new_resource.user
88
+
89
+ tempfile = Tempfile.new(["habitat_config", ".toml"])
90
+ begin
91
+ tempfile.write(render_toml(new_resource.config))
92
+ tempfile.close
93
+
94
+ hab("config", "apply", opts, new_resource.service_group, incarnation, tempfile.path)
95
+ ensure
96
+ tempfile.close
97
+ tempfile.unlink
98
+ end
99
+ end
100
+ end
101
+
102
+ action_class do
103
+ use "../resource/habitat/habitat_shared"
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,247 @@
1
+ #
2
+ # Copyright:: Chef Software, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+ require_relative "../http/simple"
18
+ require_relative "../resource"
19
+ class Chef
20
+ class Resource
21
+ class HabitatInstall < Chef::Resource
22
+ unified_mode true
23
+ provides :habitat_install
24
+
25
+ description "Use the **habitat_install** resource to install Chef Habitat."
26
+ introduced "17.3"
27
+ examples <<~DOC
28
+ **Installation Without a Resource Name**
29
+
30
+ ```ruby
31
+ habitat_install
32
+ ```
33
+
34
+ **Installation specifying a habitat builder URL**
35
+
36
+ ```ruby
37
+ habitat_install 'install habitat' do
38
+ bldr_url 'http://localhost'
39
+ end
40
+ ```
41
+
42
+ **Installation specifying version and habitat builder URL**
43
+
44
+ ```ruby
45
+ habitat_install 'install habitat' do
46
+ bldr_url 'http://localhost'
47
+ hab_version '1.5.50'
48
+ end
49
+ ```
50
+ DOC
51
+
52
+ property :name, String, default: "install habitat",
53
+ description: "Name of the resource block. This has no impact other than logging."
54
+
55
+ property :install_url, String, default: "https://raw.githubusercontent.com/habitat-sh/habitat/master/components/hab/install.sh",
56
+ description: "URL to the install script, default is from the [habitat repo](https://raw.githubusercontent.com/habitat-sh/habitat/master/components/hab/install.sh) ."
57
+
58
+ property :bldr_url, String,
59
+ description: "Optional URL to an alternate Habitat Builder."
60
+
61
+ property :create_user, [true, false], default: true,
62
+ description: "Creates the `hab` system user."
63
+
64
+ property :tmp_dir, String,
65
+ description: "Sets TMPDIR environment variable for location to place temp files. Note: This is required if `/tmp` and `/var/tmp` are mounted `noexec`."
66
+
67
+ property :license, String, equal_to: ["accept"],
68
+ description: "Specifies acceptance of habitat license when set to `accept`."
69
+
70
+ property :hab_version, String,
71
+ description: "Specify the version of `Habitat` you would like to install."
72
+
73
+ action :install, description: "Installs Habitat. Does nothing if the `hab` binary is found in the default location for the system (`/bin/hab` on Linux, `/usr/local/bin/hab` on macOS, `C:/habitat/hab.exe` on Windows)" do
74
+ if ::File.exist?(hab_path)
75
+ cmd = shell_out!([hab_path, "--version"].flatten.compact.join(" "))
76
+ version = %r{hab (\d*\.\d*\.\d[^\/]*)}.match(cmd.stdout)[1]
77
+ return if version == new_resource.hab_version
78
+ end
79
+
80
+ if windows?
81
+ # Retrieve version information
82
+ uri = "https://packages.chef.io/files"
83
+ package_name = "hab-x86_64-windows"
84
+ habfile = "#{Chef::Config[:file_cache_path]}/#{package_name}.zip"
85
+
86
+ # TODO: Figure out how to properly validate the shasum for windows. Doesn't seem it's published
87
+ # as a .sha265sum like for the linux .tar.gz
88
+ download = "#{uri}/stable/habitat/latest/hab-x86_64-windows.zip"
89
+
90
+ remote_file habfile do
91
+ source download
92
+ end
93
+
94
+ archive_file "#{package_name}.zip" do
95
+ path habfile
96
+ destination "#{Chef::Config[:file_cache_path]}/habitat"
97
+ action :extract
98
+ not_if { ::Dir.exist?('c:\habitat') }
99
+ end
100
+
101
+ directory 'c:\habitat' do
102
+ notifies :run, "powershell_script[installing from archive]", :immediately
103
+ end
104
+
105
+ powershell_script "installing from archive" do
106
+ code <<-EOH
107
+ Move-Item -Path #{Chef::Config[:file_cache_path]}/habitat/hab-*/* -Destination C:/habitat -Force
108
+ EOH
109
+ action :nothing
110
+ end
111
+
112
+ # TODO: This won't self heal if missing until the next upgrade
113
+ windows_path 'C:\habitat' do
114
+ action :add
115
+ end
116
+ else
117
+ package %w{curl tar gzip}
118
+
119
+ if new_resource.create_user
120
+ group "hab"
121
+
122
+ user "hab" do
123
+ gid "hab"
124
+ system true
125
+ end
126
+ end
127
+
128
+ remote_file ::File.join(Chef::Config[:file_cache_path], "hab-install.sh") do
129
+ source new_resource.install_url
130
+ sensitive true
131
+ end
132
+
133
+ execute "installing with hab-install.sh" do
134
+ command hab_command
135
+ environment(
136
+ {
137
+ "HAB_BLDR_URL" => "bldr_url",
138
+ "TMPDIR" => "tmp_dir",
139
+ }.each_with_object({}) do |(var, property), env|
140
+ env[var] = new_resource.send(property.to_sym) if new_resource.send(property.to_sym)
141
+ end
142
+ )
143
+ end
144
+ end
145
+ execute "hab license accept" if new_resource.license == "accept"
146
+ end
147
+
148
+ # TODO: Work out cleanest method to implement upgrade that will support effortless installs as well as standard chef-client
149
+ # action :upgrade do
150
+ # if platform_family?('windows')
151
+ # # Retrieve version information
152
+ # uri = 'https://packages.chef.io/files'
153
+ # package_name = 'hab-x86_64-windows'
154
+ # zipfile = "#{Chef::Config[:file_cache_path]}/#{package_name}.zip"
155
+
156
+ # # TODO: Figure out how to properly validate the shasum for windows. Doesn't seem it's published
157
+ # # as a .sha265sum like for the linux .tar.gz
158
+ # download = "#{uri}/stable/habitat/latest/hab-x86_64-windows.zip"
159
+
160
+ # remote_file zipfile do
161
+ # source download
162
+ # end
163
+
164
+ # if Chef::VERSION.to_i < 15
165
+ # ruby_block "#{package_name}.zip" do
166
+ # block do
167
+ # require 'zip'
168
+ # Zip::File.open(zipfile) do |zip_file|
169
+ # zip_file.each do |f|
170
+ # fpath = "#{Chef::Config[:file_cache_path]}/habitat/" + f.name
171
+ # zip_file.extract(f, fpath) # unless ::File.exist?(fpath)
172
+ # end
173
+ # end
174
+ # end
175
+ # action :run
176
+ # end
177
+ # else
178
+ # archive_file "#{package_name}.zip" do
179
+ # path zipfile
180
+ # destination "#{Chef::Config[:file_cache_path]}/habitat"
181
+ # action :extract
182
+ # end
183
+ # end
184
+
185
+ # powershell_script 'installing from archive' do
186
+ # code <<-EOH
187
+ # Move-Item -Path #{Chef::Config[:file_cache_path]}/habitat/hab-*/* -Destination C:/habitat -Force
188
+ # EOH
189
+ # end
190
+
191
+ # # TODO: This won't self heal if missing until the next upgrade
192
+ # if Chef::VERSION.to_i < 14
193
+ # env 'PATH_c-habitat' do
194
+ # key_name 'PATH'
195
+ # delim ';' # this was missing
196
+ # value 'C:\habitat'
197
+ # action :modify
198
+ # end
199
+ # else
200
+ # windows_path 'C:\habitat' do
201
+ # action :add
202
+ # end
203
+ # end
204
+ # else
205
+ # remote_file ::File.join(Chef::Config[:file_cache_path], 'hab-install.sh') do
206
+ # source new_resource.install_url
207
+ # sensitive true
208
+ # end
209
+
210
+ # execute 'installing with hab-install.sh' do
211
+ # command hab_command
212
+ # environment(
213
+ # {
214
+ # 'HAB_BLDR_URL' => 'bldr_url',
215
+ # 'TMPDIR' => 'tmp_dir',
216
+ # }.each_with_object({}) do |(var, property), env|
217
+ # env[var] = new_resource.send(property.to_sym) if new_resource.send(property.to_sym)
218
+ # end
219
+ # )
220
+ # not_if { ::File.exist?('/bin/hab') }
221
+ # end
222
+ # end
223
+ # end
224
+
225
+ action_class do
226
+ use "../resource/habitat/habitat_shared"
227
+
228
+ def hab_path
229
+ if macos?
230
+ "/usr/local/bin/hab"
231
+ elsif windows?
232
+ "C:/habitat/hab.exe"
233
+ else
234
+ "/bin/hab"
235
+ end
236
+ end
237
+
238
+ def hab_command
239
+ cmd = "bash #{Chef::Config[:file_cache_path]}/hab-install.sh"
240
+ cmd << " -v #{new_resource.hab_version} " if new_resource.hab_version
241
+ cmd << " -t x86_64-linux-kernel2" if node["kernel"]["release"].to_i < 3
242
+ cmd
243
+ end
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,451 @@
1
+ # Copyright:: Chef Software, Inc.
2
+ # License:: Apache License, Version 2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require_relative "../resource"
18
+ require "chef-utils/dist" unless defined?(ChefUtils::Dist)
19
+
20
+ class Chef
21
+ class Resource
22
+ class HabitatService < Chef::Resource
23
+ unified_mode true
24
+ provides :habitat_service
25
+
26
+ description "Use the **habitat_service** resource to manage Chef Habitat services. This requires that `core/hab-sup` be running as a service. See the `habitat_sup` resource documentation for more information. Note: Applications may run as a specific user. Often with Habitat, the default is `hab`, or `root`. If the application requires another user, then it should be created with Chef's `user` resource."
27
+ introduced "17.3"
28
+ examples <<~DOC
29
+ **Install and load nginx**
30
+
31
+ ```ruby
32
+ habitat_package 'core/nginx'
33
+ habitat_service 'core/nginx'
34
+
35
+ habitat_service 'core/nginx unload' do
36
+ service_name 'core/nginx'
37
+ action :unload
38
+ end
39
+ ```
40
+
41
+ **Pass the `strategy` and `topology` options to hab service commands**
42
+
43
+ ```ruby
44
+ habitat_service 'core/redis' do
45
+ strategy 'rolling'
46
+ topology 'standalone'
47
+ end
48
+ ```
49
+
50
+ **Using update_condition**
51
+
52
+ ```ruby
53
+ habitat_service 'core/redis' do
54
+ strategy 'rolling'
55
+ update_condition 'track-channel'
56
+ topology 'standalone'
57
+ end
58
+ ```
59
+
60
+ **If the service has it's own user specified that is not the `hab` user, don't create the `hab` user on install, and instead create the application user with Chef's `user` resource**
61
+
62
+ ```ruby
63
+ habitat_install 'install habitat' do
64
+ create_user false
65
+ end
66
+
67
+ user 'acme-apps' do
68
+ system true
69
+ end
70
+
71
+ habitat_service 'acme/apps'
72
+ ```
73
+ DOC
74
+
75
+ property :service_name, String, name_property: true,
76
+ description: "The name of the service, must be in the form of `origin/name`"
77
+
78
+ property :loaded, [true, false], default: false, skip_docs: true,
79
+ description: "state property indicating whether the service is loaded in the supervisor"
80
+
81
+ property :running, [true, false], default: false, skip_docs: true,
82
+ description: "state property indicating whether the service is running in the supervisor"
83
+
84
+ # hab svc options which get included based on the action of the resource
85
+ property :strategy, [Symbol, String], equal_to: [:none, "none", :'at-once', "at-once", :rolling, "rolling"], default: :none, coerce: proc { |s| s.is_a?(String) ? s.to_sym : s },
86
+ description: "Passes `--strategy` with the specified update strategy to the hab command. Defaults to `:none`. Other options are `:'at-once'` and `:rolling`"
87
+
88
+ property :topology, [Symbol, String], equal_to: [:standalone, "standalone", :leader, "leader"], default: :standalone, coerce: proc { |s| s.is_a?(String) ? s.to_sym : s },
89
+ description: "Passes `--topology` with the specified service topology to the hab command"
90
+
91
+ property :bldr_url, String, default: "https://bldr.habitat.sh/",
92
+ description: "Passes `--url` with the specified Habitat Builder URL to the hab command. Depending on the type of Habitat Builder you are connecting to, this URL will look different, here are the **3** current types:
93
+ - Public Habitat Builder (default) - `https://bldr.habitat.sh`
94
+ - On-Prem Habitat Builder installed using the [Source Install Method](https://github.com/habitat-sh/on-prem-builder) - `https://your.bldr.url`
95
+ - On-Prem Habitat Builder installed using the [Automate Installer](https://automate.chef.io/docs/on-prem-builder/) - `https://your.bldr.url/bldr/v1`"
96
+
97
+ property :channel, [Symbol, String], default: :stable, coerce: proc { |s| s.is_a?(String) ? s.to_sym : s },
98
+ description: "Passes `--channel` with the specified channel to the hab command"
99
+
100
+ property :bind, [String, Array], coerce: proc { |b| b.is_a?(String) ? [b] : b }, default: [],
101
+ description: "Passes `--bind` with the specified services to bind to the hab command. If an array of multiple service binds are specified then a `--bind` flag is added for each."
102
+
103
+ property :binding_mode, [Symbol, String], equal_to: [:strict, "strict", :relaxed, "relaxed"], default: :strict, coerce: proc { |s| s.is_a?(String) ? s.to_sym : s },
104
+ description: "Passes `--binding-mode` with the specified binding mode. Defaults to `:strict`. Options are `:strict` or `:relaxed`"
105
+
106
+ property :service_group, String, default: "default",
107
+ description: " Passes `--group` with the specified service group to the hab command"
108
+
109
+ property :shutdown_timeout, Integer, default: 8,
110
+ description: "The timeout in seconds allowed during shutdown."
111
+
112
+ property :health_check_interval, Integer, default: 30,
113
+ description: "The interval (seconds) on which to run health checks."
114
+
115
+ property :remote_sup, String, default: "127.0.0.1:9632", desired_state: false,
116
+ description: "Address to a remote Supervisor's Control Gateway"
117
+
118
+ # Http port needed for querying/comparing current config value
119
+ property :remote_sup_http, String, default: "127.0.0.1:9631", desired_state: false,
120
+ description: "IP address and port used to communicate with the remote supervisor. If this value is invalid, the resource will update the supervisor configuration each time #{ChefUtils::Dist::Server::PRODUCT} runs."
121
+
122
+ property :gateway_auth_token, String, desired_state: false,
123
+ description: "Auth token for accessing the remote supervisor's http port."
124
+
125
+ property :update_condition, [Symbol, String], equal_to: [:latest, "latest", :'track-channel', "track-channel"], default: :latest, coerce: proc { |s| s.is_a?(String) ? s.to_sym : s },
126
+ description: "Passes `--update-condition` dictating when this service should updated. Defaults to `latest`. Options are `latest` or `track-channel` **_Note: This requires a minimum habitat version of 1.5.71_**
127
+ - `latest`: Runs the latest package that can be found in the configured channel and local packages.
128
+ - `track-channel`: Always run the package at the head of a given channel. This enables service rollback, where demoting a package from a channel will cause the package to rollback to an older version of the package. A ramification of enabling this condition is that packages that are newer than the package at the head of the channel are also uninstalled during a service rollback."
129
+
130
+ load_current_value do
131
+ service_details = get_service_details(service_name)
132
+
133
+ running service_up?(service_details)
134
+ loaded service_loaded?(service_details)
135
+
136
+ if loaded
137
+ service_name get_spec_identifier(service_details)
138
+ strategy get_update_strategy(service_details)
139
+ update_condition get_update_condition(service_details)
140
+ topology get_topology(service_details)
141
+ bldr_url get_builder_url(service_details)
142
+ channel get_channel(service_details)
143
+ bind get_binds(service_details)
144
+ binding_mode get_binding_mode(service_details)
145
+ service_group get_service_group(service_details)
146
+ shutdown_timeout get_shutdown_timeout(service_details)
147
+ health_check_interval get_health_check_interval(service_details)
148
+ end
149
+
150
+ Chef::Log.debug("service #{service_name} service name: #{service_name}")
151
+ Chef::Log.debug("service #{service_name} running state: #{running}")
152
+ Chef::Log.debug("service #{service_name} loaded state: #{loaded}")
153
+ Chef::Log.debug("service #{service_name} strategy: #{strategy}")
154
+ Chef::Log.debug("service #{service_name} update condition: #{update_condition}")
155
+ Chef::Log.debug("service #{service_name} topology: #{topology}")
156
+ Chef::Log.debug("service #{service_name} builder url: #{bldr_url}")
157
+ Chef::Log.debug("service #{service_name} channel: #{channel}")
158
+ Chef::Log.debug("service #{service_name} binds: #{bind}")
159
+ Chef::Log.debug("service #{service_name} binding mode: #{binding_mode}")
160
+ Chef::Log.debug("service #{service_name} service group: #{service_group}")
161
+ Chef::Log.debug("service #{service_name} shutdown timeout: #{shutdown_timeout}")
162
+ Chef::Log.debug("service #{service_name} health check interval: #{health_check_interval}")
163
+ end
164
+
165
+ # This method is defined here otherwise it isn't usable in the
166
+ # `load_current_value` method.
167
+ #
168
+ # It performs a check with TCPSocket to ensure that the HTTP API is
169
+ # available first. If it cannot connect, it assumes that the service
170
+ # is not running. It then attempts to reach the `/services` path of
171
+ # the API to get a list of services. If this fails for some reason,
172
+ # then it assumes the service is not running.
173
+ #
174
+ # Finally, it walks the services returned by the API to look for the
175
+ # service we're configuring. If it is "Up", then we know the service
176
+ # is running and fully operational according to Habitat. This is
177
+ # wrapped in a begin/rescue block because if the service isn't
178
+ # present and `sup_for_service_name` will be nil and we will get a
179
+ # NoMethodError.
180
+ #
181
+ def get_service_details(svc_name)
182
+ http_uri = "http://#{remote_sup_http}"
183
+
184
+ begin
185
+ TCPSocket.new(URI(http_uri).host, URI(http_uri).port).close
186
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
187
+ Chef::Log.debug("Could not connect to #{http_uri} to retrieve status for #{service_name}")
188
+ return false
189
+ end
190
+
191
+ begin
192
+ headers = {}
193
+ headers["Authorization"] = "Bearer #{gateway_auth_token}" if property_is_set?(:gateway_auth_token)
194
+ svcs = Chef::HTTP::SimpleJSON.new(http_uri).get("/services", headers)
195
+ rescue
196
+ Chef::Log.debug("Could not connect to #{http_uri}/services to retrieve status for #{service_name}")
197
+ return false
198
+ end
199
+
200
+ origin, name, _version, _release = svc_name.split("/")
201
+ svcs.find do |s|
202
+ s["pkg"]["origin"] == origin && s["pkg"]["name"] == name
203
+ end
204
+ end
205
+
206
+ def service_up?(service_details)
207
+ service_details["process"]["state"] == "up"
208
+ rescue
209
+ Chef::Log.debug("#{service_name} not found on the Habitat supervisor")
210
+ false
211
+ end
212
+
213
+ def service_loaded?(service_details)
214
+ if service_details
215
+ true
216
+ else
217
+ false
218
+ end
219
+ end
220
+
221
+ def get_spec_identifier(service_details)
222
+ service_details["spec_ident"]["spec_identifier"]
223
+ rescue
224
+ Chef::Log.debug("#{service_name} not found on the Habitat supervisor")
225
+ nil
226
+ end
227
+
228
+ def get_update_strategy(service_details)
229
+ service_details["update_strategy"].to_sym
230
+ rescue
231
+ Chef::Log.debug("Update Strategy for #{service_name} not found on Supervisor API")
232
+ "none"
233
+ end
234
+
235
+ def get_update_condition(service_details)
236
+ service_details["update_condition"].to_sym
237
+ rescue
238
+ Chef::Log.debug("Update condition #{service_name} not found on Supervisor API")
239
+ "latest"
240
+ end
241
+
242
+ def get_topology(service_details)
243
+ service_details["topology"].to_sym
244
+ rescue
245
+ Chef::Log.debug("Topology for #{service_name} not found on Supervisor API")
246
+ "standalone"
247
+ end
248
+
249
+ def get_builder_url(service_details)
250
+ service_details["bldr_url"]
251
+ rescue
252
+ Chef::Log.debug("Habitat Builder URL for #{service_name} not found on Supervisor API")
253
+ "https://bldr.habitat.sh"
254
+ end
255
+
256
+ def get_channel(service_details)
257
+ service_details["channel"].to_sym
258
+ rescue
259
+ Chef::Log.debug("Channel for #{service_name} not found on Supervisor API")
260
+ "stable"
261
+ end
262
+
263
+ def get_binds(service_details)
264
+ service_details["binds"]
265
+ rescue
266
+ Chef::Log.debug("Update Strategy for #{service_name} not found on Supervisor API")
267
+ []
268
+ end
269
+
270
+ def get_binding_mode(service_details)
271
+ service_details["binding_mode"].to_sym
272
+ rescue
273
+ Chef::Log.debug("Binding mode for #{service_name} not found on Supervisor API")
274
+ "strict"
275
+ end
276
+
277
+ def get_service_group(service_details)
278
+ service_details["service_group"].split(".").last
279
+ rescue
280
+ Chef::Log.debug("Service Group for #{service_name} not found on Supervisor API")
281
+ "default"
282
+ end
283
+
284
+ def get_shutdown_timeout(service_details)
285
+ service_details["pkg"]["shutdown_timeout"]
286
+ rescue
287
+ Chef::Log.debug("Shutdown Timeout for #{service_name} not found on Supervisor API")
288
+ 8
289
+ end
290
+
291
+ def get_health_check_interval(service_details)
292
+ service_details["health_check_interval"]["secs"]
293
+ rescue
294
+ Chef::Log.debug("Health Check Interval for #{service_name} not found on Supervisor API")
295
+ 30
296
+ end
297
+
298
+ action :load, description: "(default action) runs `hab service load` to load and start the specified application service" do
299
+ modified = false
300
+ converge_if_changed :service_name do
301
+ modified = true
302
+ end
303
+ converge_if_changed :strategy do
304
+ modified = true
305
+ end
306
+ converge_if_changed :update_condition do
307
+ modified = true
308
+ end
309
+ converge_if_changed :topology do
310
+ modified = true
311
+ end
312
+ converge_if_changed :bldr_url do
313
+ modified = true
314
+ end
315
+ converge_if_changed :channel do
316
+ modified = true
317
+ end
318
+ converge_if_changed :bind do
319
+ modified = true
320
+ end
321
+ converge_if_changed :binding_mode do
322
+ modified = true
323
+ end
324
+ converge_if_changed :service_group do
325
+ modified = true
326
+ end
327
+ converge_if_changed :shutdown_timeout do
328
+ modified = true
329
+ end
330
+ converge_if_changed :health_check_interval do
331
+ modified = true
332
+ end
333
+
334
+ options = svc_options
335
+ if current_resource.loaded && modified
336
+ Chef::Log.debug("Reloading #{current_resource.service_name} using --force due to parameter change")
337
+ options << "--force"
338
+ end
339
+
340
+ unless current_resource.loaded && !modified
341
+ execute "test" do
342
+ command "hab svc load #{new_resource.service_name} #{options.join(" ")}"
343
+ retry_delay 10
344
+ retries 5
345
+ end
346
+ end
347
+ end
348
+
349
+ action :unload, description: "runs `hab service unload` to unload and stop the specified application service" do
350
+ if current_resource.loaded
351
+ execute "hab svc unload #{new_resource.service_name} #{svc_options.join(" ")}"
352
+ wait_for_service_unloaded
353
+ end
354
+ end
355
+
356
+ action :start, description: "runs `hab service start` to start the specified application service" do
357
+ unless current_resource.loaded
358
+ Chef::Log.fatal("No service named #{new_resource.service_name} is loaded on the Habitat supervisor")
359
+ raise "No service named #{new_resource.service_name} is loaded on the Habitat supervisor"
360
+ end
361
+
362
+ execute "hab svc start #{new_resource.service_name} #{svc_options.join(" ")}" unless current_resource.running
363
+ end
364
+
365
+ action :stop, description: "runs `hab service stop` to stop the specified application service" do
366
+ unless current_resource.loaded
367
+ Chef::Log.fatal("No service named #{new_resource.service_name} is loaded on the Habitat supervisor")
368
+ raise "No service named #{new_resource.service_name} is loaded on the Habitat supervisor"
369
+ end
370
+
371
+ if current_resource.running
372
+ execute "hab svc stop #{new_resource.service_name} #{svc_options.join(" ")}"
373
+ wait_for_service_stopped
374
+ end
375
+ end
376
+
377
+ action :restart, description: "runs the `:stop` and then `:start` actions" do
378
+ action_stop
379
+ action_start
380
+ end
381
+
382
+ action :reload, description: "runs the `:unload` and then `:load` actions" do
383
+ action_unload
384
+ action_load
385
+ end
386
+
387
+ action_class do
388
+ def svc_options
389
+ opts = []
390
+
391
+ # certain options are only valid for specific `hab svc` subcommands.
392
+ case action
393
+ when :load
394
+ opts.push(*new_resource.bind.map { |b| "--bind #{b}" }) if new_resource.bind
395
+ opts << "--binding-mode #{new_resource.binding_mode}"
396
+ opts << "--url #{new_resource.bldr_url}" if new_resource.bldr_url
397
+ opts << "--channel #{new_resource.channel}" if new_resource.channel
398
+ opts << "--group #{new_resource.service_group}" if new_resource.service_group
399
+ opts << "--strategy #{new_resource.strategy}" if new_resource.strategy
400
+ opts << "--update-condition #{new_resource.update_condition}" if new_resource.update_condition
401
+ opts << "--topology #{new_resource.topology}" if new_resource.topology
402
+ opts << "--health-check-interval #{new_resource.health_check_interval}" if new_resource.health_check_interval
403
+ opts << "--shutdown-timeout #{new_resource.shutdown_timeout}" if new_resource.shutdown_timeout
404
+ when :unload, :stop
405
+ opts << "--shutdown-timeout #{new_resource.shutdown_timeout}" if new_resource.shutdown_timeout
406
+ end
407
+
408
+ opts << "--remote-sup #{new_resource.remote_sup}" if new_resource.remote_sup
409
+
410
+ opts.map(&:split).flatten.compact
411
+ end
412
+
413
+ def wait_for_service_unloaded
414
+ ruby_block "wait-for-service-unloaded" do
415
+ block do
416
+ raise "#{new_resource.service_name} still loaded" if service_loaded?(get_service_details(new_resource.service_name))
417
+ end
418
+ retries get_shutdown_timeout(new_resource.service_name) + 1
419
+ retry_delay 1
420
+ end
421
+
422
+ ruby_block "update current_resource" do
423
+ block do
424
+ current_resource.loaded = service_loaded?(get_service_details(new_resource.service_name))
425
+ end
426
+ action :nothing
427
+ subscribes :run, "ruby_block[wait-for-service-unloaded]", :immediately
428
+ end
429
+ end
430
+
431
+ def wait_for_service_stopped
432
+ ruby_block "wait-for-service-stopped" do
433
+ block do
434
+ raise "#{new_resource.service_name} still running" if service_up?(get_service_details(new_resource.service_name))
435
+ end
436
+ retries get_shutdown_timeout(new_resource.service_name) + 1
437
+ retry_delay 1
438
+
439
+ ruby_block "update current_resource" do
440
+ block do
441
+ current_resource.running = service_up?(get_service_details(new_resource.service_name))
442
+ end
443
+ action :nothing
444
+ subscribes :run, "ruby_block[wait-for-service-stopped]", :immediately
445
+ end
446
+ end
447
+ end
448
+ end
449
+ end
450
+ end
451
+ end