fpm-cookery 0.32.0 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +5 -2
  4. data/CHANGELOG.md +19 -0
  5. data/Rakefile +34 -0
  6. data/docs/index.rst +1 -0
  7. data/docs/pages/using-hiera.rst +285 -0
  8. data/fpm-cookery.gemspec +6 -1
  9. data/lib/fpm/cookery/book.rb +29 -2
  10. data/lib/fpm/cookery/book_hook.rb +1 -0
  11. data/lib/fpm/cookery/chain_packager.rb +4 -2
  12. data/lib/fpm/cookery/cli.rb +45 -5
  13. data/lib/fpm/cookery/config.rb +2 -1
  14. data/lib/fpm/cookery/environment.rb +17 -8
  15. data/lib/fpm/cookery/exceptions.rb +3 -1
  16. data/lib/fpm/cookery/facts.rb +50 -35
  17. data/lib/fpm/cookery/hiera.rb +35 -0
  18. data/lib/fpm/cookery/hiera/defaults.rb +50 -0
  19. data/lib/fpm/cookery/hiera/scope.rb +35 -0
  20. data/lib/fpm/cookery/inheritable_attr.rb +222 -0
  21. data/lib/fpm/cookery/log/hiera.rb +21 -0
  22. data/lib/fpm/cookery/omnibus_packager.rb +4 -2
  23. data/lib/fpm/cookery/package/package.rb +1 -0
  24. data/lib/fpm/cookery/package/version.rb +11 -4
  25. data/lib/fpm/cookery/packager.rb +13 -11
  26. data/lib/fpm/cookery/recipe.rb +167 -105
  27. data/lib/fpm/cookery/source.rb +6 -8
  28. data/lib/fpm/cookery/source_handler.rb +18 -3
  29. data/lib/fpm/cookery/source_handler/curl.rb +2 -2
  30. data/lib/fpm/cookery/source_handler/directory.rb +10 -11
  31. data/lib/fpm/cookery/source_handler/noop.rb +1 -2
  32. data/lib/fpm/cookery/source_handler/svn.rb +1 -1
  33. data/lib/fpm/cookery/version.rb +1 -1
  34. data/lib/hiera/fpm_cookery_logger.rb +12 -0
  35. data/recipes/redis/config/common.yaml +11 -0
  36. data/recipes/redis/config/git_2.4.2_tag.yaml +4 -0
  37. data/recipes/redis/config/git_2.4.yaml +4 -0
  38. data/recipes/redis/config/git_sha_072a905.yaml +4 -0
  39. data/recipes/redis/config/svn_r2400.yaml +4 -0
  40. data/recipes/redis/config/svn_trunk.yaml +3 -0
  41. data/recipes/redis/recipe.rb +2 -27
  42. data/spec/book_spec.rb +34 -0
  43. data/spec/config_spec.rb +19 -0
  44. data/spec/environment_spec.rb +37 -0
  45. data/spec/facts_spec.rb +54 -31
  46. data/spec/fixtures/hiera_config/CentOS.yaml +1 -0
  47. data/spec/fixtures/hiera_config/common.yaml +12 -0
  48. data/spec/fixtures/hiera_config/custom.yaml +3 -0
  49. data/spec/fixtures/hiera_config/rpm.yaml +12 -0
  50. data/spec/hiera_spec.rb +158 -0
  51. data/spec/inheritable_attr_spec.rb +202 -0
  52. data/spec/package_dir_spec.rb +37 -0
  53. data/spec/package_maintainer_spec.rb +4 -1
  54. data/spec/package_version_spec.rb +50 -0
  55. data/spec/path_spec.rb +20 -0
  56. data/spec/recipe_spec.rb +161 -56
  57. data/spec/source_integrity_check_spec.rb +7 -6
  58. data/spec/spec_helper.rb +14 -0
  59. data/spec/support/shared_context.rb +71 -0
  60. metadata +108 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a8092cdd01badb7c7c69adc60983e1d8b220f878
