Module: Beaker::ModuleInstallHelper

Includes:
DSL
Defined in:
lib/beaker/module_install_helper.rb

Instance Method Summary collapse

Instance Method Details

#forge_apiObject



199
200
201
202
203
204
205
206
207
208
# File 'lib/beaker/module_install_helper.rb', line 199

def forge_api
  fa = ENV['BEAKER_FORGE_API'] # rubocop:disable Style/FetchEnvVar
  unless fa.nil?
    fa = "https://#{fa}" unless %r{^(https://|http://)}i.match?(fa)
    fa += '/' unless fa != %r{/$}
    return fa
  end

  'https://forgeapi.puppetlabs.com/'
end

#forge_hostObject



188
189
190
191
192
193
194
195
196
197
# File 'lib/beaker/module_install_helper.rb', line 188

def forge_host
  fh = ENV['BEAKER_FORGE_HOST'] # rubocop:disable Style/FetchEnvVar
  unless fh.nil?
    fh = "https://#{fh}" unless %r{^(https://|http://)}i.match?(fh)
    fh += '/' unless fh != %r{/$}
    return fh
  end

  'https://forge.puppet.com/'
end

#get_module_source_directory(call_stack) ⇒ Object

Use this property to store the module_source_dir, so we don’t traverse the tree every time



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/beaker/module_install_helper.rb', line 166

def get_module_source_directory(call_stack)
  matching_caller = call_stack.grep(/(spec_helper_acceptance|_spec)/i)

  raise 'Error finding module source directory' if matching_caller.empty?

  matching_caller = matching_caller[0] if matching_caller.is_a?(Array)
  search_in = matching_caller[/[^:]+/]

  module_source_dir = nil
  # here we go up the file tree and search the directories for a
  # valid metadata.json
  while module_source_dir.nil? && search_in != File.dirname(search_in)
    # remove last segment (file or folder, doesn't matter)
    search_in = File.dirname(search_in)

    # Append metadata.json, check it exists in the directory we're searching
     = File.join(search_in, 'metadata.json')
    module_source_dir = search_in if File.exist?()
  end
  module_source_dir
end

#hosts_to_install_module_onObject

This method will return array of all masters. If no masters exist, it will return all agent nodes. If no nodes tagged master or agent exist, all nodes will be returned



136
137
138
139
140
141
142
143
144
# File 'lib/beaker/module_install_helper.rb', line 136

def hosts_to_install_module_on
  masters = hosts_with_role(hosts, :master)
  return masters unless masters.empty?

  agents = hosts_with_role(hosts, :agent)
  return agents unless agents.empty?

  hosts
end

#install_module(opts = {}) ⇒ Object

This method calls the install_module_on method for each host which is a master, or if no master is present, on all agent nodes.



14
15
16
# File 'lib/beaker/module_install_helper.rb', line 14

def install_module(opts = {})
  install_module_on(hosts_to_install_module_on, opts)
end

#install_module_dependencies(deps = nil) ⇒ Object

This method calls the install_module_dependencies_on method for each host which is a master, or if no master is present, on all agent nodes.



30
31
32
# File 'lib/beaker/module_install_helper.rb', line 30

def install_module_dependencies(deps = nil)
  install_module_dependencies_on(hosts_to_install_module_on, deps)
end

#install_module_dependencies_on(hsts, deps = nil) ⇒ Object

This method will install the module under tests module dependencies on the specified host(s) from the dependencies list in metadata.json



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/beaker/module_install_helper.rb', line 36

def install_module_dependencies_on(hsts, deps = nil)
  hsts = [hsts] if hsts.is_a?(Hash)
  hsts = [hsts] unless hsts.respond_to?(:each)
  deps =  if deps.nil?

  fh = ENV.fetch('BEAKER_FORGE_HOST', nil)

  hsts.each do |host|
    deps.each do |dep|
      if fh.nil?
        install_puppet_module_via_pmt_on(host, dep)
      else
        with_forge_stubbed_on(host) do
          install_puppet_module_via_pmt_on(host, dep)
        end
      end
    end
  end
end

#install_module_from_forge(mod_name, ver_req) ⇒ Object



56
57
58
# File 'lib/beaker/module_install_helper.rb', line 56

def install_module_from_forge(mod_name, ver_req)
  install_module_from_forge_on(hosts_to_install_module_on, mod_name, ver_req)
end

#install_module_from_forge_on(hsts, mod_name, ver_req) ⇒ Object



60
61
62
63
64
65
66
67
68
# File 'lib/beaker/module_install_helper.rb', line 60

def install_module_from_forge_on(hsts, mod_name, ver_req)
  sub_mod_name = mod_name.sub('/', '-')
  dependency = {
    module_name: sub_mod_name,
    version: module_version_from_requirement(sub_mod_name, ver_req),
  }

  install_module_dependencies_on(hsts, [dependency])
end

#install_module_on(host, opts = {}) ⇒ Object

This method will install the module under test on the specified host(s) from the source on the local machine



20
21
22
23
24
25
26
# File 'lib/beaker/module_install_helper.rb', line 20

def install_module_on(host, opts = {})
  opts = {
    source: $module_source_dir,
    module_name: ,
  }.merge(opts)
  copy_module_to(host, opts)
end

#module_dependencies_from_metadataObject

This method returns an array of dependencies from the metadata.json file in the format of an array of hashes, containing :module_name and optionally :version elements. If no dependencies are specified, empty array is returned



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/beaker/module_install_helper.rb', line 73

def 
   = 
  return [] unless .key?('dependencies')

  dependencies = []
  ['dependencies'].each do |d|
    tmp = { module_name: d['name'].sub('/', '-') }

    if d.key?('version_requirement')
      tmp[:version] = module_version_from_requirement(tmp[:module_name],
                                                      d['version_requirement'])
    end
    dependencies.push(tmp)
  end

  dependencies
end

#module_metadataObject

This method uses the module_source_directory path to read the metadata.json file into a json array



157
158
159
160
161
162
# File 'lib/beaker/module_install_helper.rb', line 157

def 
   = "#{$module_source_dir}/metadata.json"
  raise "Error loading metadata.json file from #{$module_source_dir}" unless File.exist?()

  JSON.parse(File.read())
end

#module_name_from_metadataObject

This method will read the ‘name’ attribute from metadata.json file and remove the first segment. E.g. puppetlabs-vcsrepo -> vcsrepo



148
149
150
151
152
153
# File 'lib/beaker/module_install_helper.rb', line 148

def 
  res = get_module_name ['name']
  raise 'Error getting module name' unless res

  res[1]
end

#module_version_from_requirement(mod_name, vr_str) ⇒ Object

This method takes a module name and the version requirement string from the metadata.json file, containing either lower bounds of version or both lower and upper bounds. The function then uses the forge rest endpoint to find the most recent release of the given module matching the version requirement



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/beaker/module_install_helper.rb', line 95

def module_version_from_requirement(mod_name, vr_str)
  require 'net/http'
  uri = URI("#{forge_api}v3/modules/#{mod_name}")
  response = Net::HTTP.get_response(uri)
  raise "Puppetforge API error '#{uri}': '#{response.body}'" if response.code.to_i >= 400

  forge_data = JSON.parse(response.body)

  vrs = version_requirements_from_string(vr_str)

  # Here we iterate the releases of the given module and pick the most recent
  # that matches to version requirement
  forge_data['releases'].each do |rel|
    return rel['version'] if vrs.all? { |vr| vr.match?('', rel['version']) }
  end

  raise "No release version found matching '#{mod_name}' '#{vr_str}'"
end

#version_requirements_from_string(vr_str) ⇒ Object

This method takes a version requirement string as specified in the link below, with either simply a lower bound, or both lower and upper bounds and returns an array of Gem::Dependency objects docs.puppet.com/puppet/latest/modules_metadata.html



118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/beaker/module_install_helper.rb', line 118

def version_requirements_from_string(vr_str)
  ops = vr_str.scan(/[(<|>=)]{1,2}/i)
  vers = vr_str.scan(/[(0-9|.)]+/i)

  raise 'Invalid version requirements' if ops.count != 0 &&
                                          ops.count != vers.count

  vrs = []
  ops.each_with_index do |op, index|
    vrs.push(Gem::Dependency.new('', "#{op} #{vers[index]}"))
  end

  vrs
end