voxpupuli-acceptance 0.1.1 → 1.0.1

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
  SHA256:
3
- metadata.gz: 5703585055ce98b5b167311675cef06877eca43a25d888f24c304f9dd3cc9e48
4
- data.tar.gz: 998637dd8ed80052df9988eba800bd6601fe6b90512b1b29572b1aa8d6546925
3
+ metadata.gz: a4af7213db70ec8ff38b6c3210f221161309ce55aacad5fc2edceda47acad4c8
4
+ data.tar.gz: 9837dce3ad8410384caa6d75d275e2ca8bbbcf706c556cf67c3c19c18314e67e
5
5
  SHA512:
6
- metadata.gz: bc2449b163a0c21a8394242b4ddd6ca920573ebd13b4cad7d2e76a87a379272b8a68ca1f1cab75f53aa2d62335bbccb6b78d1ae5bfaf61eb66e471d14978ab98
7
- data.tar.gz: f7ef10e75b2f31605e8ac942a1c917f0cc86ed080bb6dc0f6d1346013a2e4b05afb64706dc665fc03f4c52bc75f1c038b41bb810f5855a36aefa18e4dbf4e331
6
+ metadata.gz: f3f0acefd724b135d00a073c4587c09467e952e1e147796d50189319639ed5fa4de34afd6f0d7b55e441dbbf575badb9634c539c285492c05ecd791ef376c450
7
+ data.tar.gz: 8b17e3c63d05c963bc37a9d8dac23e105b8d726518f7ffb8898875fc3dff14cce0e861f9170b26aa41901718b0abff45e089230813ca2fd67dfd744664062372
@@ -0,0 +1,21 @@
1
+ shared_examples 'an idempotent resource' do |host|
2
+ host ||= default
3
+
4
+ it 'applies with no errors' do
5
+ apply_manifest_on(host, manifest, catch_failures: true)
6
+ end
7
+
8
+ it 'applies a second time without changes' do
9
+ apply_manifest_on(host, manifest, catch_changes: true)
10
+ end
11
+ end
12
+
13
+ shared_examples 'the example' do |name, host|
14
+ include_examples 'an idempotent resource', host do
15
+ let(:manifest) do
16
+ path = File.join(Dir.pwd, 'examples', name)
17
+ raise Exception, "Example '#{path}' does not exist" unless File.exist?(path)
18
+ File.read(path)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ module Voxpupuli
2
+ module Acceptance
3
+ class Facts
4
+ ENV_VAR_PREFIX = 'BEAKER_FACTER_'
5
+ FACT_FILE = '/etc/facter/facts.d/voxpupuli-acceptance-env.json'
6
+
7
+ class << self
8
+ def beaker_facts_from_env
9
+ facts = {}
10
+
11
+ ENV.each do |var, value|
12
+ next unless var.start_with?(ENV_VAR_PREFIX)
13
+
14
+ fact = var.sub(ENV_VAR_PREFIX, '').downcase
15
+ facts[fact] = value
16
+ end
17
+
18
+ facts
19
+ end
20
+
21
+ def write_beaker_facts_on(hosts)
22
+ beaker_facts = beaker_facts_from_env
23
+
24
+ if beaker_facts.any?
25
+ require 'json'
26
+ on(hosts, "mkdir -p #{File.dirname(FACT_FILE)} && cat <<VOXPUPULI_BEAKER_ENV_VARS > #{FACT_FILE}\n#{beaker_facts.to_json}\nVOXPUPULI_BEAKER_ENV_VARS")
27
+ else
28
+ on(hosts, "rm -f #{FACT_FILE}")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,143 @@
1
+ require 'tmpdir'
2
+ require 'puppet/modulebuilder'
3
+
4
+ module Voxpupuli
5
+ module Acceptance
6
+ class Fixtures
7
+ class << self
8
+ # Install fixture modules on the given hosts
9
+ #
10
+ # @param [Host, Array<Host>, String, Symbol] hosts
11
+ # The beaker hosts to run on
12
+ # @param [Array<String>, String] modulepath
13
+ # A modulepath as Puppet uses it. Typically spec/fixtures/modules
14
+ # @param [Logger, nil] logger
15
+ # An optional logger
16
+ def install_fixture_modules_on(hosts, modulepath, logger = nil)
17
+ Dir.mktmpdir do |destination|
18
+ modules = build_modules(modulepath, destination, logger)
19
+
20
+ install_modules_on(hosts, modules, logger)
21
+ end
22
+
23
+ nil
24
+ end
25
+
26
+ # Build modules in the given sources.
27
+ #
28
+ # @param [Array<String>, String] modulepath
29
+ # A modulepath as Puppet uses it
30
+ # @param [String] destination
31
+ # The target directory to build modules into
32
+ # @param [Logger, nil] logger
33
+ # An optional logger
34
+ #
35
+ # @return [Hash<String=>String>]
36
+ # A mapping of module names and the path to their tarball
37
+ def build_modules(modulepath, destination, logger = nil)
38
+ modulepath = [modulepath] if modulepath.is_a?(String)
39
+
40
+ modules = {}
41
+
42
+ modulepath.each do |dir|
43
+ Dir[File.join(dir, '*', 'metadata.json')].each do |metadata|
44
+ path = File.dirname(metadata)
45
+ name = File.basename(path)
46
+ next if modules.include?(name)
47
+
48
+ builder = Puppet::Modulebuilder::Builder.new(File.realpath(path), destination, logger)
49
+
50
+ unless valid_directory_name?(name, builder.metadata['name'])
51
+ warning = "Directory name of #{path} doesn't match metadata name #{builder.metadata['name']}"
52
+ if logger
53
+ logger.warn(warning)
54
+ else
55
+ STDERR.puts(warning)
56
+ end
57
+ end
58
+
59
+ modules[name] = builder.build
60
+ end
61
+ end
62
+
63
+ modules
64
+ end
65
+
66
+ # Install modules on a number of hosts
67
+ #
68
+ # This is done by iterating over every host. On that host a temporary
69
+ # directory is created. Each module is copied there and installed by
70
+ # force.
71
+ #
72
+ # @param [Host, Array<Host>, String, Symbol] hosts
73
+ # The beaker hosts to run on
74
+ # @param [Hash<String=>String>] modules
75
+ # A mapping between module names and their tarball
76
+ # @param [Logger, nil] logger
77
+ # An optional logger
78
+ def install_modules_on(hosts, modules, logger = nil)
79
+ hosts.each do |host|
80
+ logger.debug("Installing modules on #{host}") if logger
81
+
82
+ temp_dir_on(host) do |target_dir|
83
+ modules.each do |name, source_path|
84
+ target_file = File.join(target_dir, File.basename(source_path))
85
+ logger.debug("Copying module #{name} from #{source_path} to #{target_file}") if logger
86
+
87
+ scp_to(host, source_path, target_file)
88
+ on host, puppet("module install --force --ignore-dependencies '#{target_file}'")
89
+ end
90
+ end
91
+ end
92
+
93
+ nil
94
+ end
95
+
96
+ # Create a temporay directory on the host, similar to Dir.mktmpdir but
97
+ # on a remote host.
98
+ #
99
+ # @example
100
+ # temp_dir_on(host) { |dir| puts dir }
101
+ #
102
+ # @param [Host, String, Symbol] host
103
+ # The beaker host to run on
104
+ def temp_dir_on(host, &block)
105
+ result = on host, "mktemp -d"
106
+ raise "Could not create directory" unless result.success?
107
+
108
+ dir = result.stdout.strip
109
+
110
+ begin
111
+ yield dir
112
+ ensure
113
+ on host, "rm -rf #{dir}"
114
+ end
115
+
116
+ nil
117
+ end
118
+
119
+ # Validate a directory name matches its metadata name.
120
+ #
121
+ # This is useful to detect misconfigurations in fixture set ups.
122
+ #
123
+ # @example
124
+ # assert valid_directory_name?('tftp', 'theforeman-tftp')
125
+ # @example
126
+ # refute valid_directory_name?('puppet-tftp', 'theforeman-tftp')
127
+ #
128
+ # @param [String] directory_name
129
+ # Name of the directory. Not the full path
130
+ # @param [String] metadata_name
131
+ # Name as it shows up in the metadata. It is normalized and accepts
132
+ # both / and - as separators.
133
+ #
134
+ # @return [Boolean] Wether the directory name is valid with the given
135
+ # metadata name
136
+ def valid_directory_name?(directory_name, metadata_name)
137
+ normalized = metadata_name.tr('/', '-').split('-').last
138
+ normalized == directory_name
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,7 @@
1
+ begin
2
+ require 'puppetlabs_spec_helper/tasks/beaker'
3
+ # Fixtures can be needed because of spec_prep
4
+ require 'puppetlabs_spec_helper/tasks/fixtures'
5
+ rescue LoadError
6
+ require 'beaker-rspec/rake_task'
7
+ end
@@ -1,14 +1,25 @@
1
- def configure_beaker(&block)
1
+ require_relative 'examples'
2
+
3
+ def configure_beaker(modules: :metadata, &block)
2
4
  ENV['PUPPET_INSTALL_TYPE'] ||= 'agent'
