kafo 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 13fc7c4d5d0d30aa719d2af9047ed92bf5a6c93c
4
- data.tar.gz: cc7e5c57c7e3f5e888c8db5e963d43bdb505dc01
3
+ metadata.gz: 873ad76a8a766b68a73ad74b34ae17b2d9c48272
4
+ data.tar.gz: 72adff8cb4533c7292a286c0706a87fe574797cb
5
5
  SHA512:
6
- metadata.gz: 0065c3f73debd2dc8056185c91bc5a48c822b5baaa31e47f84d9758e59ceca260c735953060bc5628188ecb14d9ece380709c695483faaa32954e21cc45eef6d
7
- data.tar.gz: c58bf1204a85e7bd5c9273baec1a93e5f6f5a8ced3bbc2bfc027f54840d42930cb891720a9e182fd5e57a17c0020f1f10d471893f27d3b8af54c645147bfc2c9
6
+ metadata.gz: 293954125bbd2feb79cb7ba396459d8fb32e9ef9e61d1d38027d4ff2c79980c5c7a8f339d424347c84c06b63ecb6f64d6b88cff5b7465a5a58ae8853b45cb0b3
7
+ data.tar.gz: a5763aeefec19555ef5c1315f5bc7961f06cd49cb0f0b672a64fc878310b5f0290e123c130f318abba0b841427cc32c5d3c9fd000a259836a9a3f16e3e1d1c55
data/README.md CHANGED
@@ -158,6 +158,14 @@ As you may have noticed there are several ways how to specify arguments. Here's
158
158
  * values specified on CLI
159
159
  * interactive mode arguments
160
160
 
161
+ ## Requirements
162
+
163
+ Kafo is supported with Puppet versions 3 and 4. Puppet 2 is no longer supported
164
+ in current versions, use an older version of Kafo or update Puppet.
165
+
166
+ Puppet may be installed as a gem (add it to Gemfile) or through a package,
167
+ including official AIO packages.
168
+
161
169
  ## How do I report bugs or contribute?
162
170
 
