chef-apply 0.3.3 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/chef-apply.gemspec +2 -1
- data/lib/chef_apply/action/base.rb +1 -0
- data/lib/chef_apply/action/converge_target.rb +11 -11
- data/lib/chef_apply/action/converge_target/ccr_failure_mapper.rb +100 -0
- data/lib/chef_apply/action/generate_local_policy.rb +1 -1
- data/lib/chef_apply/action/generate_temp_cookbook.rb +53 -53
- data/lib/chef_apply/action/generate_temp_cookbook/recipe_lookup.rb +124 -0
- data/lib/chef_apply/action/generate_temp_cookbook/temp_cookbook.rb +175 -0
- data/lib/chef_apply/action/install_chef.rb +8 -8
- data/lib/chef_apply/action/install_chef/minimum_chef_version.rb +85 -0
- data/lib/chef_apply/cli.rb +10 -9
- data/lib/chef_apply/cli/options.rb +2 -2
- data/lib/chef_apply/cli/validation.rb +2 -1
- data/lib/chef_apply/file_fetcher.rb +1 -1
- data/lib/chef_apply/log.rb +4 -6
- data/lib/chef_apply/startup.rb +7 -4
- data/lib/chef_apply/target_host.rb +10 -5
- data/lib/chef_apply/target_host/linux.rb +1 -1
- data/lib/chef_apply/target_resolver.rb +3 -1
- data/lib/chef_apply/telemeter.rb +1 -1
- data/lib/chef_apply/text/error_translation.rb +1 -1
- data/lib/chef_apply/text/text_wrapper.rb +2 -1
- data/lib/chef_apply/ui/error_printer.rb +15 -13
- data/lib/chef_apply/ui/plain_text_element.rb +1 -2
- data/lib/chef_apply/ui/plain_text_header.rb +1 -1
- data/lib/chef_apply/ui/terminal.rb +4 -4
- data/lib/chef_apply/version.rb +1 -1
- data/spec/spec_helper.rb +43 -3
- data/spec/unit/action/base_spec.rb +2 -1
- data/spec/unit/{errors → action/converge_target}/ccr_failure_mapper_spec.rb +12 -9
- data/spec/unit/action/converge_target_spec.rb +21 -22
- data/spec/unit/action/generate_local_policy_spec.rb +5 -5
- data/spec/unit/{recipe_lookup_spec.rb → action/generate_temp_cookbook/recipe_lookup_spec.rb} +10 -10
- data/spec/unit/{temp_cookbook_spec.rb → action/generate_temp_cookbook/temp_cookbook_spec.rb} +23 -24
- data/spec/unit/action/generate_temp_cookbook_spec.rb +4 -6
- data/spec/unit/{minimum_chef_version_spec.rb → action/install_chef/minimum_chef_version_spec.rb} +13 -13
- data/spec/unit/action/install_chef_spec.rb +4 -4
- data/spec/unit/cli/options_spec.rb +17 -17
- data/spec/unit/cli/validation_spec.rb +6 -3
- data/spec/unit/cli_spec.rb +12 -9
- data/spec/unit/log_spec.rb +1 -1
- data/spec/unit/startup_spec.rb +11 -12
- data/spec/unit/target_host/windows_spec.rb +1 -1
- data/spec/unit/target_host_spec.rb +3 -2
- data/spec/unit/telemeter_spec.rb +5 -5
- data/spec/unit/text/error_translation_spec.rb +11 -7
- data/spec/unit/ui/error_printer_spec.rb +6 -7
- metadata +24 -11
- data/Gemfile.lock +0 -400
- data/lib/chef_apply/errors/ccr_failure_mapper.rb +0 -93
- data/lib/chef_apply/minimum_chef_version.rb +0 -79
- data/lib/chef_apply/recipe_lookup.rb +0 -117
- data/lib/chef_apply/temp_cookbook.rb +0 -170
@@ -0,0 +1,175 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2018 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
|
+
|
18
|
+
require "tmpdir"
|
19
|
+
require "fileutils"
|
20
|
+
require "chef_apply/log"
|
21
|
+
require "chef_apply/error"
|
22
|
+
require "chef_apply/action/generate_temp_cookbook"
|
23
|
+
module ChefApply
|
24
|
+
module Action
|
25
|
+
class GenerateTempCookbook
|
26
|
+
# This class knows how to create a local cookbook in a temp file, populate
|
27
|
+
# it with various recipes, attributes, config, etc. and delete it when the
|
28
|
+
# cookbook is no longer necessary
|
29
|
+
class TempCookbook
|
30
|
+
attr_reader :path, :descriptor, :from
|
31
|
+
def initialize
|
32
|
+
@path = Dir.mktmpdir("cw")
|
33
|
+
end
|
34
|
+
|
35
|
+
def from_existing_recipe(existing_recipe_path)
|
36
|
+
ext_name = File.extname(existing_recipe_path)
|
37
|
+
raise UnsupportedExtension.new(ext_name) unless ext_name == ".rb"
|
38
|
+
|
39
|
+
cb = cookbook_for_recipe(existing_recipe_path)
|
40
|
+
if cb
|
41
|
+
# Full existing cookbook - only needs policyfile
|
42
|
+
ChefApply::Log.debug("Found full cookbook at path '#{cb[:path]}' and using recipe '#{cb[:recipe_name]}'")
|
43
|
+
@descriptor = "#{cb[:name]}::#{cb[:recipe_name]}"
|
44
|
+
@from = "#{cb[:path]}"
|
45
|
+
recipe_name = cb[:recipe_name]
|
46
|
+
cb_name = cb[:name]
|
47
|
+
FileUtils.cp_r(cb[:path], path)
|
48
|
+
# cp_r copies the whole existing cookbook into the tempdir so need to reset our path
|
49
|
+
@path = File.join(path, File.basename(cb[:path]))
|
50
|
+
else
|
51
|
+
# Cookbook from single recipe not in a cookbook. We create the full cookbook
|
52
|
+
# structure including metadata, then generate policyfile. We set the cookbook
|
53
|
+
# name to the recipe name so hopefully this gives us better reporting info
|
54
|
+
# in the future
|
55
|
+
ChefApply::Log.debug("Found single recipe at path '#{existing_recipe_path}'")
|
56
|
+
recipe = File.basename(existing_recipe_path)
|
57
|
+
recipe_name = File.basename(recipe, ext_name)
|
58
|
+
cb_name = "cw_recipe"
|
59
|
+
@descriptor = "#{recipe_name}"
|
60
|
+
@from = existing_recipe_path
|
61
|
+
recipes_dir = generate_recipes_dir
|
62
|
+
# This has the potential to break if they specify a recipe without a .rb
|
63
|
+
# extension, but lets wait to deal with that bug until we encounter it
|
64
|
+
FileUtils.cp(existing_recipe_path, File.join(recipes_dir, recipe))
|
65
|
+
generate_metadata(cb_name)
|
66
|
+
end
|
67
|
+
generate_policyfile(cb_name, recipe_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def from_resource(resource_type, resource_name, properties)
|
71
|
+
# Generate a cookbook containing a single default recipe with the specified
|
72
|
+
# resource in it. Incloud the resource type in the cookbook name so hopefully
|
73
|
+
# this gives us better reporting info in the future.
|
74
|
+
@descriptor = "#{resource_type}[#{resource_name}]"
|
75
|
+
@from = "resource"
|
76
|
+
|
77
|
+
ChefApply::Log.debug("Generating cookbook for single resource '#{resource_type}[#{resource_name}]'")
|
78
|
+
name = "cw_#{resource_type}"
|
79
|
+
recipe_name = "default"
|
80
|
+
recipes_dir = generate_recipes_dir
|
81
|
+
File.open(File.join(recipes_dir, "#{recipe_name}.rb"), "w+") do |f|
|
82
|
+
f.print(create_resource_definition(resource_type, resource_name, properties))
|
83
|
+
end
|
84
|
+
generate_metadata(name)
|
85
|
+
generate_policyfile(name, recipe_name)
|
86
|
+
end
|
87
|
+
|
88
|
+
def delete
|
89
|
+
FileUtils.remove_entry path
|
90
|
+
end
|
91
|
+
|
92
|
+
def cookbook_for_recipe(existing_recipe_path)
|
93
|
+
metadata = File.expand_path(File.join(existing_recipe_path, "../../metadata.rb"))
|
94
|
+
if File.file?(metadata)
|
95
|
+
require "chef/cookbook/metadata"
|
96
|
+
m = Chef::Cookbook::Metadata.new
|
97
|
+
m.from_file(metadata)
|
98
|
+
{
|
99
|
+
name: m.name,
|
100
|
+
recipe_name: File.basename(existing_recipe_path, File.extname(existing_recipe_path)),
|
101
|
+
path: File.expand_path(File.join(metadata, "../")),
|
102
|
+
}
|
103
|
+
else
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def generate_recipes_dir
|
109
|
+
recipes_path = File.join(path, "recipes")
|
110
|
+
FileUtils.mkdir_p(recipes_path)
|
111
|
+
recipes_path
|
112
|
+
end
|
113
|
+
|
114
|
+
def generate_metadata(name)
|
115
|
+
metadata_file = File.join(path, "metadata.rb")
|
116
|
+
File.open(metadata_file, "w+") do |f|
|
117
|
+
f.print("name \"#{name}\"\n")
|
118
|
+
end
|
119
|
+
metadata_file
|
120
|
+
end
|
121
|
+
|
122
|
+
def generate_policyfile(name, recipe_name)
|
123
|
+
policy_file = File.join(path, "Policyfile.rb")
|
124
|
+
if File.exist?(policy_file)
|
125
|
+
File.open(policy_file, "a") do |f|
|
126
|
+
# We override the specified run_list with the run_list we want.
|
127
|
+
# We append and put this at the end of the file so it overrides
|
128
|
+
# any specified run_list.
|
129
|
+
f.print("\n# Overriding run_list with command line specified value\n")
|
130
|
+
f.print("run_list \"#{name}::#{recipe_name}\"\n")
|
131
|
+
end
|
132
|
+
else
|
133
|
+
File.open(policy_file, "w+") do |f|
|
134
|
+
f.print("name \"#{name}_policy\"\n")
|
135
|
+
ChefApply::Config.chef.cookbook_repo_paths.each do |p|
|
136
|
+
f.print("default_source :chef_repo, \"#{p}\"\n")
|
137
|
+
end
|
138
|
+
f.print("default_source :supermarket\n")
|
139
|
+
f.print("run_list \"#{name}::#{recipe_name}\"\n")
|
140
|
+
f.print("cookbook \"#{name}\", path: \".\"\n")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
policy_file
|
144
|
+
end
|
145
|
+
|
146
|
+
def create_resource_definition(resource_type, resource_name, properties)
|
147
|
+
r = "#{resource_type} '#{resource_name}'"
|
148
|
+
# lets format the properties into the correct syntax Chef expects
|
149
|
+
unless properties.empty?
|
150
|
+
r += " do\n"
|
151
|
+
properties.each do |k, v|
|
152
|
+
v = "'#{v}'" if v.is_a? String
|
153
|
+
r += " #{k} #{v}\n"
|
154
|
+
end
|
155
|
+
r += "end"
|
156
|
+
end
|
157
|
+
r += "\n"
|
158
|
+
r
|
159
|
+
end
|
160
|
+
|
161
|
+
def policyfile_lock_path
|
162
|
+
File.join(path, "Policyfile.lock.json")
|
163
|
+
end
|
164
|
+
|
165
|
+
def export_path
|
166
|
+
File.join(path, "export")
|
167
|
+
end
|
168
|
+
|
169
|
+
class UnsupportedExtension < ChefApply::ErrorNoLogs
|
170
|
+
def initialize(ext); super("CHEFVAL009", ext); end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -16,19 +16,18 @@
|
|
16
16
|
#
|
17
17
|
|
18
18
|
require "chef_apply/action/base"
|
19
|
-
require "chef_apply/minimum_chef_version"
|
19
|
+
require "chef_apply/action/install_chef/minimum_chef_version"
|
20
20
|
require "fileutils"
|
21
21
|
|
22
22
|
module ChefApply
|
23
23
|
module Action
|
24
|
-
class InstallChef <
|
25
|
-
|
24
|
+
class InstallChef < Base
|
26
25
|
def initialize(opts = { check_only: false })
|
27
26
|
super
|
28
27
|
end
|
29
28
|
|
30
29
|
def perform_action
|
31
|
-
if
|
30
|
+
if InstallChef::MinimumChefVersion.check!(target_host, config[:check_only]) == :minimum_version_met
|
32
31
|
notify(:already_installed)
|
33
32
|
else
|
34
33
|
perform_local_install
|
@@ -40,7 +39,7 @@ module ChefApply
|
|
40
39
|
end
|
41
40
|
|
42
41
|
def perform_local_install
|
43
|
-
package = lookup_artifact
|
42
|
+
package = lookup_artifact
|
44
43
|
notify(:downloading)
|
45
44
|
local_path = download_to_workstation(package.url)
|
46
45
|
notify(:uploading)
|
@@ -54,18 +53,19 @@ module ChefApply
|
|
54
53
|
# TODO BOOTSTRAP - we'll need to implement this for both platforms
|
55
54
|
# require "mixlib/install"
|
56
55
|
# installer = Mixlib::Install.new({
|
57
|
-
# platform: "windows"
|
56
|
+
# platform: "windows",/etc -
|
58
57
|
# product_name: "chef",
|
59
58
|
# channel: :stable,
|
60
59
|
# shell_type: :ps1,
|
61
60
|
# version: "13",
|
62
61
|
# })
|
63
|
-
target_host.run_command! installer.install_command
|
62
|
+
# target_host.run_command! installer.install_command
|
64
63
|
raise NotImplementedError
|
65
64
|
end
|
66
65
|
|
67
66
|
def lookup_artifact
|
68
67
|
return @artifact_info if @artifact_info
|
68
|
+
|
69
69
|
require "mixlib/install"
|
70
70
|
c = train_to_mixlib(target_host.platform)
|
71
71
|
Mixlib::Install.new(c).artifact_info
|
@@ -109,7 +109,7 @@ module ChefApply
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def upload_to_target(local_path)
|
112
|
-
installer_dir = target_host.temp_dir
|
112
|
+
installer_dir = target_host.temp_dir
|
113
113
|
remote_path = File.join(installer_dir, File.basename(local_path))
|
114
114
|
target_host.upload_file(local_path, remote_path)
|
115
115
|
remote_path
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2017 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
|
+
|
18
|
+
require "chef_apply/error"
|
19
|
+
require "chef_apply/action/install_chef/minimum_chef_version"
|
20
|
+
|
21
|
+
module ChefApply
|
22
|
+
module Action
|
23
|
+
class InstallChef < Base
|
24
|
+
class MinimumChefVersion
|
25
|
+
|
26
|
+
CONSTRAINTS = {
|
27
|
+
windows: {
|
28
|
+
13 => Gem::Version.new("13.10.4"),
|
29
|
+
14 => Gem::Version.new("14.4.22"),
|
30
|
+
},
|
31
|
+
linux: {
|
32
|
+
13 => Gem::Version.new("13.10.4"),
|
33
|
+
14 => Gem::Version.new("14.1.1"),
|
34
|
+
},
|
35
|
+
}.freeze
|
36
|
+
|
37
|
+
def self.check!(target, check_only)
|
38
|
+
begin
|
39
|
+
installed_version = target.installed_chef_version
|
40
|
+
rescue ChefApply::TargetHost::ChefNotInstalled
|
41
|
+
if check_only
|
42
|
+
raise ClientNotInstalled.new
|
43
|
+
end
|
44
|
+
|
45
|
+
return :client_not_installed
|
46
|
+
end
|
47
|
+
|
48
|
+
os_constraints = CONSTRAINTS[target.base_os]
|
49
|
+
min_14_version = os_constraints[14]
|
50
|
+
min_13_version = os_constraints[13]
|
51
|
+
|
52
|
+
case
|
53
|
+
when installed_version >= Gem::Version.new("14.0.0") && installed_version < min_14_version
|
54
|
+
raise Client14Outdated.new(installed_version, min_14_version)
|
55
|
+
when installed_version >= Gem::Version.new("13.0.0") && installed_version < min_13_version
|
56
|
+
raise Client13Outdated.new(installed_version, min_13_version, min_14_version)
|
57
|
+
when installed_version < Gem::Version.new("13.0.0")
|
58
|
+
# If they have Chef < 13.0.0 installed we want to show them the easiest upgrade path -
|
59
|
+
# Chef 13 first and then Chef 14 since most customers cannot make the leap directly
|
60
|
+
# to 14.
|
61
|
+
raise Client13Outdated.new(installed_version, min_13_version, min_14_version)
|
62
|
+
end
|
63
|
+
|
64
|
+
:minimum_version_met
|
65
|
+
end
|
66
|
+
|
67
|
+
class ClientNotInstalled < ChefApply::ErrorNoLogs
|
68
|
+
def initialize(); super("CHEFINS002"); end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Client13Outdated < ChefApply::ErrorNoLogs
|
72
|
+
def initialize(current_version, min_13_version, min_14_version)
|
73
|
+
super("CHEFINS003", current_version, min_13_version, min_14_version)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Client14Outdated < ChefApply::ErrorNoLogs
|
78
|
+
def initialize(current_version, target_version)
|
79
|
+
super("CHEFINS004", current_version, target_version)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/chef_apply/cli.rb
CHANGED
@@ -24,10 +24,6 @@ require "chef-config/logger"
|
|
24
24
|
require "chef_apply/cli/validation"
|
25
25
|
require "chef_apply/cli/options"
|
26
26
|
require "chef_apply/cli/help"
|
27
|
-
require "chef_apply/action/converge_target"
|
28
|
-
require "chef_apply/action/generate_local_policy"
|
29
|
-
require "chef_apply/action/generate_temp_cookbook"
|
30
|
-
require "chef_apply/action/install_chef"
|
31
27
|
require "chef_apply/error"
|
32
28
|
require "chef_apply/log"
|
33
29
|
require "chef_apply/target_host"
|
@@ -39,6 +35,10 @@ require "chef_apply/ui/terminal/job"
|
|
39
35
|
require "license_acceptance/cli_flags/mixlib_cli"
|
40
36
|
require "license_acceptance/acceptor"
|
41
37
|
|
38
|
+
require "chef_apply/action/generate_temp_cookbook"
|
39
|
+
require "chef_apply/action/generate_local_policy"
|
40
|
+
require "chef_apply/action/converge_target"
|
41
|
+
|
42
42
|
module ChefApply
|
43
43
|
class CLI
|
44
44
|
attr_reader :temp_cookbook, :archive_file_location, :target_hosts
|
@@ -118,9 +118,8 @@ module ChefApply
|
|
118
118
|
rescue OptionParser::InvalidOption => e # from parse_options
|
119
119
|
# Using nil here is a bit gross but it prevents usage from printing.
|
120
120
|
ove = OptionValidationError.new("CHEFVAL010", nil,
|
121
|
-
|
122
|
-
|
123
|
-
)
|
121
|
+
e.message.split(":")[1].strip, # only want the flag
|
122
|
+
format_flags.lines[1..-1].join) # remove 'FLAGS:' header
|
124
123
|
handle_perform_error(ove)
|
125
124
|
rescue => e
|
126
125
|
handle_perform_error(e)
|
@@ -140,8 +139,8 @@ module ChefApply
|
|
140
139
|
|
141
140
|
def resolve_targets(host_spec, opts)
|
142
141
|
@target_hosts = TargetResolver.new(host_spec,
|
143
|
-
|
144
|
-
|
142
|
+
opts.delete(:protocol),
|
143
|
+
opts).targets
|
145
144
|
end
|
146
145
|
|
147
146
|
def render_cookbook_setup(arguments)
|
@@ -182,6 +181,7 @@ module ChefApply
|
|
182
181
|
end
|
183
182
|
|
184
183
|
def install(target_host, reporter)
|
184
|
+
require "chef_apply/action/install_chef"
|
185
185
|
context = TS.install_chef
|
186
186
|
reporter.update(context.verifying)
|
187
187
|
installer = Action::InstallChef.new(target_host: target_host, check_only: !parsed_options[:install])
|
@@ -310,6 +310,7 @@ module ChefApply
|
|
310
310
|
# message when there was only one job.
|
311
311
|
raise jobs.first.exception
|
312
312
|
end
|
313
|
+
|
313
314
|
raise ChefApply::MultiJobFailure.new(failed_jobs)
|
314
315
|
end
|
315
316
|
|
@@ -16,7 +16,6 @@
|
|
16
16
|
#
|
17
17
|
|
18
18
|
require "chef_apply/text"
|
19
|
-
require "chef_apply/action/install_chef"
|
20
19
|
|
21
20
|
# Moving the options into here so the cli.rb file is smaller and easier to read
|
22
21
|
# For options that need to be merged back into the global ChefApply::Config object
|
@@ -68,6 +67,7 @@ module ChefApply
|
|
68
67
|
unless File.exist?(path)
|
69
68
|
raise OptionValidationError.new("CHEFVAL001", self, path)
|
70
69
|
end
|
70
|
+
|
71
71
|
path
|
72
72
|
end)
|
73
73
|
|
@@ -89,7 +89,7 @@ module ChefApply
|
|
89
89
|
long: "--protocol <PROTOCOL>",
|
90
90
|
short: "-p",
|
91
91
|
description: T.protocol_description(ChefApply::Config::SUPPORTED_PROTOCOLS.join(" "),
|
92
|
-
|
92
|
+
ChefApply::Config.connection.default_protocol),
|
93
93
|
default: ChefApply::Config.connection.default_protocol,
|
94
94
|
proc: Proc.new { |val| ChefApply::Config.connection.default_protocol(val) }
|
95
95
|
|
@@ -30,6 +30,7 @@ module ChefApply
|
|
30
30
|
if params.size < 2
|
31
31
|
raise OptionValidationError.new("CHEFVAL002", self)
|
32
32
|
end
|
33
|
+
|
33
34
|
if params.size == 2
|
34
35
|
# Trying to specify a recipe to run remotely, no properties
|
35
36
|
cb = params[1]
|
@@ -73,7 +74,7 @@ module ChefApply
|
|
73
74
|
value
|
74
75
|
when /^\d+$/
|
75
76
|
value.to_i
|
76
|
-
when
|
77
|
+
when /^\d+\.\d*$/, /^\d*\.\d+$/
|
77
78
|
value.to_f
|
78
79
|
when /true/i
|
79
80
|
true
|
data/lib/chef_apply/log.rb
CHANGED
@@ -24,19 +24,17 @@ module ChefApply
|
|
24
24
|
def self.setup(location, log_level)
|
25
25
|
if location.is_a?(String)
|
26
26
|
if location.casecmp("stdout") == 0
|
27
|
-
|
27
|
+
@stream = $stdout
|
28
28
|
else
|
29
|
-
|
29
|
+
@stream = File.open(location, "w+")
|
30
30
|
end
|
31
31
|
end
|
32
|
-
@location = location
|
33
32
|
init(location)
|
34
33
|
Log.level = log_level
|
35
34
|
end
|
36
35
|
|
37
|
-
def self.
|
38
|
-
@
|
36
|
+
def self.stream
|
37
|
+
@stream
|
39
38
|
end
|
40
|
-
|
41
39
|
end
|
42
40
|
end
|