3
5
  ENV['BEAKER_PUPPET_COLLECTION'] ||= 'puppet6'
4
6
  ENV['BEAKER_debug'] ||= 'true'
5
7
  ENV['BEAKER_HYPERVISOR'] ||= 'docker'
6
8
 
9
+ # On Ruby 3 this doesn't appear to matter but on Ruby 2 beaker-hiera must be
10
+ # included before beaker-rspec so Beaker::DSL is final
11
+ require 'beaker-hiera'
7
12
  require 'beaker-rspec'
8
13
  require 'beaker-puppet'
9
14
  require 'beaker/puppet_install_helper'
10
- require 'beaker/module_install_helper'
11
- $module_source_dir = get_module_source_directory caller
15
+
16
+ case modules
17
+ when :metadata
18
+ require 'beaker/module_install_helper'
19
+ $module_source_dir = get_module_source_directory caller
20
+ when :fixtures
21
+ require_relative 'fixtures'
22
+ end
12
23
 
13
24
  run_puppet_install_helper unless ENV['BEAKER_provision'] == 'no'
14
25
 
@@ -18,14 +29,56 @@ def configure_beaker(&block)
18
29
 
19
30
  # Configure all nodes in nodeset
20
31
  c.before :suite do
21
- install_module
22
- install_module_dependencies
32
+ case modules
33
+ when :metadata
34
+ install_module
35
+ install_module_dependencies
36
+ when :fixtures
37
+ fixture_modules = File.join(Dir.pwd, 'spec', 'fixtures', 'modules')
38
+ Voxpupuli::Acceptance::Fixtures.install_fixture_modules_on(hosts, fixture_modules)
39
+ end
23
40
 
