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.
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