4
- data.tar.gz: b31722bf137e40a7201b1b8b00aaa6adc89ca165
3
+ metadata.gz: 1bf794a51fecd510948128ab67bb5c795ed3e4c6
4
+ data.tar.gz: 7020e143e7ba574171c2ace14831df9336e40182
5
5
  SHA512:
6
- metadata.gz: cf005ab828be976ab4372ea4366155ac3e0c9b21d545d462a7000430ceebd4117c0cff927c7feb17a39873e6057b79d8a5f83e8bb30789f3ff216efc2a2674af
7
- data.tar.gz: a3b7a495348df7a575f802f7f4881a4996791a7ae5a4fade00f62111c5da79196fa99c08ee4cfa2a95e339e0caa07511bafcdbad5b074647e6682ee3e335a894
6
+ metadata.gz: a711e293257e46fbb1b46601c96e4ee90152cb835604ab30e75fc10f204f54f2b5d19591ef9a6777ea2b085dc50097554611517a1601aa1a886e4008dbb193ff
7
+ data.tar.gz: 0625f2d75df8e1aaafdeedcf2796ffc4b65d57a8648cbdd655aa60ae09f353fa6eb60ee5bf8f5d6ae03207c3bdb61a12f601e611cdc62474efa32107c31d6746
data/.gitignore CHANGED
@@ -12,6 +12,8 @@ tmp-dest/
12
12
  .vagrant
13
13
  Vagrantfile
14
14
  /vendor
15
+ /coverage
16
+ /doc
15
17
 
16
18
  # vim backups
17
19
  *~
@@ -1,10 +1,13 @@
1
1
  sudo: false
2
+ cache: bundler
2
3
  script: bundle exec rake spec
3
4
  rvm:
4
5
  - 1.9.3
5
6
  - 2.0.0
6
- - 2.1.1
7
- - 2.2.1
7
+ - 2.1.10
8
+ - 2.2.5
9
+ - 2.3.1
10
+ - 2.4.1
8
11
  - ruby-head
9
12
 
10
13
  matrix:
