hybrid_platforms_conductor 32.13.4 → 32.14.0

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/CHANGELOG.md +12 -0
  3. data/bin/get_impacted_nodes +1 -1
  4. data/bin/setup +6 -1
  5. data/docs/plugins.md +1 -0
  6. data/docs/plugins/platform_handler/serverless_chef.md +105 -0
  7. data/lib/hybrid_platforms_conductor/deployer.rb +2 -1
  8. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef.rb +440 -0
  9. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef/dsl_parser.rb +51 -0
  10. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef/recipes_tree_builder.rb +271 -0
  11. data/lib/hybrid_platforms_conductor/nodes_handler.rb +9 -5
  12. data/lib/hybrid_platforms_conductor/version.rb +1 -1
  13. data/spec/hybrid_platforms_conductor_test.rb +3 -0
  14. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +23 -0
  15. data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb +11 -0
  16. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/config_dsl_spec.rb +17 -0
  17. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/deploy_output_parsing_spec.rb +94 -0
  18. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/diff_impacts_spec.rb +317 -0
  19. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/inventory_spec.rb +65 -0
  20. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/packaging_spec.rb +213 -0
  21. data/spec/hybrid_platforms_conductor_test/api/platform_handlers/serverless_chef/services_deployment_spec.rb +268 -0
  22. data/spec/hybrid_platforms_conductor_test/helpers/serverless_chef_helpers.rb +53 -0
  23. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/chef_versions.yml +3 -0
  24. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/nodes/node.json +14 -0
  25. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/1_node/policyfiles/test_policy.rb +3 -0
  26. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/data_bags/chef_versions.yml +3 -0
  27. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/data_bags/data_bags/my_bag/my_item.json +4 -0
  28. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/data_bags/nodes/node.json +14 -0
  29. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/data_bags/policyfiles/test_policy.rb +3 -0
  30. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_1/recipes/default.rb +1 -0
  31. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_2/libraries/default.rb +4 -0
  32. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_2/recipes/default.rb +1 -0
  33. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_2/recipes/other_recipe.rb +1 -0
  34. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/cookbooks/test_cookbook_2/resources/my_resource.rb +1 -0
  35. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/nodes/node1.json +10 -0
  36. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/nodes/node2.json +10 -0
  37. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/policyfiles/test_policy_1.rb +4 -0
  38. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/recipes/policyfiles/test_policy_2.rb +4 -0
  39. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/config.rb +1 -0
  40. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/cookbooks/test_cookbook_1/recipes/default.rb +1 -0
  41. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/nodes/node1.json +10 -0
  42. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/nodes/node2.json +10 -0
  43. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/other_cookbooks/test_cookbook_2/libraries/default.rb +4 -0
  44. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/other_cookbooks/test_cookbook_2/recipes/default.rb +1 -0
  45. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/other_cookbooks/test_cookbook_2/recipes/other_recipe.rb +1 -0
  46. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/other_cookbooks/test_cookbook_2/resources/my_resource.rb +1 -0
  47. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/policyfiles/test_policy_1.rb +4 -0
  48. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_cookbooks/policyfiles/test_policy_2.rb +4 -0
  49. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/chef_versions.yml +3 -0
  50. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/nodes/local.json +10 -0
  51. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/nodes/node1.json +10 -0
  52. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/nodes/node2.json +10 -0
  53. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/policyfiles/test_policy_1.rb +3 -0
  54. data/spec/hybrid_platforms_conductor_test/serverless_chef_repositories/several_nodes/policyfiles/test_policy_2.rb +3 -0
  55. metadata +187 -143
