chef-apply 0.3.3 → 0.4.6

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/chef-apply.gemspec +2 -1
  4. data/lib/chef_apply/action/base.rb +1 -0
  5. data/lib/chef_apply/action/converge_target.rb +11 -11
  6. data/lib/chef_apply/action/converge_target/ccr_failure_mapper.rb +100 -0
  7. data/lib/chef_apply/action/generate_local_policy.rb +1 -1
  8. data/lib/chef_apply/action/generate_temp_cookbook.rb +53 -53
  9. data/lib/chef_apply/action/generate_temp_cookbook/recipe_lookup.rb +124 -0
  10. data/lib/chef_apply/action/generate_temp_cookbook/temp_cookbook.rb +175 -0
  11. data/lib/chef_apply/action/install_chef.rb +8 -8
  12. data/lib/chef_apply/action/install_chef/minimum_chef_version.rb +85 -0
  13. data/lib/chef_apply/cli.rb +10 -9
  14. data/lib/chef_apply/cli/options.rb +2 -2
  15. data/lib/chef_apply/cli/validation.rb +2 -1
  16. data/lib/chef_apply/file_fetcher.rb +1 -1
  17. data/lib/chef_apply/log.rb +4 -6
  18. data/lib/chef_apply/startup.rb +7 -4
  19. data/lib/chef_apply/target_host.rb +10 -5
  20. data/lib/chef_apply/target_host/linux.rb +1 -1
  21. data/lib/chef_apply/target_resolver.rb +3 -1
  22. data/lib/chef_apply/telemeter.rb +1 -1
  23. data/lib/chef_apply/text/error_translation.rb +1 -1
  24. data/lib/chef_apply/text/text_wrapper.rb +2 -1
  25. data/lib/chef_apply/ui/error_printer.rb +15 -13
  26. data/lib/chef_apply/ui/plain_text_element.rb +1 -2
  27. data/lib/chef_apply/ui/plain_text_header.rb +1 -1
  28. data/lib/chef_apply/ui/terminal.rb +4 -4
  29. data/lib/chef_apply/version.rb +1 -1
  30. data/spec/spec_helper.rb +43 -3
  31. data/spec/unit/action/base_spec.rb +2 -1
  32. data/spec/unit/{errors → action/converge_target}/ccr_failure_mapper_spec.rb +12 -9
  33. data/spec/unit/action/converge_target_spec.rb +21 -22
  34. data/spec/unit/action/generate_local_policy_spec.rb +5 -5
  35. data/spec/unit/{recipe_lookup_spec.rb → action/generate_temp_cookbook/recipe_lookup_spec.rb} +10 -10
  36. data/spec/unit/{temp_cookbook_spec.rb → action/generate_temp_cookbook/temp_cookbook_spec.rb} +23 -24
  37. data/spec/unit/action/generate_temp_cookbook_spec.rb +4 -6
  38. data/spec/unit/{minimum_chef_version_spec.rb → action/install_chef/minimum_chef_version_spec.rb} +13 -13
  39. data/spec/unit/action/install_chef_spec.rb +4 -4
  40. data/spec/unit/cli/options_spec.rb +17 -17
  41. data/spec/unit/cli/validation_spec.rb +6 -3
  42. data/spec/unit/cli_spec.rb +12 -9
  43. data/spec/unit/log_spec.rb +1 -1
  44. data/spec/unit/startup_spec.rb +11 -12
  45. data/spec/unit/target_host/windows_spec.rb +1 -1
  46. data/spec/unit/target_host_spec.rb +3 -2
  47. data/spec/unit/telemeter_spec.rb +5 -5
  48. data/spec/unit/text/error_translation_spec.rb +11 -7
  49. data/spec/unit/ui/error_printer_spec.rb +6 -7
  50. metadata +24 -11
  51. data/Gemfile.lock +0 -400
  52. data/lib/chef_apply/errors/ccr_failure_mapper.rb +0 -93
  53. data/lib/chef_apply/minimum_chef_version.rb +0 -79
  54. data/lib/chef_apply/recipe_lookup.rb +0 -117
  55. data/lib/chef_apply/temp_cookbook.rb +0 -170
