Module: Beaker::ModuleInstallHelper

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

Overview

Provides method for use in module test setup to install the module under test and it’s dependencies on the specified hosts

Instance Method Summary collapse

Instance Method Details

#forge_apiObject



194
195
196
197
198
199
200
201
202
203
# File 'lib/beaker/module_install_helper.rb', line 194

def forge_api
  fa = ENV['BEAKER_FORGE_API']
  unless fa.nil?
    fa = 'https://' + fa if fa !~ /^(https:\/\/|http:\/\/)/i
    fa += '/' unless fa != /\/$/
    return fa
  end

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

#forge_hostObject



183
184
185
186
187
188
189
190
191
192
# File 'lib/beaker/module_install_helper.rb', line 183

def forge_host
  fh = ENV['BEAKER_FORGE_HOST']
  unless fh.nil?
    fh = 'https://' + fh if fh !~ /^(https:\/\/|http:\/\/)/i
    fh += '/' unless fh != /\/$/
    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



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/beaker/module_install_helper.rb', line 161

def get_module_source_directory(call_stack)
  matching_caller = call_stack.select { |i| i =~ /(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



131
132
133
134
135
136
137
138
139
# File 'lib/beaker/module_install_helper.rb', line 131

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.



11
12
13
# File 'lib/beaker/module_install_helper.rb', line 11

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.



27
28
29
# File 'lib/beaker/module_install_helper.rb', line 27

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



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

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

  fh = ENV['BEAKER_FORGE_HOST']

  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



53
54
55
# File 'lib/beaker/module_install_helper.rb', line 53

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



57
58
59
60
61
62
63
64
65
# File 'lib/beaker/module_install_helper.rb', line 57

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



17
18
19
20
21
22
23
# File 'lib/beaker/module_install_helper.rb', line 17

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



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

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



151
152
153
154
155
156
157
# File 'lib/beaker/module_install_helper.rb', line 151

def 
   = "#{$module_source_dir}/metadata.json"
  unless File.exist?()
    raise "Error loading metadata.json file from #{$module_source_dir}"
  end
  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



143
144
145
146
147
# File 'lib/beaker/module_install_helper.rb', line 143

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



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/beaker/module_install_helper.rb', line 92

def module_version_from_requirement(mod_name, vr_str)
  require 'net/http'
  uri = URI("#{forge_api}v3/modules/#{mod_name}")
  response = Net::HTTP.get(uri)
  forge_data = JSON.parse(response)

  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 '#{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



113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/beaker/module_install_helper.rb', line 113

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