@@ -0,0 +1,51 @@
1
+ module HybridPlatformsConductor
2
+
3
+ module HpcPlugins
4
+
5
+ module PlatformHandler
6
+
7
+ class ServerlessChef < HybridPlatformsConductor::PlatformHandler
8
+
9
+ # Small class that can get a Ruby DSL file and return all DSL calls that have been made to it
10
+ class DslParser
11
+
12
+ # List of calls made by parsing the source file
13
+ # Array
14
+ attr_reader :calls
15
+
16
+ # Constructor
17
+ #
18
+ # Parameters::
19
+ # * *calls* (Array): List of calls to complement [default = []]
20
+ def initialize(calls = [])
21
+ @calls = calls
22
+ end
23
+
24
+ # Parse a file and get all its DSL calls
25
+ #
26
+ # Parameters::
27
+ # * *source* (String): File to parse
28
+ def parse(source)
29
+ instance_eval(File.read(source))
30
+ end
31
+
32
+ def method_missing(method_name, *args, &block)
33
+ sub_calls = []
34
+ @calls << {
35
+ method: method_name,
36
+ args: args,
37
+ block: block,
38
+ calls_on_result: sub_calls
39
+ }
40
+ DslParser.new(sub_calls)
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,271 @@
1
+ require 'hybrid_platforms_conductor/hpc_plugins/platform_handler/serverless_chef/dsl_parser'
2
+
3
+ module HybridPlatformsConductor
4
+
5
+ module HpcPlugins
6
+
7
+ module PlatformHandler
8
+
9
+ class ServerlessChef < HybridPlatformsConductor::PlatformHandler
10
+
11
+ # Build the recipes tree from a ServerlessChef platform
12
+ class RecipesTreeBuilder
13
+
14
+ # Constructor
15
+ #
16
+ # Parameters::
17
+ # * *config* (Config): Configuration that can be used to tune tree building
18
+ # * *platform* (ServerlessChef): Platform for which we build the recipes tree
19
+ def initialize(config, platform)
20
+ @config = config
21
+ @platform = platform
22
+ end
23
+
24
+ # Get the whole tree of recipes
25
+ #
26
+ # Result::
27
+ # * The tree of recipes:
28
+ # Hash< Symbol, Hash< Symbol, Hash<Symbol,Object> >
29
+ # Hash< cookbook, Hash< recipe, recipe_info >
30
+ # Each recipe info has the following attributes:
31
+ # * *included_recipes* (Array< [String or nil, Symbol, Symbol] >): List of [cookbook_dir, cookbook, recipe] included by this recipe
32
+ # * *used_by_policies* (Array<String>): List of policies that include (recursively) this recipe
33
+ # * *used_templates* (Array<String>): List of template sources used by this recipe
34
+ # * *used_files* (Array<String>): List of cookbook files used by this recipe
35
+ # * *used_cookbooks* (Array<Symbol>): List of additional used cookbooks (for example for resources)
36
+ def full_recipes_tree
37
+ @recipes_tree = {}
38
+ @platform.deployable_services.each do |service|
39
+ policy_run_list(service).each do |(cookbook_dir, cookbook, recipe)|
40
+ add_recipe_in_tree(cookbook_dir, cookbook, recipe)
41
+ end
42
+ end
43
+ @platform.deployable_services.each do |service|
44
+ policy_run_list(service).each do |(cookbook_dir, cookbook, recipe)|
45
+ mark_recipe_used_by_policy(cookbook, recipe, service)
46
+ end
47
+ end
48
+ @recipes_tree
49
+ end
50
+
51
+ private
52
+
53
+ # Get the run list of a given policy
54
+ #
55
+ # Parameters::
56
+ # * *policy* (String): Policy to get the run list from
57
+ # Result::
58
+ # * Array<[String or nil, Symbol,Symbol]>: Run list of the given policy, as [cookbook_dir, cookbook, recipe]
59
+ def policy_run_list(policy)
60
+ # Read the policy file
61
+ dsl_parser = DslParser.new
62
+ policy_file = "#{@platform.repository_path}/policyfiles/#{policy}.rb"
63
+ dsl_parser.parse(policy_file)
64
+ run_list_call = dsl_parser.calls.find { |call_info| call_info[:method] == :run_list }
65
+ raise "Policy #{policy} has no run list defined in #{policy_file}" if run_list_call.nil?
66
+ run_list_call[:args].map { |recipe_def| decode_recipe(recipe_def) }
67
+ end
68
+
69
+ # Return the cookbook directory, cookbook name and recipe name from which a recipe definition is found.
70
+ # The following forms are handled:
71
+ # * cookbook
72
+ # * cookbook::recipe
73
+ # * recipe[cookbook]
74
+ # * recipe[cookbook::recipe]
75
+ #
76
+ # Parameters::
77
+ # * *recipe_def* (String): Recipe definition (cookbook or cookbook::recipe).
78
+ # Result::
79
+ # * String: The cookbook directory, or nil if unknown
80
+ # * Symbol: The cookbook name
81
+ # * Symbol: The recipe name
82
+ def decode_recipe(recipe_def)
83
+ recipe_def = $1 if recipe_def =~ /^recipe\[(.+)\]$/
84
+ cookbook, recipe = recipe_def.split('::').map(&:to_sym)
85
+ recipe = :default if recipe.nil?
86
+ # Find the cookbook it belongs to
87
+ cookbook_dir = @platform.known_cookbook_paths.find { |cookbook_path| File.exist?("#{@platform.repository_path}/#{cookbook_path}/#{cookbook}") }
88
+ raise "Unknown recipe #{cookbook}::#{recipe} from cookbook #{@platform.repository_path}/#{cookbook_dir}/#{cookbook}." if !cookbook_dir.nil? && !File.exist?("#{@platform.repository_path}/#{cookbook_dir}/#{cookbook}/recipes/#{recipe}.rb")
89
+ return cookbook_dir, cookbook, recipe
90
+ end
91
+
92
+ # Fill the tree with a recipe and all its dependencies
93
+ #
94
+ # Parameters::
95
+ # * *cookbook_dir* (String): The cookbook directory, or nil if unknown
96
+ # * *cookbook* (Symbol): The cookbook name
97
+ # * *recipe* (Symbol): The recipe name
98
+ def add_recipe_in_tree(cookbook_dir, cookbook, recipe)
99
+ @recipes_tree[cookbook] = {} unless @recipes_tree.key?(cookbook)
100
+ unless @recipes_tree[cookbook].key?(recipe)
101
+ recipe_info =
102
+ if cookbook_dir.nil?
103
+ # This recipe comes from an external cookbook, we won't get into it.
104
+ {
105
+ included_recipes: [],
106
+ used_templates: [],
107
+ used_files: [],
108
+ used_cookbooks: []
109
+ }
110
+ else
111
+ recipe_usage(cookbook_dir, cookbook, recipe)
112
+ end
113
+ @recipes_tree[cookbook][recipe] = recipe_info.merge(
114
+ used_by_policies: []
115
+ )
116
+ recipe_info[:included_recipes].each do |(sub_cookbook_dir, sub_cookbook, sub_recipe)|
117
+ add_recipe_in_tree(sub_cookbook_dir, sub_cookbook, sub_recipe)
118
+ end
119
+ end
120
+ end
121
+
122
+ # Get some info on a given recipe.
123
+ # Parses for:
124
+ # * include_recipe.
125
+ # * source of template and cookbook_file.
126
+ # * Any library helper we know use some recipes.
127
+ # * Any resource we have defined in other cookbooks.
128
+ # * Any library method we have defined in other cookbooks.
129
+ #
130
+ # Parameters::
131
+ # * *cookbook_dir* (String): The cookbook directory
132
+ # * *cookbook* (Symbol): The cookbook name
133
+ # * *recipe* (Symbol): The recipe name
134
+ # Result::
135
+ # * Hash<Symbol,Object>: A structure describing the recipe:
136
+ # * *included_recipes* (Array< [String, Symbol, Symbol] >): List of tuples [cookbook_dir, cookbook, recipe] used by this recipe
137
+ # * *used_templates* (Array<String>): List of template sources used by this recipe
138
+ # * *used_files* (Array<String>): List of cookbook files used by this recipe
139
+ # * *used_cookbooks* (Array<String>): List of additional cookbooks used by this recipe
140
+ def recipe_usage(cookbook_dir, cookbook, recipe)
141
+ recipe_content = File.read("#{@platform.repository_path}/#{cookbook_dir}/#{cookbook}/recipes/#{recipe}.rb")
142
+ # Check for include_recipe
143
+ used_recipes = recipe_content.
144
+ scan(/include_recipe\s+["'](\w+(::\w+)?)["']/).
145
+ map { |(recipe_def, _sub_grp)| decode_recipe(recipe_def) }
146
+ # Check for some helpers we know include some recipes
147
+ @config.known_helpers_including_recipes.each do |helper_name, used_recipes_by_helper|
148
+ if recipe_content =~ Regexp.new(/(\W|^)#{Regexp.escape(helper_name)}(\W|$)/)
149
+ used_recipes.concat(used_recipes_by_helper.map { |recipe_def| decode_recipe(recipe_def) })
150
+ used_recipes.uniq!
151
+ end
152
+ end
153
+ sources = []
154
+ recipe_content.
155
+ scan(/source\s+(["'])(.+?)\1/).
156
+ each do |(_sub_grp, source)|
157
+ sources << source unless source =~ /^https?:\/\//
158
+ end
159
+ erb_sources = sources.select { |source| File.extname(source).downcase == '.erb' }
160
+ non_erb_sources = sources - erb_sources
161
+ erb_sources.concat(recipe_content.scan(/template:?\s+(["'])(.+?)\1/).map { |(_sub_grp, source)| source })
162
+ # Check for known resources and library methods
163
+ used_cookbooks = []
164
+ known_resources.each do |cookbook, methods|
165
+ used_cookbooks << cookbook if methods.any? { |method_name| recipe_content.include?(method_name) }
166
+ end
167
+ known_library_methods.each do |cookbook, methods|
168
+ used_cookbooks << cookbook if methods.any? { |method_name| recipe_content.include?(method_name) }
169
+ end
170
+ {
171
+ included_recipes: used_recipes,
172
+ used_templates: erb_sources,
173
+ used_files: non_erb_sources,
174
+ used_cookbooks: used_cookbooks.uniq
175
+ }
176
+ end
177
+
178
+ # Get the user defined resources, per cookbook.
179
+ # Keep a memory cache of it.
180
+ #
181
+ # Result::
182
+ # * Hash< Symbol, Array<String> >: List of resource names (as useable methods), per cookbook
183
+ def known_resources
184
+ unless defined?(@known_resources)
185
+ @known_resources = {}
186
+ for_each_cookbook do |cookbook, cookbook_dir|
187
+ if File.exist?("#{cookbook_dir}/resources")
188
+ @known_resources[cookbook] = Dir.glob("#{cookbook_dir}/resources/*.rb").map do |resource_file|
189
+ "#{cookbook}_#{File.basename(resource_file, '.rb')}"
190
+ end
191
+ end
192
+ end
193
+ end
194
+ @known_resources
195
+ end
196
+
197
+ # Get the list of library methods we know we have to ignore from the parsing
198
+ # Array<String>
199
+ INVALID_LIBRARY_METHODS = [
200
+ 'initialize'
201
+ ]
202
+
203
+ # Get the user defined library methods, per cookbook.
204
+ # Keep a memory cache of it.
205
+ #
206
+ # Result::
207
+ # * Hash< Symbol, Array<String> >: List of library method names, per cookbook
208
+ def known_library_methods
209
+ unless defined?(@known_library_methods)
210
+ @known_library_methods = {}
211
+ for_each_cookbook do |cookbook, cookbook_dir|
212
+ if File.exist?("#{cookbook_dir}/libraries")
213
+ found_methods = Dir.glob("#{cookbook_dir}/libraries/*.rb").
214
+ map { |lib_file| File.read(lib_file).scan(/\bdef\s+(\w+)\b/).map { |(method_name)| method_name } }.
215
+ flatten - INVALID_LIBRARY_METHODS
216
+ @known_library_methods[cookbook] = found_methods unless found_methods.empty?
217
+ end
218
+ end
219
+ end
220
+ @known_library_methods
221
+ end
222
+
223
+ # Iterate over all cookbooks
224
+ #
225
+ # Parameters::
226
+ # * Proc: Code called for each cookbook:
227
+ # * Parameters::
228
+ # * *cookbook* (Symbol): Cookbook name
229
+ # * *cookbook_dir* (String): Cookbook directory
230
+ def for_each_cookbook
231
+ @platform.known_cookbook_paths.each do |cookbook_path|
232
+ cookbooks_in(cookbook_path).each do |cookbook, cookbook_dir|
233
+ yield cookbook, cookbook_dir
234
+ end
235
+ end
236
+ end
237
+
238
+ # Get the list of cookbooks of a given cookbook type
239
+ #
240
+ # Parameters::
241
+ # * *cookbook_type* (String): The cookbook type (like site-cookbook)
242
+ # Result::
243
+ # * Hash<Symbol, String>: List of cookbook directories, per cookbook name
244
+ def cookbooks_in(cookbook_type)
245
+ Hash[Dir.glob("#{@platform.repository_path}/#{cookbook_type}/*").map { |dir| [File.basename(dir).to_sym, dir] }.sort]
246
+ end
247
+
248
+ # Mark a recipe (and its included recipes) as used by a policy
249
+ #
250
+ # Parameters::
251
+ # * *cookbook* (Symbol): The cookbook
252
+ # * *recipe* (Symbol): The recipe
253
+ # * *used_by_policy* (String): The policy using this recipe
254
+ def mark_recipe_used_by_policy(cookbook, recipe, used_by_policy)
255
+ unless @recipes_tree[cookbook][recipe][:used_by_policies].include?(used_by_policy)
256
+ @recipes_tree[cookbook][recipe][:used_by_policies] << used_by_policy
257
+ @recipes_tree[cookbook][recipe][:included_recipes].each do |(_sub_cookbook_dir, sub_cookbook, sub_recipe)|
258
+ mark_recipe_used_by_policy(sub_cookbook, sub_recipe, used_by_policy)
259
+ end
260
+ end
261
+ end
262
+
263
+ end
264
+
265
+ end
266
+
267
+ end
268
+
269
+ end
270
+
271
+ end
@@ -269,12 +269,16 @@ module HybridPlatformsConductor
269
269
  #
270
270
  # Parameters::
271
271
  # * *node* (String): Node
272
- # * *property* (Symbol): The property name
272
+ # * *property* (Symbol or nil): The property name, or nil for all [default=nil]
273
273
  # Result::
274
- # * Object or nil: The node's metadata value for this property, or nil if none
275
- def metadata_of(node, property)
276
- prefetch_metadata_of([node], property) unless @metadata.key?(node) && @metadata[node].key?(property)
277
- @metadata[node][property]
274
+ # * Object or nil: The node's metadata value for this property, or nil if none, or a Hash of metadata if property was nil
275
+ def metadata_of(node, property = nil)
276
+ if property.nil?
277
+ @metadata[node] || {}
278
+ else
279
+ prefetch_metadata_of([node], property) unless @metadata.key?(node) && @metadata[node].key?(property)
280
+ @metadata[node][property]
281
+ end
278
282
  end
279
283
 
280
284
  # Override a metadata property for a given node
@@ -1,5 +1,5 @@
1
1
  module HybridPlatformsConductor
2
2
 
3
- VERSION = '32.13.4'
3
+ VERSION = '32.14.0'
4
4
 
5
5
  end
@@ -35,6 +35,7 @@ require 'hybrid_platforms_conductor_test/helpers/platforms_handler_helpers'
35
35
  require 'hybrid_platforms_conductor_test/helpers/plugins_helpers'
36
36
  require 'hybrid_platforms_conductor_test/helpers/provisioner_proxmox_helpers'
37
37
  require 'hybrid_platforms_conductor_test/helpers/reports_handler_helpers'
38
+ require 'hybrid_platforms_conductor_test/helpers/serverless_chef_helpers'
38
39
  require 'hybrid_platforms_conductor_test/helpers/services_handler_helpers'
39
40
  require 'hybrid_platforms_conductor_test/helpers/tests_runner_helpers'
40
41
  require 'hybrid_platforms_conductor_test/platform_handler_plugins/test'
@@ -69,6 +70,7 @@ module HybridPlatformsConductorTest
69
70
  include PluginsHelpers
70
71
  include ProvisionerProxmoxHelpers
71
72
  include ReportsHandlerHelpers
73
+ include ServerlessChefHelpers
72
74
  include ServicesHandlerHelpers
73
75
  include TestsRunnerHelpers
74
76
 
@@ -95,6 +97,7 @@ module HybridPlatformsConductorTest
95
97
  ENV.delete 'hpc_domain_for_thycotic'
96
98
  ENV.delete 'hpc_certificates'
97
99
  ENV.delete 'hpc_interactive'
100
+ ENV.delete 'hpc_test_cookbooks_path'
98
101
  # Set the necessary Hybrid Platforms Conductor environment variables
99
102
  ENV['hpc_ssh_user'] = 'test_user'
100
103
  HybridPlatformsConductor::ServicesHandler.packaged_deployments.clear
@@ -84,6 +84,29 @@ describe HybridPlatformsConductor::Deployer do
84
84
  end
85
85
  end
86
86
 
87
+ it 'gives a new test instance ready to be used in place of the node without local node' do
88
+ with_test_platform(
89
+ {
90
+ nodes: {
91
+ 'node1' => { meta: { local_node: true } },
92
+ 'node2' => { meta: { local_node: true } }
93
+ }
94
+ }
95
+ ) do |repository|
96
+ register_plugins(:provisioner, { test_provisioner: HybridPlatformsConductorTest::TestProvisioner })
97
+ File.write("#{test_config.hybrid_platforms_dir}/dummy_secrets.json", '{}')
98
+ HybridPlatformsConductorTest::TestProvisioner.mocked_states = %i[created created running exited]
99
+ HybridPlatformsConductorTest::TestProvisioner.mocked_ip = '172.17.0.1'
100
+ expect(Socket).to receive(:tcp).with('172.17.0.1', 22, { connect_timeout: 1 }) do |&block|
101
+ block.call
102
+ end
103
+ test_deployer.with_test_provisioned_instance(:test_provisioner, 'node1', environment: 'hpc_testing_provisioner') do |sub_test_deployer, test_instance|
104
+ expect(sub_test_deployer.instance_eval { @nodes_handler.get_local_node_of('node1') }).to eq false
105
+ expect(sub_test_deployer.instance_eval { @nodes_handler.get_local_node_of('node2') }).to eq true
106
+ end
107
+ end
108
+ end
109
+
87
110
  it 'gives a new test instance ready to be used in place of the node without sudo specificities' do
88
111
  with_test_platform(
89
112
  {
@@ -38,6 +38,17 @@ describe HybridPlatformsConductor::NodesHandler do
38
38
  end
39
39
  end
40
40
 
41
+ it 'returns nodes currently known metadata using generic method' do
42
+ with_cmdb_test_platform do
43
+ test_nodes_handler.metadata_of('node1', :upcase)
44
+ test_nodes_handler.get_double_of('node1')
45
+ expect(test_nodes_handler.metadata_of('node1')).to eq(
46
+ double: 'node1node1',
47
+ upcase: 'NODE1'
48
+ )
49
+ end
50
+ end
51
+
41
52
  it 'returns nodes metadata using dynamic method several times (as the method is created dynamically)' do
42
53
  with_cmdb_test_platform do
43
54
  3.times { expect(test_nodes_handler.get_upcase_of('node1')).to eq 'NODE1' }
@@ -0,0 +1,17 @@
1
+ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef do
2
+
3
+ context 'checking config DSL' do
4
+
5
+ it 'defines helpers that include recipes' do
6
+ with_repository do |repository|
7
+ with_platforms('helpers_including_recipes(my_helper: [\'cookbook1::recipe1\', \'cookbook2\'])') do
8
+ expect(test_config.known_helpers_including_recipes).to eq(
9
+ my_helper: %w[cookbook1::recipe1 cookbook2]
10
+ )
11
+ end
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,94 @@
1
+ describe HybridPlatformsConductor::HpcPlugins::PlatformHandler::ServerlessChef do
2
+
3
+ context 'checking how deployment output is parsed' do
4
+
5
+ it 'parses a deployment output properly' do
6
+ with_serverless_chef_platforms('empty') do |platform|
7
+ stdout = <<~EOS
8
+ Starting Chef Client, version 14.14.29
9
+ resolving cookbooks for run list: ["policy_xae_websql::xae"]
10
+ Synchronizing Cookbooks:
11
+ - policy_xae_websql (0.1.0)
12
+ - chef-ruby (0.1.2)
13
+ - nginx (10.1.0)
14
+ Installing Cookbook Gems:
15
+ Compiling Cookbooks...
16
+ Recipe: site_debian::default
17
+ * apt_update[apt update] action update
18
+ - force update new lists of packages
19
+ * directory[/etc/apt/apt.conf.d] action create (up to date)
20
+ * file[/etc/apt/apt.conf.d/15update-stamp] action create_if_missing (up to date)
21
+ * execute[apt-get -q update] action run
22
+ - execute ["apt-get", "-q", "update"]
23
+
24
+ Converging 145 resources
25
+ Recipe: policy_xae_websql::api
26
+ * site_artifactory_dpkg_package[xaecalcite] action install
27
+ * remote_file[/opt/chef_cache/xaecalcite_0.2.4-1_amd64.deb] action create
28
+ - create new file /opt/chef_cache/xaecalcite_0.2.4-1_amd64.deb
29
+ - update content in file /opt/chef_cache/xaecalcite_0.2.4-1_amd64.deb from none to 39b0ca
30
+ (file sizes exceed 10000000 bytes, diff output suppressed)
31
+ * dpkg_package[xaecalcite] action install
32
+ - install version 0.2.4-1 of package xaecalcite
33
+
34
+ * service[/var/lib/xaecalcite/xaecalcite.service] action enable (skipped due to not_if)
35
+
36
+ Running handlers:
37
+ Running handlers complete
38
+ Chef Client finished, 16/300 resources updated in 27 seconds
39
+ EOS
40
+ expect(platform.parse_deploy_output(stdout, '')). to eq [
41
+ {
42
+ action: 'update',
43
+ diffs: "force update new lists of packages\n",
44
+ name: 'apt_update[apt update]',
45
+ status: :changed
46
+ },
47
+ {
48
+ action: 'create (up to date)',
49
+ name: 'directory[/etc/apt/apt.conf.d]',
50
+ status: :identical
51
+ },
52
+ {
53
+ action: 'create_if_missing (up to date)',
54
+ name: 'file[/etc/apt/apt.conf.d/15update-stamp]',
55
+ status: :identical
56
+ },
57
+ {
58
+ action: 'run',
59
+ diffs: "execute [\"apt-get\", \"-q\", \"update\"]\n",
60
+ name: 'execute[apt-get -q update]',
61
+ status: :changed
62
+ },
63
+ {
64
+ action: 'install',
65
+ name: 'site_artifactory_dpkg_package[xaecalcite]',
66
+ status: :identical
67
+ },
68
+ {
69
+ action: 'create',
70
+ diffs: <<~EOS,
71
+ create new file /opt/chef_cache/xaecalcite_0.2.4-1_amd64.deb
72
+ update content in file /opt/chef_cache/xaecalcite_0.2.4-1_amd64.deb from none to 39b0ca
73
+ EOS
74
+ name: 'remote_file[/opt/chef_cache/xaecalcite_0.2.4-1_amd64.deb]',
75
+ status: :changed
76
+ },
77
+ {
78
+ action: 'install',
79
+ diffs: "install version 0.2.4-1 of package xaecalcite\n",
80
+ name: 'dpkg_package[xaecalcite]',
81
+ status: :changed
82
+ },
83
+ {
84
+ action: 'enable (skipped due to not_if)',
85
+ name: 'service[/var/lib/xaecalcite/xaecalcite.service]',
86
+ status: :identical
87
+ }
88
+ ]
89
+ end
90
+ end
91
+
92
+ end
93
+
94
+ end