@@ -1,79 +0,0 @@
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
-
20
- module ChefApply
21
- class MinimumChefVersion
22
-
23
- CONSTRAINTS = {
24
- windows: {
25
- 13 => Gem::Version.new("13.10.4"),
26
- 14 => Gem::Version.new("14.4.22"),
27
- },
28
- linux: {
29
- 13 => Gem::Version.new("13.10.4"),
30
- 14 => Gem::Version.new("14.1.1"),
31
- },
32
- }.freeze
33
-
34
- def self.check!(target, check_only)
35
- begin
36
- installed_version = target.installed_chef_version
37
- rescue ChefApply::TargetHost::ChefNotInstalled
38
- if check_only
39
- raise ClientNotInstalled.new()
40
- end
41
- return :client_not_installed
42
- end
43
-
44
- os_constraints = CONSTRAINTS[target.base_os]
45
- min_14_version = os_constraints[14]
46
- min_13_version = os_constraints[13]
47
-
48
- case
49
- when installed_version >= Gem::Version.new("14.0.0") && installed_version < min_14_version
50
- raise Client14Outdated.new(installed_version, min_14_version)
51
- when installed_version >= Gem::Version.new("13.0.0") && installed_version < min_13_version
52
- raise Client13Outdated.new(installed_version, min_13_version, min_14_version)
53
- when installed_version < Gem::Version.new("13.0.0")
54
- # If they have Chef < 13.0.0 installed we want to show them the easiest upgrade path -
55
- # Chef 13 first and then Chef 14 since most customers cannot make the leap directly
56
- # to 14.
57
- raise Client13Outdated.new(installed_version, min_13_version, min_14_version)
58
- end
59
-
60
- :minimum_version_met
61
- end
62
-
63
- class ClientNotInstalled < ChefApply::ErrorNoLogs
64
- def initialize(); super("CHEFINS002"); end
65
- end
66
-
67
- class Client13Outdated < ChefApply::ErrorNoLogs
68
- def initialize(current_version, min_13_version, min_14_version)
69
- super("CHEFINS003", current_version, min_13_version, min_14_version)
70
- end
71
- end
72
-
73
- class Client14Outdated < ChefApply::ErrorNoLogs
74
- def initialize(current_version, target_version)
75
- super("CHEFINS004", current_version, target_version)
76
- end
77
- end
78
- end
79
- end
@@ -1,117 +0,0 @@
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-config/config"
19
- require "chef_apply/config"
20
- require "chef_apply/error"
21
- require "chef_apply/log"
22
-
23
- module ChefApply
24
- # When users are trying to converge a local recipe on a remote target, there
25
- # is a very specific (but expansive) set of things they can specify. This
26
- # class encapsulates that logic for testing purposes. We either return
27
- # a path to a recipe or we raise an error.
28
- class RecipeLookup
29
-
30
- attr_reader :cookbook_repo_paths
31
- def initialize(cookbook_repo_paths)
32
- @cookbook_repo_paths = cookbook_repo_paths
33
- end
34
-
35
- # The recipe specifier is provided by the customer as either a path OR
36
- # a cookbook and optional recipe name.
37
- def split(recipe_specifier)
38
- recipe_specifier.split("::")
39
- end
40
-
41
- # Given a cookbook path or name, try to load that cookbook. Either return
42
- # a cookbook object or raise an error.
43
- def load_cookbook(path_or_name)
44
- require "chef/exceptions"
45
- if File.directory?(path_or_name)
46
- cookbook_path = path_or_name
47
- # First, is there a cookbook in the specified dir that matches?
48
- require "chef/cookbook/cookbook_version_loader"
49
- begin
50
- v = Chef::Cookbook::CookbookVersionLoader.new(cookbook_path)
51
- v.load!
52
- cookbook = v.cookbook_version
53
- rescue Chef::Exceptions::CookbookNotFoundInRepo
54
- raise InvalidCookbook.new(cookbook_path)
55
- end
56
- else
57
- cookbook_name = path_or_name
58
- # Second, is there a cookbook in their local repository that matches?
59
- require "chef/cookbook_loader"
60
- cb_loader = Chef::CookbookLoader.new(cookbook_repo_paths)
61
- cb_loader.load_cookbooks
62
-
63
- begin
64
- cookbook = cb_loader[cookbook_name]
65
- rescue Chef::Exceptions::CookbookNotFoundInRepo
66
- cookbook_repo_paths.each do |repo_path|
67
- cookbook_path = File.join(repo_path, cookbook_name)
68
- if File.directory?(cookbook_path)
69
- raise InvalidCookbook.new(cookbook_path)
70
- end
71
- end
72
- raise CookbookNotFound.new(cookbook_name, cookbook_repo_paths)
73
- end
74
- end
75
- cookbook
76
- end
77
-
78
- # Find the specified recipe or default recipe if none is specified.
79
- # Raise an error if recipe cannot be found.
80
- def find_recipe(cookbook, recipe_name = nil)
81
- recipes = cookbook.recipe_filenames_by_name
82
- if recipe_name.nil?
83
- default_recipe = recipes["default"]
84
- raise NoDefaultRecipe.new(cookbook.root_dir, cookbook.name) if default_recipe.nil?
85
- default_recipe
86
- else
87
- recipe = recipes[recipe_name]
88
- raise RecipeNotFound.new(cookbook.root_dir, recipe_name, recipes.keys, cookbook.name) if recipe.nil?
89
- recipe
90
- end
91
- end
92
-
93
- class InvalidCookbook < ChefApply::Error
94
- def initialize(cookbook_path); super("CHEFVAL005", cookbook_path); end
95
- end
96
-
97
- class CookbookNotFound < ChefApply::Error
98
- def initialize(cookbook_name, repo_paths)
99
- repo_paths = repo_paths.join("\n")
100
- super("CHEFVAL006", cookbook_name, repo_paths)
101
- end
102
- end
103
-
104
- class NoDefaultRecipe < ChefApply::Error
105
- def initialize(cookbook_path, cookbook_name); super("CHEFVAL007", cookbook_path, cookbook_name); end
106
- end
107
-
108
- class RecipeNotFound < ChefApply::Error
109
- def initialize(cookbook_path, recipe_name, available_recipes, cookbook_name)
110
- available_recipes.map! { |r| "'#{r}'" }
111
- available_recipes = available_recipes.join(", ")
112
- super("CHEFVAL008", cookbook_path, recipe_name, available_recipes, cookbook_name)
113
- end
114
- end
115
-
116
- end
117
- end
@@ -1,170 +0,0 @@
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
-
23
- module ChefApply
24
- # This class knows how to create a local cookbook in a temp file, populate
25
- # it with various recipes, attributes, config, etc. and delete it when the
26
- # cookbook is no longer necessary
27
- class TempCookbook
28
- attr_reader :path, :descriptor, :from
29
- def initialize
30
- @path = Dir.mktmpdir("cw")
31
- end
32
-
33
- def from_existing_recipe(existing_recipe_path)
34
- ext_name = File.extname(existing_recipe_path)
35
- raise UnsupportedExtension.new(ext_name) unless ext_name == ".rb"
36
- cb = cookbook_for_recipe(existing_recipe_path)
37
- if cb
38
- # Full existing cookbook - only needs policyfile
39
- ChefApply::Log.debug("Found full cookbook at path '#{cb[:path]}' and using recipe '#{cb[:recipe_name]}'")
40
- @descriptor = "#{cb[:name]}::#{cb[:recipe_name]}"
41
- @from = "#{cb[:path]}"
42
- recipe_name = cb[:recipe_name]
43
- cb_name = cb[:name]
44
- FileUtils.cp_r(cb[:path], path)
45
- # cp_r copies the whole existing cookbook into the tempdir so need to reset our path
46
- @path = File.join(path, File.basename(cb[:path]))
47
- else
48
- # Cookbook from single recipe not in a cookbook. We create the full cookbook
49
- # structure including metadata, then generate policyfile. We set the cookbook
50
- # name to the recipe name so hopefully this gives us better reporting info
51
- # in the future
52
- ChefApply::Log.debug("Found single recipe at path '#{existing_recipe_path}'")
53
- recipe = File.basename(existing_recipe_path)
54
- recipe_name = File.basename(recipe, ext_name)
55
- cb_name = "cw_recipe"
56
- @descriptor = "#{recipe_name}"
57
- @from = existing_recipe_path
58
- recipes_dir = generate_recipes_dir
59
- # This has the potential to break if they specify a recipe without a .rb
60
- # extension, but lets wait to deal with that bug until we encounter it
61
- FileUtils.cp(existing_recipe_path, File.join(recipes_dir, recipe))
62
- generate_metadata(cb_name)
63
- end
64
- generate_policyfile(cb_name, recipe_name)
65
- end
66
-
67
- def from_resource(resource_type, resource_name, properties)
68
- # Generate a cookbook containing a single default recipe with the specified
69
- # resource in it. Incloud the resource type in the cookbook name so hopefully
70
- # this gives us better reporting info in the future.
71
- @descriptor = "#{resource_type}[#{resource_name}]"
72
- @from = "resource"
73
-
74
- ChefApply::Log.debug("Generating cookbook for single resource '#{resource_type}[#{resource_name}]'")
75
- name = "cw_#{resource_type}"
76
- recipe_name = "default"
77
- recipes_dir = generate_recipes_dir
78
- File.open(File.join(recipes_dir, "#{recipe_name}.rb"), "w+") do |f|
79
- f.print(create_resource_definition(resource_type, resource_name, properties))
80
- end
81
- generate_metadata(name)
82
- generate_policyfile(name, recipe_name)
83
- end
84
-
85
- def delete
86
- FileUtils.remove_entry path
87
- end
88
-
89
- def cookbook_for_recipe(existing_recipe_path)
90
- metadata = File.expand_path(File.join(existing_recipe_path, "../../metadata.rb"))
91
- if File.file?(metadata)
92
- require "chef/cookbook/metadata"
93
- m = Chef::Cookbook::Metadata.new
94
- m.from_file(metadata)
95
- {
96
- name: m.name,
97
- recipe_name: File.basename(existing_recipe_path, File.extname(existing_recipe_path)),
98
- path: File.expand_path(File.join(metadata, "../")),
99
- }
100
- else
101
- nil
102
- end
103
- end
104
-
105
- def generate_recipes_dir
106
- recipes_path = File.join(path, "recipes")
107
- FileUtils.mkdir_p(recipes_path)
108
- recipes_path
109
- end
110
-
111
- def generate_metadata(name)
112
- metadata_file = File.join(path, "metadata.rb")
113
- File.open(metadata_file, "w+") do |f|
114
- f.print("name \"#{name}\"\n")
115
- end
116
- metadata_file
117
- end
118
-
119
- def generate_policyfile(name, recipe_name)
120
- policy_file = File.join(path, "Policyfile.rb")
121
- if File.exist?(policy_file)
122
- File.open(policy_file, "a") do |f|
123
- # We override the specified run_list with the run_list we want.
124
- # We append and put this at the end of the file so it overrides
125
- # any specified run_list.
126
- f.print("\n# Overriding run_list with command line specified value\n")
127
- f.print("run_list \"#{name}::#{recipe_name}\"\n")
128
- end
129
- else
130
- File.open(policy_file, "w+") do |f|
131
- f.print("name \"#{name}_policy\"\n")
132
- ChefApply::Config.chef.cookbook_repo_paths.each do |p|
133
- f.print("default_source :chef_repo, \"#{p}\"\n")
134
- end
135
- f.print("default_source :supermarket\n")
136
- f.print("run_list \"#{name}::#{recipe_name}\"\n")
137
- f.print("cookbook \"#{name}\", path: \".\"\n")
138
- end
139
- end
140
- policy_file
141
- end
142
-
143
- def create_resource_definition(resource_type, resource_name, properties)
144
- r = "#{resource_type} '#{resource_name}'"
145
- # lets format the properties into the correct syntax Chef expects
146
- unless properties.empty?
147
- r += " do\n"
148
- properties.each do |k, v|
149
- v = "'#{v}'" if v.is_a? String
150
- r += " #{k} #{v}\n"
151
- end
152
- r += "end"
153
- end
154
- r += "\n"
155
- r
156
- end
157
-
158
- def policyfile_lock_path
159
- File.join(path, "Policyfile.lock.json")
160
- end
161
-
162
- def export_path
163
- File.join(path, "export")
164
- end
165
-
166
- class UnsupportedExtension < ChefApply::ErrorNoLogs
167
- def initialize(ext); super("CHEFVAL009", ext); end
168
- end
169
- end
170
- end