163
171
  You can find our redmine issue tracker [here](http://projects.theforeman.org/projects/kafo),
@@ -971,6 +979,36 @@ configure it in config/kafo.yaml with:
971
979
  The cache will be skipped if the file modification time of the manifest is
972
980
  greater than the mtime recorded in the cache.
973
981
 
982
+ ## Configuring Hiera
983
+
984
+ Kafo uses Hiera to include classes and pass parameters to classes using data
985
+ binding, but this can be extended so parameters can be set for classes not
986
+ being managed by Kafo. Set a custom Hiera config file in Kafo's config with:
987
+
988
+ ```yaml
989
+ :hiera_config: /usr/share/kafo/hiera.yaml
990
+ ```
991
+
992
+ The contents of this file are as per the [hiera.yaml docs](https://docs.puppet.com/hiera/latest/configuring.html),
993
+ but hierarchy should contain the item `kafo_answers` and the `yaml` backend
994
+ should be enabled. Kafo will add these if they're missing.
995
+
996
+ When running Puppet, Kafo will copy the Hiera config and YAML data directory to
997
+ a temporary location to include its data. The file `kafo_answers.yaml` will be
998
+ generated containing _all_ default and overriden values for parameters managed
999
+ by Kafo. This may change in the future to allow a more complex hierarchy. As an
1000
+ example, a hierarchy could be set up with:
1001
+
1002
+ ```yaml
1003
+ :hierarchy:
1004
+ - kafo_answers
1005
+ - "%{::osfamily}"
1006
+ - common
1007
+ ```
1008
+
1009
+ This would give precedence to all Kafo-managed parameter values, but for any
1010
+ others, would check for values per OS family, followed by a `common.yaml` file.
1011
+
974
1012
  ## Exit code
975
1013
 
976
1014
  Kafo can terminate either before or after puppet is run. If it is run with
@@ -42,6 +42,7 @@
42
42
  # :log_group: root
43
43
  # :config_header_file:
44
44
  # :dont_save_answers:
45
+ # :hiera_config: /usr/share/kafo/hiera.yaml
45
46
 
46
47
  ## Hooks - hooks in these extra directories will be loaded,
47
48
  # by default they are loaded from $installer_dir/hooks/$type
@@ -225,10 +225,6 @@ module Kafo
225
225
  end
226
226
  end
227
227
 
228
- def temp_config_file
229
- @temp_config_file ||= "/tmp/kafo_answers_#{rand(1_000_000)}.yaml"
230
- end
231
-
232
228
  def log_file
233
229
  File.join(app[:log_dir], app[:log_name])
234
230
  end
@@ -251,6 +247,7 @@ module Kafo
251
247
  migrations.store_applied
252
248
  @logger.info("#{migrations.migrations.count} migration/s were applied. Updated configuration was saved.")
253
249
  end
250
+ migrations.migrations.count
254
251
  end
255
252
 
256
253
  def migrations_dir
@@ -0,0 +1,83 @@
1
+ require 'fileutils'
2
+ require 'tmpdir'
3
+
4
+ module Kafo
5
+ class HieraConfigurer
6
+ attr_reader :temp_dir, :config_path, :data_dir, :logger
7
+
8
+ def initialize(user_config_path, modules, modules_order)
9
+ @user_config_path = user_config_path
10
+ @modules = modules
11
+ @modules_order = modules_order
12
+ @logger = KafoConfigure.logger
13
+ end
14
+
15
+ def write_configs
16
+ @temp_dir = Dir.mktmpdir('kafo_hiera')
17
+ @config_path = File.join(temp_dir, 'hiera.conf')
18
+ @data_dir = File.join(temp_dir, 'data')
19
+
20
+ if @user_config_path
21
+ logger.debug("Merging existing Hiera config file from #{@user_config_path}")
22
+ user_config = YAML.load(File.read(@user_config_path))
23
+ user_data_dir = user_config[:yaml][:datadir] if user_config[:yaml]
24
+ else
25
+ user_config = {}
26
+ user_data_dir = false
27
+ end
28
+ logger.debug("Writing Hiera config file to #{config_path}")
29
+ File.open(config_path, 'w') do |f|
30
+ # merge required config changes into the user's Hiera config
31
+ f.write(format_yaml_symbols(generate_config(user_config).to_yaml))
32
+ end
33
+
34
+ if user_data_dir
35
+ logger.debug("Copying Hiera data files from #{user_data_dir} to #{data_dir}")
36
+ FileUtils.cp_r(user_data_dir, data_dir)
37
+ else
38
+ logger.debug("Creating Hiera data files in #{data_dir}")
39
+ FileUtils.mkdir(data_dir)
40
+ end
41
+
42
+ File.open(File.join(data_dir, 'kafo_answers.yaml'), 'w') do |f|
43
+ f.write(format_yaml_symbols(generate_data(@modules).to_yaml))
44
+ end
45
+ end
46
+
47
+ def generate_config(config = {})
48
+ config ||= {}
49
+
50
+ # ensure YAML is enabled
51
+ config[:backends] ||= []
52
+ config[:backends] << 'yaml' unless config[:backends].include?('yaml')
53
+
54
+ # ensure kafo_answers is present and most specific
55
+ config[:hierarchy] ||= []
56
+ config[:hierarchy].unshift('kafo_answers') unless config[:hierarchy].include?('kafo_answers')
57
+
58
+ # use our copy of the data dir
59
+ config[:yaml] ||= {}
60
+ config[:yaml][:datadir] = data_dir
61
+
62
+ config
63
+ end
64
+
65
+ def generate_data(modules)
66
+ classes = []
67
+ data = modules.select(&:enabled?).inject({}) do |config, mod|
68
+ classes << mod.class_name
69
+ config.update(Hash[mod.params_hash.map { |k, v| ["#{mod.class_name}::#{k}", v] }])
70
+ end
71
+ data['classes'] = @modules_order ? sort_modules(classes, @modules_order) : classes
72
+ data
73
+ end
74
+
75
+ def sort_modules(modules, order)
76
+ (order & modules) + (modules - order)
77
+ end
78
+
79
+ def format_yaml_symbols(data)
80
+ data.gsub('!ruby/sym ', ':')
81
+ end
82
+ end
83
+ end
@@ -24,13 +24,14 @@ require 'kafo/progress_bar'
24
24
  require 'kafo/hooking'
25
25
  require 'kafo/exit_handler'
26
26
  require 'kafo/scenario_manager'
27
+ require 'kafo/hiera_configurer'
27
28
 
28
29
  module Kafo
29
30
  class KafoConfigure < Clamp::Command
30
31
  include StringHelper
31
32
 
32
33
  class << self
33
- attr_accessor :config, :root_dir, :config_file, :gem_root, :temp_config_file,
34
+ attr_accessor :config, :root_dir, :config_file, :gem_root,
34
35
  :module_dirs, :kafo_modules_dir, :verbose, :app_options, :logger,
35
36
  :check_dirs, :exit_handler, :scenario_manager
36
37
  attr_writer :hooking
@@ -57,9 +58,9 @@ module Kafo
57
58
  setup_config(config_file)
58
59
 
59
60
  self.class.hooking.execute(:pre_migrations)
60
-
61
- # run migrations
62
- self.class.config.run_migrations
61
+ reload_config
62
+ applied_total = self.class.config.run_migrations
63
+ @config_reload_requested = true if applied_total > 0
63
64
 
64
65
  if ARGV.include?('--migrations-only')
65
66
  self.class.verbose = (ARGV.include?('--verbose') || ARGV.include?('-v'))
@@ -68,13 +69,7 @@ module Kafo
68
69
  self.class.exit(0)
69
70
  end
70
71
 
71
- # reload config
72
- if @config_reload_requested
73
- scenario_manager = setup_scenario_manager
74
- self.class.scenario_manager = scenario_manager
75
- setup_config(self.class.config_file)
76
- self.class.logger.info('Installer configuration was reloaded')
77
- end
72
+ reload_config
78
73
 
79
74
  if scenario_manager.configured?
80
75
  scenario_manager.check_scenario_change(self.class.config_file)
@@ -139,10 +134,7 @@ module Kafo
139
134
  end
140
135
 
141
136
  self.class.hooking.execute(:pre_commit)
142
- if dont_save_answers? || noop?
143
- self.class.temp_config_file = self.class.config.temp_config_file
144
- store_params(self.class.config.temp_config_file)
145
- else
137
+ unless dont_save_answers? || noop?
146
138
  store_params
147
139
  self.class.scenario_manager.link_last_scenario(self.class.config_file) if self.class.scenario_manager.configured?
148
140
  end
@@ -241,6 +233,16 @@ module Kafo
241
233
  self.class.hooking.kafo = self
242
234
  end
243
235
 
236
+ def reload_config
237
+ if @config_reload_requested
238
+ scenario_manager = setup_scenario_manager
239
+ self.class.scenario_manager = scenario_manager
240
+ setup_config(self.class.config_file)
241
+ self.class.logger.info('Installer configuration was reloaded')
242
+ @config_reload_requestd = false
243
+ end
244
+ end
245
+
244
246
  def setup_scenario_manager
245
247
  ScenarioManager.new((defined?(CONFIG_DIR) && CONFIG_DIR) || (defined?(CONFIG_FILE) && CONFIG_FILE))
246
248
  end
@@ -376,6 +378,11 @@ module Kafo
376
378
 
377
379
  def run_installation
378
380
  self.class.hooking.execute(:pre)
381
+
382
+ hiera = HieraConfigurer.new(config.app[:hiera_config], config.modules, config.app[:order])
383
+ hiera.write_configs
384
+ self.class.exit_handler.register_cleanup_path(hiera.temp_dir)
385
+
379
386
  exit_code = 0
380
387
  exit_status = nil
381
388
  options = [
@@ -386,6 +393,7 @@ module Kafo
386
393
  '--show_diff',
387
394
  '--detailed-exitcodes',
388
395
  '--reports=',
396
+ "--hiera_config=#{hiera.config_path}",
389
397
  ]
390
398
  options.push '--noop' if noop?
391
399
  options.push '--profile' if profile?
@@ -413,7 +421,6 @@ module Kafo
413
421
  end
414
422
  @progress_bar.close if @progress_bar
415
423
  logger.info "Puppet has finished, bye!"
416
- FileUtils.rm(self.class.config.temp_config_file, :force => true)
417
424
  self.class.exit(exit_code) do
418
425
  self.class.hooking.execute(:post)
419
426
  end
@@ -12,17 +12,13 @@ module Kafo
12
12
  @logger = KafoConfigure.logger
13
13
  end
14
14
 
15
- def custom_answer_file
16
- KafoConfigure.temp_config_file.nil? ? '' : "$kafo_answer_file=\"#{KafoConfigure.temp_config_file}\""
17
- end
18
-
19
15
  def add_progress
20
16
  KafoConfigure.verbose ? '' : "$kafo_add_progress=true"
21
17
  end
22
18
 
23
19
  def command
24
20
  result = [
25
- "echo '$kafo_config_file=\"#{@configuration.config_file}\" #{custom_answer_file} #{add_progress} #{@command}'",
21
+ "echo '$kafo_config_file=\"#{@configuration.config_file}\" #{add_progress} #{@command}'",
26
22
  '|',
27
23
  "RUBYLIB=#{[@configuration.kafo_modules_dir, ::ENV['RUBYLIB']].join(File::PATH_SEPARATOR)}",
28
24
  "#{puppet_path} apply #{@options.join(' ')} #{@suffix}",
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module Kafo
3
- VERSION = "0.8.2"
3
+ VERSION = "0.9.0"
4
4
  end
@@ -11,8 +11,5 @@ class kafo_configure {
11
11
  }
12
12
 
13
13
  $password = load_kafo_password()
14
- $params = loadanyyaml(load_kafo_answer_file())
15
- $keys = kafo_ordered(hash_keys($params))
16
-
17
- kafo_configure::yaml_to_class { $keys: }
14
+ hiera_include('classes')
18
15
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kafo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marek Hulan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-03 00:00:00.000000000 Z
11
+ date: 2016-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -226,6 +226,7 @@ files:
226
226
  - lib/kafo/help_builders/advanced.rb
227
227
  - lib/kafo/help_builders/base.rb
228
228
  - lib/kafo/help_builders/basic.rb
229
+ - lib/kafo/hiera_configurer.rb
229
230
  - lib/kafo/hook_context.rb
230
231
  - lib/kafo/hooking.rb
231
232
  - lib/kafo/kafo_configure.rb
@@ -255,28 +256,12 @@ files:
255
256
  - lib/kafo/validator.rb
256
257
  - lib/kafo/version.rb
257
258
  - lib/kafo/wizard.rb
258
- - modules/create_resources/Gemfile
259
- - modules/create_resources/LICENSE
260
- - modules/create_resources/Modulefile
261
- - modules/create_resources/README.md
262
- - modules/create_resources/Rakefile
263
- - modules/create_resources/lib/puppet/parser/functions/create_resources.rb
264
- - modules/create_resources/spec/spec_helper.rb
265
- - modules/create_resources/spec/unit/puppet/parser/functions/create_resources_spec.rb
266
- - modules/create_resources/tests/users.pp
267
259
  - modules/kafo_configure/lib/kafo/puppet/report_wrapper.rb
268
260
  - modules/kafo_configure/lib/puppet/parser/functions/add_progress.rb
269
- - modules/kafo_configure/lib/puppet/parser/functions/class_name.rb
270
261
  - modules/kafo_configure/lib/puppet/parser/functions/decrypt.rb
271
262
  - modules/kafo_configure/lib/puppet/parser/functions/dump_values.rb
272
- - modules/kafo_configure/lib/puppet/parser/functions/hash_keys.rb
273
- - modules/kafo_configure/lib/puppet/parser/functions/is_hash.rb
274
- - modules/kafo_configure/lib/puppet/parser/functions/kafo_ordered.rb
275
- - modules/kafo_configure/lib/puppet/parser/functions/load_kafo_answer_file.rb
276
263
  - modules/kafo_configure/lib/puppet/parser/functions/load_kafo_password.rb
277
- - modules/kafo_configure/lib/puppet/parser/functions/loadanyyaml.rb
278
264
  - modules/kafo_configure/manifests/init.pp
279
- - modules/kafo_configure/manifests/yaml_to_class.pp
280
265
  homepage: https://github.com/theforeman/kafo
281
266
  licenses:
282
267
  - GPLv3+
@@ -1,11 +0,0 @@
1
- source :rubygems
2
-
3
- group :development, :test do
4
- gem 'puppetlabs_spec_helper', :require => false
5
- end
6
-
7
- if puppetversion = ENV['PUPPET_GEM_VERSION']
8
- gem 'puppet', puppetversion, :require => false
9
- else
10
- gem 'puppet', :require => false
11
- end
@@ -1,202 +0,0 @@
1
- Apache License
2
- Version 2.0, January 2004
3
- http://www.apache.org/licenses/
4
-
5
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
-
7
- 1. Definitions.
8
-
9
- "License" shall mean the terms and conditions for use, reproduction,
10
- and distribution as defined by Sections 1 through 9 of this document.
11
-
12
- "Licensor" shall mean the copyright owner or entity authorized by
13
- the copyright owner that is granting the License.
14
-
15
- "Legal Entity" shall mean the union of the acting entity and all
16
- other entities that control, are controlled by, or are under common
17
- control with that entity. For the purposes of this definition,
18
- "control" means (i) the power, direct or indirect, to cause the
19
- direction or management of such entity, whether by contract or
20
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
- outstanding shares, or (iii) beneficial ownership of such entity.
22
-
23
- "You" (or "Your") shall mean an individual or Legal Entity
24
- exercising permissions granted by this License.
25
-
26
- "Source" form shall mean the preferred form for making modifications,
27
- including but not limited to software source code, documentation
28
- source, and configuration files.
29
-
30
- "Object" form shall mean any form resulting from mechanical
31
- transformation or translation of a Source form, including but
32
- not limited to compiled object code, generated documentation,
33
- and conversions to other media types.
34
-
35
- "Work" shall mean the work of authorship, whether in Source or
36
- Object form, made available under the License, as indicated by a
37
- copyright notice that is included in or attached to the work
38
- (an example is provided in the Appendix below).
39
-
40
- "Derivative Works" shall mean any work, whether in Source or Object
41
- form, that is based on (or derived from) the Work and for which the
42
- editorial revisions, annotations, elaborations, or other modifications
43
- represent, as a whole, an original work of authorship. For the purposes
44
- of this License, Derivative Works shall not include works that remain
45
- separable from, or merely link (or bind by name) to the interfaces of,
46
- the Work and Derivative Works thereof.
47
-
48
- "Contribution" shall mean any work of authorship, including
49
- the original version of the Work and any modifications or additions
50
- to that Work or Derivative Works thereof, that is intentionally
51
- submitted to Licensor for inclusion in the Work by the copyright owner
52
- or by an individual or Legal Entity authorized to submit on behalf of
53
- the copyright owner. For the purposes of this definition, "submitted"
54
- means any form of electronic, verbal, or written communication sent
55
- to the Licensor or its representatives, including but not limited to
56
- communication on electronic mailing lists, source code control systems,
57
- and issue tracking systems that are managed by, or on behalf of, the
58
- Licensor for the purpose of discussing and improving the Work, but
59
- excluding communication that is conspicuously marked or otherwise
60
- designated in writing by the copyright owner as "Not a Contribution."
61
-
62
- "Contributor" shall mean Licensor and any individual or Legal Entity
63
- on behalf of whom a Contribution has been received by Licensor and
64
- subsequently incorporated within the Work.
65
-
66
- 2. Grant of Copyright License. Subject to the terms and conditions of
67
- this License, each Contributor hereby grants to You a perpetual,
68
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
- copyright license to reproduce, prepare Derivative Works of,
70
- publicly display, publicly perform, sublicense, and distribute the
71
- Work and such Derivative Works in Source or Object form.
72
-
73
- 3. Grant of Patent License. Subject to the terms and conditions of
74
- this License, each Contributor hereby grants to You a perpetual,
75
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
- (except as stated in this section) patent license to make, have made,
77
- use, offer to sell, sell, import, and otherwise transfer the Work,
78
- where such license applies only to those patent claims licensable
79
- by such Contributor that are necessarily infringed by their
80
- Contribution(s) alone or by combination of their Contribution(s)
81
- with the Work to which such Contribution(s) was submitted. If You
82
- institute patent litigation against any entity (including a
83
- cross-claim or counterclaim in a lawsuit) alleging that the Work
84
- or a Contribution incorporated within the Work constitutes direct
85
- or contributory patent infringement, then any patent licenses
86
- granted to You under this License for that Work shall terminate
87
- as of the date such litigation is filed.
88
-
89
- 4. Redistribution. You may reproduce and distribute copies of the
90
- Work or Derivative Works thereof in any medium, with or without
91
- modifications, and in Source or Object form, provided that You
92
- meet the following conditions:
93
-
94
- (a) You must give any other recipients of the Work or
95
- Derivative Works a copy of this License; and
96
-
97
- (b) You must cause any modified files to carry prominent notices
98
- stating that You changed the files; and
99
-
100
- (c) You must retain, in the Source form of any Derivative Works
101
- that You distribute, all copyright, patent, trademark, and
102
- attribution notices from the Source form of the Work,
103
- excluding those notices that do not pertain to any part of
104
- the Derivative Works; and
105
-
106
- (d) If the Work includes a "NOTICE" text file as part of its
107
- distribution, then any Derivative Works that You distribute must
108
- include a readable copy of the attribution notices contained
109
- within such NOTICE file, excluding those notices that do not
110
- pertain to any part of the Derivative Works, in at least one
111
- of the following places: within a NOTICE text file distributed
112
- as part of the Derivative Works; within the Source form or
113
- documentation, if provided along with the Derivative Works; or,
114
- within a display generated by the Derivative Works, if and
115
- wherever such third-party notices normally appear. The contents
116
- of the NOTICE file are for informational purposes only and
117
- do not modify the License. You may add Your own attribution
118
- notices within Derivative Works that You distribute, alongside
119
- or as an addendum to the NOTICE text from the Work, provided
120
- that such additional attribution notices cannot be construed
121
- as modifying the License.
122
-
123
- You may add Your own copyright statement to Your modifications and
124
- may provide additional or different license terms and conditions
125
- for use, reproduction, or distribution of Your modifications, or
126
- for any such Derivative Works as a whole, provided Your use,
127
- reproduction, and distribution of the Work otherwise complies with
128
- the conditions stated in this License.
129
-
130
- 5. Submission of Contributions. Unless You explicitly state otherwise,
131
- any Contribution intentionally submitted for inclusion in the Work
132
- by You to the Licensor shall be under the terms and conditions of
133
- this License, without any additional terms or conditions.
134
- Notwithstanding the above, nothing herein shall supersede or modify
135
- the terms of any separate license agreement you may have executed
136
- with Licensor regarding such Contributions.
137
-
138
- 6. Trademarks. This License does not grant permission to use the trade
139
- names, trademarks, service marks, or product names of the Licensor,
140
- except as required for reasonable and customary use in describing the
141
- origin of the Work and reproducing the content of the NOTICE file.
142
-
143
- 7. Disclaimer of Warranty. Unless required by applicable law or
144
- agreed to in writing, Licensor provides the Work (and each
145
- Contributor provides its Contributions) on an "AS IS" BASIS,
146
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
- implied, including, without limitation, any warranties or conditions
148
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
- PARTICULAR PURPOSE. You are solely responsible for determining the
150
- appropriateness of using or redistributing the Work and assume any
151
- risks associated with Your exercise of permissions under this License.
152
-
153
- 8. Limitation of Liability. In no event and under no legal theory,
154
- whether in tort (including negligence), contract, or otherwise,
155
- unless required by applicable law (such as deliberate and grossly
156
- negligent acts) or agreed to in writing, shall any Contributor be
157
- liable to You for damages, including any direct, indirect, special,
158
- incidental, or consequential damages of any character arising as a
159
- result of this License or out of the use or inability to use the
160
- Work (including but not limited to damages for loss of goodwill,
161
- work stoppage, computer failure or malfunction, or any and all
162
- other commercial damages or losses), even if such Contributor
163
- has been advised of the possibility of such damages.
164
-
165
- 9. Accepting Warranty or Additional Liability. While redistributing
166
- the Work or Derivative Works thereof, You may choose to offer,
167
- and charge a fee for, acceptance of support, warranty, indemnity,
168
- or other liability obligations and/or rights consistent with this
169
- License. However, in accepting such obligations, You may act only
170
- on Your own behalf and on Your sole responsibility, not on behalf
171
- of any other Contributor, and only if You agree to indemnify,
172
- defend, and hold each Contributor harmless for any liability
173
- incurred by, or claims asserted against, such Contributor by reason
174
- of your accepting any such warranty or additional liability.
175
-
176
- END OF TERMS AND CONDITIONS
177
-
178
- APPENDIX: How to apply the Apache License to your work.
179
-
180
- To apply the Apache License to your work, attach the following
181
- boilerplate notice, with the fields enclosed by brackets "[]"
182
- replaced with your own identifying information. (Don't include
183
- the brackets!) The text should be enclosed in the appropriate
184
- comment syntax for the file format. We also recommend that a
185
- file or class name and description of purpose be included on the
186
- same "printed page" as the copyright notice for easier
187
- identification within third-party archives.
188
-
189
- Copyright [yyyy] [name of copyright owner]
190
-
191
- Licensed under the Apache License, Version 2.0 (the "License");
192
- you may not use this file except in compliance with the License.
193
- You may obtain a copy of the License at
194
-
195
- http://www.apache.org/licenses/LICENSE-2.0
196
-
197
- Unless required by applicable law or agreed to in writing, software
198
- distributed under the License is distributed on an "AS IS" BASIS,
199
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
- See the License for the specific language governing permissions and
201
- limitations under the License.
202
-
@@ -1,11 +0,0 @@
1
- name 'puppetlabs-create_resources'
2
- version '0.0.1'
3
- source 'git://github.com/puppetlabs/puppetlabs-create_resources.git'
4
- author 'puppetlabs'
5
- license 'Apache Version 2.0'
6
- summary 'Function to dynamically create resources from hashes'
7
- description 'Function to dynamically create resources from hashes'
8
- project_page 'https://github.com/puppetlabs/puppetlabs-create_resources'
9
-
10
- ## Add dependencies, if any:
11
- # dependency 'username/name', '>= 1.2.0'
@@ -1,37 +0,0 @@
1
- build status of unit tests:
2
-
3
- [![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-create_resources.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-create_resources)
4
-
5
-
6
- - License - Apache Version 2.0
7
- - Copyright - Puppetlabs 2011
8
-
9
- *NOTE* - this has exists in 2.7.x core, it has been published seperately
10
- so that it can be used with 2.6.x
11
-
12
- This module contains a custom function for puppet that can be used to dynamically add resources to the catalog.
13
-
14
- I wrote this to use with an external node classifier that consumes YAML.
15
-
16
- The yaml specifies classes and passes hashes to those classes as parameters
17
-
18
- classes:
19
- webserver::instances:
20
- instances:
21
- instance1:
22
- foo: bar
23
- instance2:
24
- foo: blah
25
-
26
- Then puppet code can consume the hash parameters and convert then into resources
27
-
28
- class webserver::instances (
29
- $instances = {}
30
- ) {
31
- create_resources('webserver::instance', $instances)
32
- }
33
-
34
- Now I can dynamically determine how webserver instances are deployed to nodes
35
- by updating the YAML files.
36
-
37
-
@@ -1 +0,0 @@
1
- require 'puppetlabs_spec_helper/rake_tasks'
@@ -1,75 +0,0 @@
1
- Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC') do |args|
2
- Converts a hash into a set of resources and adds them to the catalog.
3
-
4
- This function takes two mandatory arguments: a resource type, and a hash describing
5
- a set of resources. The hash should be in the form `{title => {parameters} }`:
6
-
7
- # A hash of user resources:
8
- $myusers = {
9
- 'nick' => { uid => '1330',
10
- group => allstaff,
11
- groups => ['developers', 'operations', 'release'], }
12
- 'dan' => { uid => '1308',
13
- group => allstaff,
14
- groups => ['developers', 'prosvc', 'release'], }
15
- }
16
-
17
- create_resources(user, $myusers)
18
-
19
- A third, optional parameter may be given, also as a hash:
20
-
21
- $defaults = {
22
- 'ensure' => present,
23
- 'provider' => 'ldap',
24
- }
25
-
26
- create_resources(user, $myusers, $defaults)
27
-
28
- The values given on the third argument are added to the parameters of each resource
29
- present in the set given on the second argument. If a parameter is present on both
30
- the second and third arguments, the one on the second argument takes precedence.
31
-
32
- This function can be used to create defined resources and classes, as well
33
- as native resources.
34
- ENDHEREDOC
35
- raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2 or 3)") if args.length < 2 || args.length > 3
36
-
37
- # figure out what kind of resource we are
38
- type_of_resource = nil
39
- type_name = args[0].downcase
40
- if type_name == 'class'
41
- type_of_resource = :class
42
- else
43
- if resource = Puppet::Type.type(type_name.to_sym)
44
- type_of_resource = :type
45
- elsif resource = find_definition(type_name.downcase)
46
- type_of_resource = :define
47
- else
48
- raise ArgumentError, "could not create resource of unknown type #{type_name}"
49
- end
50
- end
51
- # iterate through the resources to create
52
- defaults = args[2] || {}
53
- args[1].each do |title, params|
54
- params = Puppet::Util.symbolizehash(defaults.merge(params))
55
- raise ArgumentError, 'params should not contain title' if(params[:title])
56
- case type_of_resource
57
- # JJM The only difference between a type and a define is the call to instantiate_resource
58
- # for a defined type.
59
- when :type, :define
60
- p_resource = Puppet::Parser::Resource.new(type_name, title, :scope => self, :source => resource)
61
- {:name => title}.merge(params).each do |k,v|
62
- p_resource.set_parameter(k,v)
63
- end
64
- if type_of_resource == :define then
65
- resource.instantiate_resource(self, p_resource)
66
- end
67
- compiler.add_resource(self, p_resource)
68
- when :class
69
- klass = find_hostclass(title)
70
- raise ArgumentError, "could not find hostclass #{title}" unless klass
71
- klass.ensure_in_catalog(self, params)
72
- compiler.catalog.add_class(title)
73
- end
74
- end
75
- end
@@ -1 +0,0 @@
1
- require 'puppetlabs_spec_helper/module_spec_helper'
@@ -1,116 +0,0 @@
1
- require 'puppet'
2
- require 'spec_helper'
3
-
4
- describe 'function for dynamically creating resources' do
5
-
6
- def setup_scope
7
- @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
8
- if Puppet.version =~ /^3\./
9
- @scope = Puppet::Parser::Scope.new(@compiler)
10
- else
11
- @scope = Puppet::Parser::Scope.new(:compiler => @compiler)
12
- end
13
- @topscope = @topscope
14
- @scope.parent = @topscope
15
- Puppet::Parser::Functions.function(:create_resources)
16
- end
17
-
18
- describe 'basic tests' do
19
-
20
- before :each do
21
- setup_scope
22
- end
23
-
24
- it "should exist" do
25
- Puppet::Parser::Functions.function(:create_resources).should == "function_create_resources"
26
- end
27
- it 'should require two arguments' do
28
- lambda { @scope.function_create_resources(['foo']) }.should raise_error(ArgumentError, 'create_resources(): wrong number of arguments (1; must be 2 or 3)')
29
- end
30
- end
31
-
32
- describe 'when creating native types' do
33
- before :each do
34
- Puppet[:code]=
35
- '
36
- class t {}
37
- notify{test:}
38
- '
39
- setup_scope
40
- end
41
- it 'empty hash should not cause resources to be added' do
42
-
43
- @scope.function_create_resources(['file', {}])
44
- @compiler.catalog.resources.size == 1
45
- end
46
- it 'should be able to add' do
47
- @scope.function_create_resources(['file', {'/etc/foo'=>{'ensure'=>'present'}}])
48
- @compiler.catalog.resource(:file, "/etc/foo")['ensure'].should == 'present'
49
- end
50
- it 'should accept multiple types' do
51
- type_hash = {}
52
- type_hash['notify'] = {'message' => 'one'}
53
- type_hash['user'] = {'home' => true}
54
- @scope.function_create_resources(['notify', type_hash])
55
- @compiler.catalog.resource(:notify, "notify")['message'].should == 'one'
56
- @compiler.catalog.resource(:notify, "user")['home'].should == true
57
- end
58
- it 'should fail to add non-existing type' do
59
- lambda {
60
- @scope.function_create_resources(['fooper', {}]) }.should raise_error(ArgumentError, 'could not create resource of unknown type fooper')
61
- end
62
- before :each do
63
- Puppet[:code]=
64
- '
65
- class t {}
66
- define foo($one){notify{$name: message => $one}}
67
- notify{test:}
68
- '
69
- setup_scope
70
- Puppet::Parser::Functions.function(:create_resources)
71
- end
72
- it 'should be able to create defined resoure types' do
73
- @scope.function_create_resources(['foo', {'blah'=>{'one'=>'two'}}])
74
- # still have to compile for this to work...
75
- # I am not sure if this constraint ruins the tests
76
- @scope.compiler.compile
77
- @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
78
- end
79
- it 'should fail if defines are missing params' do
80
- @scope.function_create_resources(['foo', {'blah'=>{}}])
81
- lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /Must pass one/)
82
- end
83
- it 'should be able to add multiple defines' do
84
- hash = {}
85
- hash['blah'] = {'one' => 'two'}
86
- hash['blaz'] = {'one' => 'three'}
87
- @scope.function_create_resources(['foo', hash])
88
- # still have to compile for this to work...
89
- # I am not sure if this constraint ruins the tests
90
- @scope.compiler.compile
91
- @compiler.catalog.resource(:notify, "blah")['message'].should == 'two'
92
- @compiler.catalog.resource(:notify, "blaz")['message'].should == 'three'
93
- end
94
- end
95
- describe 'when creating classes' do
96
- before :each do
97
- Puppet[:code]=
98
- '
99
- class t {}
100
- class bar($one){notify{test: message => $one}}
101
- notify{tester:}
102
- '
103
- setup_scope
104
- Puppet::Parser::Functions.function(:create_resources)
105
- end
106
- it 'should be able to create classes' do
107
- @scope.function_create_resources(['class', {'bar'=>{'one'=>'two'}}])
108
- @scope.compiler.compile
109
- @compiler.catalog.resource(:notify, "test")['message'].should == 'two'
110
- @compiler.catalog.resource(:class, "bar").should_not be_nil#['message'].should == 'two'
111
- end
112
- it 'should fail to create non-existing classes' do
113
- lambda { @scope.function_create_resources(['class', {'blah'=>{'one'=>'two'}}]) }.should raise_error(ArgumentError ,'could not find hostclass blah')
114
- end
115
- end
116
- end
@@ -1,48 +0,0 @@
1
- $users3 = {
2
- 'dannyboy454' => {
3
- 'user_name'=>'dlfjdslkf',
4
- 'ensure'=>present,
5
- 'require' => 'User[foobar]',
6
- 'before' => 'User[sally-mae]'
7
- },
8
- 'bobby-joe' => {'ensure'=>present}
9
- }
10
- create_resources('create_resources::user', $users3)
11
-
12
- # TODO - types are not applied in main stage
13
- $users = {
14
- 'sally-mae' =>
15
- {'ensure' => 'present',
16
- 'require' => 'User[bobby-joe]'
17
- }
18
- }
19
- create_resources('user', $users)
20
-
21
- user { 'foobar':
22
- ensure => present,
23
- require => User['bobby-joe']
24
- }
25
-
26
- $classes = {
27
- 'create_resources' => {
28
- 'ensure' => 'present'
29
- }
30
- }
31
-
32
- create_resources('class', $classes)
33
-
34
- class create_resources(
35
- $ensure,
36
- $user_name=$name
37
- ){
38
- user{$name: ensure => $ensure}
39
- notify{$user_name:}
40
- }
41
-
42
- define create_resources::user(
43
- $ensure,
44
- $user_name=$operatingsystem
45
- ){
46
- user{$name: ensure => $ensure}
47
- notify{$user_name:}
48
- }
@@ -1,15 +0,0 @@
1
- # Translates module name to proper class name
2
- # This is especially useful if you want to give a nice name to
3
- # a configuration option and still want to use some class with
4
- # less readable name e.g. puppetmaster -> puppet::server
5
- # - if the argument matches known module name, it returns corresponding class name
6
- # - otherwise it returns argument that was specified
7
- #
8
- module Puppet::Parser::Functions
9
- newfunction(:class_name, :type => :rvalue) do |args|
10
- mapping = YAML.load_file(lookupvar('kafo_config_file'))[:mapping]
11
- mod = args[0].to_sym
12
- mapping[mod].nil? ? mod : "#{mapping[mod][:dir_name]}::#{mapping[mod][:manifest_name].gsub('/', '::')}"
13
- end
14
- end
15
-
@@ -1,15 +0,0 @@
1
- # Takes a hash to extract keys from
2
- # - If the first argument is not Hash, print warning and return nil
3
- # - Returns array of hash keys otherwise
4
- #
5
- module Puppet::Parser::Functions
6
- newfunction(:hash_keys, :type => :rvalue) do |args|
7
- unless args[0].is_a?(Hash)
8
- Puppet.warning "hash_keys takes one argument, the input hash"
9
- nil
10
- else
11
- args[0].keys
12
- end
13
- end
14
- end
15
-
@@ -1,22 +0,0 @@
1
- #
2
- # is_hash.rb
3
- #
4
-
5
- module Puppet::Parser::Functions
6
- newfunction(:is_hash, :type => :rvalue, :doc => <<-EOS
7
- Returns true if the variable passed to this function is a hash.
8
- EOS
9
- ) do |arguments|
10
-
11
- raise(Puppet::ParseError, "is_hash(): Wrong number of arguments " +
12
- "given (#{arguments.size} for 1)") if arguments.size != 1
13
-
14
- type = arguments[0]
15
-
16
- result = type.is_a?(Hash)
17
-
18
- return result
19
- end
20
- end
21
-
22
- # vim: set ts=2 sw=2 et :
@@ -1,21 +0,0 @@
1
- # Orders modules names according to kafo.yaml
2
- #
3
- # if order was specified we take all modules in this order, if there are
4
- # other modules that were not ordered, we put them at the end in non-specified
5
- # order
6
- module Puppet::Parser::Functions
7
- newfunction(:kafo_ordered, :type => :rvalue) do |args|
8
- order = YAML.load_file(lookupvar('kafo_config_file'))[:order]
9
- if order.nil?
10
- args[0]
11
- else
12
- result = []
13
- base = args[0].clone
14
- order.each do |name|
15
- result<< base.delete(name)
16
- end
17
- (result + base).compact
18
- end
19
- end
20
- end
21
-
@@ -1,13 +0,0 @@
1
- # Loads a answer file
2
- #
3
- # it can be specified either as a $kafo_answer_file variable or it's read from config file
4
- module Puppet::Parser::Functions
5
- newfunction(:load_kafo_answer_file, :type => :rvalue) do |args|
6
- answer_file = lookupvar('kafo_answer_file')
7
- if answer_file && answer_file != :undefined && !answer_file.empty?
8
- answer_file
9
- else
10
- YAML.load_file(lookupvar('kafo_config_file'))[:answer_file]
11
- end
12
- end
13
- end
@@ -1,37 +0,0 @@
1
- module Puppet::Parser::Functions
2
-
3
- # convert nil values to :undefined recursively
4
- newfunction(:convert, :type => :rvalue) do |args|
5
- hash = args[0]
6
- data = {}
7
-
8
- hash.each do |key, value|
9
- if value.is_a?(Hash)
10
- data[key] = function_convert([value])
11
- else
12
- data[key] = value unless value.nil?
13
- end
14
- end
15
-
16
- data
17
- end
18
-
19
- newfunction(:loadanyyaml, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
20
- Load a YAML file containing an array, string, or hash, and return the data
21
- in the corresponding native data type.
22
-
23
- For example:
24
-
25
- $myhash = loadanyyaml('/etc/puppet/data/myhash.yaml')
26
- ENDHEREDOC
27
-
28
- args.delete_if { |filename| not File.exist? filename }
29
-
30
- if args.length == 0
31
- raise Puppet::ParseError, ("loadanyyaml(): No files to load")
32
- end
33
-
34
- function_convert([YAML.load_file(args[0])])
35
- end
36
-
37
- end
@@ -1,24 +0,0 @@
1
- # Takes a key to lookup in the installation answers file
2
- # - If it's a hash, declare a class with those parameters
3
- # - If it's true or "true" declare the default parameters for that class
4
- # - If it's false or "false" ignore it
5
- # - Otherwise fail with error
6
- #
7
- define kafo_configure::yaml_to_class {
8
-
9
- $classname = class_name($name)
10
-
11
- if is_hash($kafo_configure::params[$name]) {
12
- # The quotes around $classname seem to matter to puppet's parser...
13
- $params = { "${classname}" => $kafo_configure::params[$name] }
14
- create_resources( 'class', $params )
15
- } elsif $kafo_configure::params[$name] == true {
16
- $params = { "${classname}" => {} }
17
- create_resources( 'class', $params )
18
- } elsif ! $kafo_configure::params[$name] or $kafo_configure::params[$name] == "false" {
19
- debug("${::hostname}: not including $name")
20
- } else {
21
- fail("${::hostname}: unknown type of answers data for $name")
22
- }
23
-
24
- }