24
- if block
25
- hosts.each do |host|
26
- yield host
41
+ if RSpec.configuration.suite_configure_facts_from_env
42
+ require_relative 'facts'
43
+ Voxpupuli::Acceptance::Facts.write_beaker_facts_on(hosts)
44
+ end
45
+
46
+ if RSpec.configuration.suite_hiera?
47
+ hiera_data_dir = RSpec.configuration.suite_hiera_data_dir
48
+
49
+ if Dir.exist?(hiera_data_dir)
50
+ write_hiera_config_on(hosts, RSpec.configuration.suite_hiera_hierachy)
51
+ copy_hiera_data_to(hosts, hiera_data_dir)
52
+ end
53
+ end
54
+
55
+ local_setup = RSpec.configuration.setup_acceptance_node
56
+ hosts.each do |host|
57
+ yield host if block
58
+
59
+ if local_setup && File.exist?(local_setup)
60
+ puts "Configuring #{host} by applying #{local_setup}"
61
+ apply_manifest_on(host, File.read(local_setup), catch_failures: true)
27
62
  end
28
63
  end
29
64
  end
30
65
  end
31
66
  end
67
+
68
+ RSpec.configure do |c|
69
+ # Fact handling
70
+ c.add_setting :suite_configure_facts_from_env, default: true
71
+
72
+ # Hiera settings
73
+ c.add_setting :suite_hiera, default: true
74
+ c.add_setting :suite_hiera_data_dir, default: File.join('spec', 'acceptance', 'hieradata')
75
+ c.add_setting :suite_hiera_hierachy, default: [
76
+ 'fqdn/%{fqdn}.yaml',
77
+ 'os/%{os.family}/%{os.release.major}.yaml',
78
+ 'os/%{os.family}.yaml',
79
+ 'common.yaml',
80
+ ]
81
+
82
+ # Node setup
83
+ c.add_setting :setup_acceptance_node, default: File.join('spec', 'setup_acceptance_node.pp')
84
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voxpupuli-acceptance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vox Pupuli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-06 00:00:00.000000000 Z
11
+ date: 2021-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bcrypt_pbkdf
@@ -31,6 +31,12 @@ dependencies:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 4.2.0
34
+ - - "!="
35
+ - !ruby/object:Gem::Version
36
+ version: 4.22.0
37
+ - - "!="
38
+ - !ruby/object:Gem::Version
39
+ version: 4.23.0
34
40
  type: :runtime
