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.
- checksums.yaml +4 -4
- data/Gemfile +4 -3
- data/chef.gemspec +1 -0
- data/lib/chef/client.rb +1 -1
- data/lib/chef/data_bag.rb +1 -2
- data/lib/chef/data_bag_item.rb +1 -2
- data/lib/chef/deprecated.rb +10 -4
- data/lib/chef/dsl.rb +1 -0
- data/lib/chef/dsl/render_helpers.rb +44 -0
- data/lib/chef/dsl/secret.rb +64 -0
- data/lib/chef/dsl/toml.rb +116 -0
- data/lib/chef/dsl/universal.rb +5 -0
- data/lib/chef/exceptions.rb +22 -0
- data/lib/chef/handler/slow_report.rb +1 -1
- data/lib/chef/json_compat.rb +1 -1
- data/lib/chef/policy_builder/policyfile.rb +88 -45
- data/lib/chef/provider/file.rb +2 -2
- data/lib/chef/provider/lwrp_base.rb +1 -1
- data/lib/chef/provider/package/habitat.rb +168 -0
- data/lib/chef/provider/package/powershell.rb +5 -0
- data/lib/chef/providers.rb +1 -0
- data/lib/chef/resource/chef_client_config.rb +7 -2
- data/lib/chef/resource/chef_client_cron.rb +1 -1
- data/lib/chef/resource/chef_client_launchd.rb +1 -1
- data/lib/chef/resource/chef_client_scheduled_task.rb +1 -1
- data/lib/chef/resource/chef_client_systemd_timer.rb +1 -1
- data/lib/chef/resource/chef_client_trusted_certificate.rb +2 -2
- data/lib/chef/resource/chef_vault_secret.rb +2 -2
- data/lib/chef/resource/dsc_resource.rb +1 -1
- data/lib/chef/resource/execute.rb +3 -3
- data/lib/chef/resource/gem_package.rb +2 -1
- data/lib/chef/resource/habitat/_habitat_shared.rb +28 -0
- data/lib/chef/resource/habitat/habitat_package.rb +129 -0
- data/lib/chef/resource/habitat/habitat_sup.rb +329 -0
- data/lib/chef/resource/habitat/habitat_sup_systemd.rb +67 -0
- data/lib/chef/resource/habitat/habitat_sup_windows.rb +90 -0
- data/lib/chef/resource/habitat_config.rb +107 -0
- data/lib/chef/resource/habitat_install.rb +247 -0
- data/lib/chef/resource/habitat_service.rb +451 -0
- data/lib/chef/resource/habitat_user_toml.rb +92 -0
- data/lib/chef/resource/lwrp_base.rb +1 -1
- data/lib/chef/resource/support/HabService.dll.config.erb +19 -0
- data/lib/chef/resource/support/client.erb +8 -1
- data/lib/chef/resource/support/sup.toml.erb +179 -0
- data/lib/chef/resource/windows_defender.rb +163 -0
- data/lib/chef/resource/windows_defender_exclusion.rb +125 -0
- data/lib/chef/resource/windows_printer.rb +78 -44
- data/lib/chef/resource/windows_printer_port.rb +1 -1
- data/lib/chef/resource/windows_update_settings.rb +259 -0
- data/lib/chef/resources.rb +12 -1
- data/lib/chef/secret_fetcher.rb +54 -0
- data/lib/chef/secret_fetcher/aws_secrets_manager.rb +53 -0
- data/lib/chef/secret_fetcher/azure_key_vault.rb +56 -0
- data/lib/chef/secret_fetcher/base.rb +72 -0
- data/lib/chef/secret_fetcher/example.rb +46 -0
- data/lib/chef/version.rb +1 -1
- data/spec/functional/mixin/from_file_spec.rb +1 -1
- data/spec/integration/recipes/recipe_dsl_spec.rb +1 -1
- data/spec/integration/recipes/resource_action_spec.rb +4 -4
- data/spec/support/shared/unit/provider/file.rb +2 -8
- data/spec/unit/data_bag_item_spec.rb +2 -2
- data/spec/unit/data_bag_spec.rb +1 -1
- data/spec/unit/dsl/render_helpers_spec.rb +102 -0
- data/spec/unit/dsl/secret_spec.rb +65 -0
- data/spec/unit/policy_builder/dynamic_spec.rb +0 -5
- data/spec/unit/policy_builder/policyfile_spec.rb +144 -56
- data/spec/unit/provider/apt_update_spec.rb +3 -1
- data/spec/unit/provider/mount/aix_spec.rb +1 -1
- data/spec/unit/provider/package/powershell_spec.rb +74 -12
- data/spec/unit/resource/windows_defender_exclusion_spec.rb +62 -0
- data/spec/unit/resource/windows_defender_spec.rb +71 -0
- data/spec/unit/resource/windows_update_settings_spec.rb +64 -0
- data/spec/unit/secret_fetcher/azure_key_vault_spec.rb +63 -0
- data/spec/unit/secret_fetcher_spec.rb +82 -0
- 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
|