@@ -1,3 +1,22 @@
1
+ # v0.33.0
2
+ * Hiera lookups of recipe data from templated YAML files. (BaxterStockman / #150)
3
+ * Travis-CI build matrix improvements. (thedrow / #155)
4
+ * Expose `lsbcodename` fact. (thedrow / #158)
5
+ * Improved build cookie generator. (BaxterStockman / #157)
6
+ * Improved facter usage. (BaxterStockman / #167)
7
+ * Alpine (apk) package support. (lloydpick / #162)
8
+ * Fix typos and missing tests. (lloydpick / #163)
9
+ * Add `inspect` command. (BaxterStockman / #165)
10
+ * json dependency fix to work with older Rubies. (BaxterStockman / #166)
11
+ * Bug fix when using local directory sources. (#164)
12
+ * Make vendor delimiter configurable. (#169)
13
+ * Ensure consistend extracted source value from all source handlers. (#170)
14
+ * Add default package version and guard against nil/empty versions. (BaxterStockman / #176)
15
+ * Documenting the use of Hiera in recipes. (BaxterStockman / #184)
16
+ * Ruby pre-2.0 compatibility fix. (BaxterStockman / #183)
17
+ * Add "safe\_yaml" dependency. (davewongillies / #186, #154)
18
+ * Add `rpm_dist` method. (sfzylad / #190)
19
+
1
20
  # v0.32.0
2
21
  * Add `sourcedir` accessor that holds the path to the extracted source. (#132)
3
22
  * Add support for DirRecipe and Directory Handler. (cas-ei / #147)
data/Rakefile CHANGED
@@ -5,3 +5,37 @@ desc 'Run all specs'
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
7
7
  task :default => :spec
8
+
9
+ namespace :docs do |ns|
10
+ require 'systemu'
11
+
12
+ docs_dir = File.join(File.dirname(File.expand_path(__FILE__)), 'docs')
13
+
14
+ Dir.chdir docs_dir do
15
+ sphinxbuild = ENV['SPHINXBUILD'] || 'sphinx-build'
16
+
17
+ status, stdout, stderr = systemu "make SPHINXBUILD=#{sphinxbuild} help"
18
+ if status != 0 and Rake.verbose
19
+ $stderr.puts '# Unable to load tasks in the `docs` namespace:'
20
+ stderr.each_line { |l| $stderr.puts "# #{l}" }
21
+ end
22
+
23
+ desc 'clean up doc builds'
24
+ task 'clean' do
25
+ Dir.chdir docs_dir do
26
+ system "make SPHINXBUILD=#{sphinxbuild} clean"
27
+ end
28
+ end
29
+
30
+ stdout.each_line.grep(/^\s+(\w+?)\s+(.*)$/) do
31
+ t, d = $1, $2
32
+
33
+ desc d
34
+ task t do
35
+ Dir.chdir docs_dir do
36
+ system "make SPHINXBUILD=#{sphinxbuild} #{t}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -26,6 +26,7 @@ Documentation Contents
26
26
  :maxdepth: 2
27
27
 
28
28
  pages/getting-started
29
+ pages/using-hiera
29
30
 
30
31
 
31
32
  Indices and tables
@@ -0,0 +1,285 @@
1
+ Using Hiera
2
+ ===========
3
+
4
+ `Hiera <http://docs.puppetlabs.com/hiera>`_ is a hierarchical key-value lookup
5
+ tool from Puppet Labs that, integrated with fpm-cookery, allows you to improve
6
+ your package builds by:
7
+
8
+ * Separating data from build logic,
9
+ * Selectively overriding particular recipe attributes for different platforms,
10
+ software versions, etc., and
11
+ * Staying DRY by reusing data via the ``hiera`` and ``scope``
12
+ :ref:`interpolation methods <hiera-interpolation-in-data-files>`.
13
+
14
+ Configuring Hiera
15
+ -----------------
16
+
17
+ Controlling the Lookup Hierarchy
18
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19
+
20
+ By default, FPM-Cookery looks for Hiera data files under the ``config``
21
+ subdirectory of the directory containing the target recipe. You can override
22
+ this through the ``--data-dir`` option to ``fpm-cook``. You can also set the
23
+ data file directory via the ``datadir=`` class method while defining the recipe
24
+ class:
25
+
26
+ .. code-block:: ruby
27
+
28
+ class FreshRecipe < FPM::Cookery::Recipe
29
+ datadir = "/somewhere/other/than/#{File.dirname(__FILE__)}/config"
30
+ end
31
+
32
+ .. note::
33
+
34
+ Part of the recipe initialization process involves :ref:`automatically
35
+ applying data<hiera-automatic-application-of-hiera-data>` contained in the
36
+ files in the current ``datadir``. If you change ``datadir`` after the
37
+ ``initialize`` method completes, you must call the ``apply`` method
38
+ manually to reconfigure the recipe according to the files in the the new
39
+ ``datadir``.
40
+
41
+ When retrieving recipe data, fpm-cookery observes the following hierarchy of
42
+ files under ``datadir``, ordered from highest to lowest precedence:
43
+
44
+ +--------------------------------+--------------------------------------------+
45
+ | Path | Description |
46
+ +================================+============================================+
47
+ | ``"#{recipe.platform}.yaml"``, | The platform for which the recipe is being |
48
+ | ``"#{recipe.platform}.json"`` | built. Corresponds to Facter's |
49
+ | | ``operatingsystem`` fact, except that all |
50
+ | | characters are lowercase. For instance, if |
51
+ | | ``operatingsystem`` is ``ArchLinux``, |
52
+ | | ``recipe.platform`` will be ``archlinux``. |
53
+ +--------------------------------+--------------------------------------------+
54
+ | ``"#{recipe.target}.yaml"``, | The target package type. Options span all |
55
+ | ``"#{recipe.target}.json"`` | package types that FPM can build, |
56
+ | | including include ``rpm``, ``apk``, |
57
+ | | ``deb``, ``osxpkg``, and others. |
58
+ +--------------------------------+--------------------------------------------+
59
+ | ``"common.yaml"``, | Intended for configuration data that is |
60
+ | ``"common.json"`` | common to all builds. |
61
+ +--------------------------------+--------------------------------------------+
62
+
63
+ You can further influence the lookup hierarchy by setting the environment
64
+ variable ``FPM_HIERARCHY``. The value should be string containing a
65
+ colon-separated list of filename stems. For example::
66
+
67
+ $ FPM_HIERARCHY=centos:rhel:el fpm-cook package
68
+
69
+ prepends ``centos``, ``rhel``, and ``el`` to the search hierarchy, causing
70
+ fpm-cookery to attempt load data from ``centos.yaml``, ``rhel.yaml``,
71
+ ``el.yaml``, and their ``.json`` counterparts. The final hierarchy is:
72
+
73
+ * ``"centos.yaml"``
74
+ * ``"rhel.yaml"``
75
+ * ``"el.yaml"``
76
+ * ``"#{recipe.platform}.yaml"``
77
+ * ``"#{recipe.target}.yaml"``
78
+ * ``"common.yaml"``
79
+
80
+ Other Settings
81
+ ^^^^^^^^^^^^^^
82
+
83
+ You can exercise more fine-grained control by providing the path to a Hiera
84
+ configuration file via the ``--hiera-config`` option. See `the Hiera docs
85
+ <http://docs.puppetlabs.com/hiera/3.0/configuring.html>`_ for available
86
+ configuration file options.
87
+
88
+ Hiera in Recipes
89
+ ----------------
90
+
91
+ Lookups
92
+ ^^^^^^^
93
+
94
+ fpm-cookery provides the ``lookup`` class method on all classes that inherit
95
+ from ``FPM::Cookery::Recipe``, as well as an instance method of the same name.
96
+ ``lookup`` takes one mandatory argument: a key to be looked up in the Hiera
97
+ data files. If Hiera locates the key, ``lookup`` returns the corresponding
98
+ value; otherwise ``lookup`` returns ``nil``.
99
+
100
+ Writing Data Files
101
+ ^^^^^^^^^^^^^^^^^^
102
+
103
+ See `the Hiera data sources documentation <http://docs.puppetlabs.com/hiera/3.0/data_sources.html>`_
104
+ for an overview of Hiera data sources.
105
+
106
+ .. note::
107
+
108
+ Please ensure that your data files use the extensions ``.yaml`` or
109
+ ``.json``, as appropriate -- Hiera ignores files with any other
110
+ extension.
111
+
112
+ You'll probably find data files most useful for defining recipe attributes.
113
+ However, key-value mappings in Hiera data sources need not correspond to recipe
114
+ attributes -- you can store any data you like as long as it is valid YAML or
115
+ JSON:
116
+
117
+ .. code-block:: yaml
118
+
119
+ name: custom-package
120
+ version: '2.1.6'
121
+ some_arbitrary_data:
122
+ - thing one
123
+ - thing two
124
+ - thing: three
125
+ is_a: hash
126
+
127
+ *(later on...)*
128
+
129
+ .. code-block:: ruby
130
+
131
+ CustomPackageRecipe.lookup('some_arbitrary_data')
132
+ #=> ['thing one', 'thing two', {'thing' => 'three', 'is_a' => 'hash'}]
133
+
134
+ .. _hiera-interpolation-in-data-files:
135
+
136
+ Interpolation in Data Files
137
+ '''''''''''''''''''''''''''
138
+
139
+ Within a data file, the ``%{scope("...")}`` method interpolates values from the
140
+ following sources:
141
+
142
+ * The current recipe class
143
+ * ``FPM::Cookery::Facts``
144
+ * `Facter <https://puppetlabs.com/facter>`_ facts
145
+
146
+ The ``%{hiera("...")}`` method interpolates values looked up in the data files
147
+ themselves.
148
+
149
+ Say you are on an ``x86_64`` system, and consider the following YAML data:
150
+
151
+ .. code-block:: yaml
152
+
153
+ name: something-clever
154
+ version: '0.9.0'
155
+ source: 'https://www.sporkforge.net/archive/%{scope("arch")}/%{hiera("name")}-%{hiera("version")}.tar.gz'
156
+
157
+ ``source`` evaluates like so:
158
+
159
+ .. code-block:: ruby
160
+
161
+ SomethingCleverRecipe.lookup('source')
162
+ #=> 'https://www.sporkforge.net/archive/x86_64/something-clever-0.9.0.tar.gz'
163
+
164
+ .. _hiera-automatic-application-of-hiera-data:
165
+
166
+ Symbolized Hash Keys
167
+ ''''''''''''''''''''
168
+
169
+ Ruby's YAML library automatically converts hash keys prefixed with colons into
170
+ symbols. This is good to know when using Hiera to store data relevant to
171
+ methods that expect symbols in their arguments -- for instance, ``source``.
172
+
173
+ **BAD**:
174
+
175
+ .. code-block:: yaml
176
+
177
+ source:
178
+ - 'git://gogs.myhostname.info/labyrinthm/bowie.git'
179
+ - with: git
180
+ tag: 'v1.1.3'
181
+
182
+ **GOOD**:
183
+
184
+ .. code-block:: yaml
185
+
186
+ source:
187
+ - 'git://gogs.myhostname.info/labyrinthm/bowie.git'
188
+ - :with: git
189
+ :tag: 'v1.1.3'
190
+
191
+ Method Signatures and Unpacking Data Structures
192
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
193
+
194
+ fpm-cookery tries to Do What You Mean when dealing when loading data from
195
+ Hiera, but there are some subtleties relating to method signatures that you
196
+ should be aware of.
197
+
198
+ Methods that expect a single argument are the simplest case -- just provide a
199
+ single key-value pair:
200
+
201
+ .. code-block:: yaml
202
+
203
+ name: 'myrecipe'
204
+
205
+ Methods that expect multiple arguments should be given as a list:
206
+
207
+ .. code-block:: yaml
208
+
209
+ depends:
210
+ - openssl-devel
211
+ - docker-compose
212
+
213
+ fpm-cookery will automatically unpack the argument list with Ruby's splat
214
+ (``*``) operator when invoking the method.
215
+
216
+ Methods that expect a hash should be given as a series of key-value pairs:
217
+
218
+ .. code-block:: yaml
219
+
220
+ environment:
221
+ LC_ALL: C
222
+ SHELLOPTS: xtrace
223
+ PAGER: cat
224
+
225
+ fpm-cookery will *merge* these pairs into whatever data is already assigned as
226
+ the value of the attribute, rather than replacing it.
227
+
228
+ Some methods expect a heterogeneous list of arguments, ``source`` being the
229
+ most important of these. If you want to pass options to ``source`` or other
230
+ such methods, use the following technique:
231
+
232
+ .. code-block:: yaml
233
+
234
+ source:
235
+ - 'https://my.subversion-server.net/trunk'
236
+ - :revision: 92834
237
+ :externals: false
238
+
239
+ This translates to a Ruby ``Array``:
240
+
241
+ .. code-block:: ruby
242
+
243
+ ['https://my.subversion-server.net/trunk', {:revision => 92834, :externals => false}]
244
+
245
+ For simple sources that consist only of a URL, you can do:
246
+
247
+ .. code-block:: yaml
248
+
249
+ source: 'git://our.internal-git.com/foo/bar.git'
250
+
251
+ Automatic Application of Hiera Data
252
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
253
+
254
+ As part of the recipe initialization process, fpm-cookery calls ``lookup`` to
255
+ retrieve any Hiera-defined values corresponding to recipe attribute names such
256
+ as ``name``, ``version``, and ``source``. If Hiera can locate the key,
257
+ fpm-cookery automatically sets the relevant attribute to the retrieved value.
258
+
259
+ Attributes defined in Hiera data files take precedence over
260
+ attributes defined in ``recipe.rb``:
261
+
262
+ .. code-block:: yaml
263
+
264
+ --- # common.yaml
265
+ source: https://www.repourl.org/source/neato-0.2.4-7.tar.bz2
266
+
267
+ .. code-block:: ruby
268
+
269
+ # recipe.rb
270
+ class NeatoRecipe < FPM::Cookery::Recipe
271
+ source 'https://www.repourl.org/source/nightly/neato-nightly.tar.gz'
272
+ end
273
+
274
+ This results in:
275
+
276
+ .. code-block:: ruby
277
+
278
+ NeatoRecipe.source #=> https://www.repourl.org/source/neato-0.2.4-7.tar.bz2
279
+
280
+ Examples
281
+ --------
282
+
283
+ See the `Redis recipe
284
+ <https://github.com/bernd/fpm-cookery/tree/master/recipes/redis>`_ for an
285
+ example of fpm-cookery and Hiera in action.
@@ -18,11 +18,16 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_development_dependency "rspec", "~> 3.0"
21
+ s.add_development_dependency "rspec", "~> 3.3"
22
22
  s.add_development_dependency "rake"
23
+ s.add_development_dependency "pry"
24
+ s.add_development_dependency "simplecov", "~> 0.11"
23
25
  s.add_runtime_dependency "fpm", "~> 1.1"
24
26
  s.add_runtime_dependency "facter"
25
27
  s.add_runtime_dependency "puppet", "~> 3.4"
26
28
  s.add_runtime_dependency "addressable", "~> 2.3.8"
27
29
  s.add_runtime_dependency "systemu"
30
+ s.add_runtime_dependency "json", ">= 1.7.7", "< 2.0"
31
+ s.add_runtime_dependency "json_pure", ">= 1.7.7", "< 2.0"
32
+ s.add_runtime_dependency "safe_yaml", "~> 1.0.4"
28
33
  end
@@ -1,10 +1,13 @@
1
1
  require 'singleton'
2
+ require 'fpm/cookery/path'
2
3
 
3
4
  module FPM
4
5
  module Cookery
5
6
  class Book
6
7
  include Singleton
7
8
 
9
+ attr_accessor :filename, :config
10
+
8
11
  def initialize
9
12
  @recipe = nil
10
13
  end
@@ -12,13 +15,37 @@ module FPM
12
15
  # Load the given file and instantiate an object. Wrap the class in an
13
16
  # anonymous module to avoid namespace cluttering. (see Kernel.load)
14
17
  def load_recipe(filename, config, &callback)
15
- Kernel.load(filename, true)
16
- callback.call(@recipe.new(filename, config))
18
+ @filename = FPM::Cookery::Path.new(filename).realpath
19
+ @config = config
20
+
21
+ Kernel.load(@filename.to_path, true)
22
+ callback.call(@recipe.new)
17
23
  end
18
24
 
19
25
  def add_recipe_class(klass)
20
26
  @recipe = klass
21
27
  end
28
+
29
+ # Hijack the recipe singleton to make the +filename+ and +config+ objects
30
+ # available when a descendent of BaseRecipe is declared. This makes it
31
+ # possible to do Hiera lookups at class definition time.
32
+ def inject_class_methods!(klass)
33
+ # It's necessary to close over local variables because the receiver
34
+ # changes within the scope of +define_method+, so +self.filename+ would
35
+ # wrongly refer to +singleton_klass.filename+.
36
+ filename = self.filename
37
+ config = self.config
38
+
39
+ singleton_klass = (class << klass ; self ; end)
40
+
41
+ singleton_klass.send(:define_method, :filename) do
42
+ filename
43
+ end
44
+
45
+ singleton_klass.send(:define_method, :config) do
46
+ config
47
+ end
48
+ end
22
49
  end
23
50
  end
24
51
  end