35
41
  prerelease: false
36
42
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,6 +44,12 @@ dependencies:
38
44
  - - ">="
39
45
  - !ruby/object:Gem::Version
40
46
  version: 4.2.0
47
+ - - "!="
48
+ - !ruby/object:Gem::Version
49
+ version: 4.22.0
50
+ - - "!="
51
+ - !ruby/object:Gem::Version
52
+ version: 4.23.0
41
53
  - !ruby/object:Gem::Dependency
42
54
  name: beaker-docker
43
55
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +64,20 @@ dependencies:
52
64
  - - ">="
53
65
  - !ruby/object:Gem::Version
54
66
  version: '0'
67
+ - !ruby/object:Gem::Dependency
68
+ name: beaker-hiera
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '0.4'
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '0.4'
55
81
  - !ruby/object:Gem::Dependency
56
82
  name: beaker-hostgenerator
57
83
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +176,34 @@ dependencies:
150
176
  - - ">="
151
177
  - !ruby/object:Gem::Version
152
178
  version: '0'
179
+ - !ruby/object:Gem::Dependency
180
+ name: puppet-modulebuilder
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - "~>"
184
+ - !ruby/object:Gem::Version
185
+ version: '0.1'
186
+ type: :runtime
187
+ prerelease: false
188
+ version_requirements: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: '0.1'
193
+ - !ruby/object:Gem::Dependency
194
+ name: rake
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ">="
198
+ - !ruby/object:Gem::Version
199
+ version: '0'
200
+ type: :runtime
201
+ prerelease: false
202
+ version_requirements: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
153
207
  - !ruby/object:Gem::Dependency
154
208
  name: rbnacl
155
209
  requirement: !ruby/object:Gem::Requirement
@@ -215,8 +269,12 @@ extensions: []
215
269
  extra_rdoc_files: []
216
270
  files:
217
271
  - lib/voxpupuli/acceptance.rb
272
+ - lib/voxpupuli/acceptance/examples.rb
273
+ - lib/voxpupuli/acceptance/facts.rb
274
+ - lib/voxpupuli/acceptance/fixtures.rb
275
+ - lib/voxpupuli/acceptance/rake.rb
218
276
  - lib/voxpupuli/acceptance/spec_helper_acceptance.rb
219
- homepage: http://github.com/voxpupuli/voxpupuli-acceptance
277
+ homepage: https://github.com/voxpupuli/voxpupuli-acceptance
220
278
  licenses:
221
279
  - Apache-2.0
222
280
  metadata: {}
@@ -228,15 +286,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
228
286
  requirements:
229
287
  - - ">="
230
288
  - !ruby/object:Gem::Version
231
- version: '0'
289
+ version: '2.4'
290
+ - - "<"
291
+ - !ruby/object:Gem::Version
292
+ version: '4'
232
293
  required_rubygems_version: !ruby/object:Gem::Requirement
233
294
  requirements:
234
295
  - - ">="
235
296
  - !ruby/object:Gem::Version
236
297
  version: '0'
237
298
  requirements: []
238
- rubyforge_project:
239
- rubygems_version: 2.7.10
299
+ rubygems_version: 3.1.6
240
300
  signing_key:
241
301
  specification_version: 4
242
302
  summary: Helpers for acceptance testing Vox Pupuli modules