Class: Puppet::Moddeps::Installer

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/moddeps/installer.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(module_path = nil, puppet_version = nil) ⇒ Installer

Creates an instance of Puppet::Moddeps::Installer

Examples:

No parameters

depinstaller = Puppet::Moddeps::Installer.new

Specify a module path

depinstaller = Puppet::Moddeps::Installer.new('/tmp')

Specify a module path and a Puppet version

depinstaller = Puppet::Moddeps::Installer.new('/tmp', '6.18.0')

Parameters:

  • module_path (String) (defaults to: nil)

    The path to which modules will be installed

  • puppet_version (String) (defaults to: nil)

    The verion of Puppet to use when resolving dependencies



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/puppet/moddeps/installer.rb', line 40

def initialize(module_path=nil, puppet_version=nil)
  if module_path
    abort('The provided module path was not a string.') unless module_path.is_a?(String)
    @module_path = module_path
  else
    separator = self.path_separator(RbConfig::CONFIG['host_os'])
    @module_path = %x(puppet config print modulepath).split(separator)[0].strip
  end

  if puppet_version
    abort('The provided puppet version was not a string.') unless puppet_version.is_a?(String)
  end

  @puppet_version = puppet_version

  @usage = <<~ENDUSAGE
    Usage: puppet-moddeps module_one [module_two] [...]
           Call puppet-moddeps with the name of one or more installed modules'
  ENDUSAGE
end

Instance Attribute Details

#module_pathString (readonly)

The path to which modules will be installed

Returns:

  • (String)

    The path to which modules will be installed



13
14
15
# File 'lib/puppet/moddeps/installer.rb', line 13

def module_path
  @module_path
end

#puppet_versionString (readonly)

The version of Puppet that will be used when resolving dependencies. If none is provided then a Puppet version constraint is not applied during resolution.

Returns:

  • (String)

    The version of Puppet that will be used when resolving dependencies if one was specified.



22
23
24
# File 'lib/puppet/moddeps/installer.rb', line 22

def puppet_version
  @puppet_version
end

Instance Method Details

#call_puppet(module_object) ⇒ Object

Shell out to the puppet binary to install a module without dependencies.

Parameters:



237
238
239
240
241
# File 'lib/puppet/moddeps/installer.rb', line 237

def call_puppet(module_object)
  cmd = "puppet module install --force --ignore-dependencies #{module_object.owner}-#{module_object.name} --version #{module_object.version}"
  puts "Running \"#{cmd}\""
  %x(#{cmd})
end

#install(*puppet_module) ⇒ Object

Installs the dependencies for one or more local modules. This is the primary entry point for this class.

Examples:

Install dependencies for one module

depinstaller.install(['apache'])

Install dependencies for multiple module

depinstaller.install(['apache', 'nginx'])

Parameters:

  • puppet_module (Array[String])

    An array of strings representig the names of one or more locally installed puppet modules.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/puppet/moddeps/installer.rb', line 73

def install(*puppet_module)
  # puppet_module will always be an array.
  # The elements of the array are the values passed in.
  if puppet_module.nil? || puppet_module.size == 0 || puppet_module[0].nil? || puppet_module[0].size == 0
    puts 'input problem'
    abort(@usage)
  end

  module_array = puppet_module[0]

  # The intent is to only accept strings as arguments.
  # It is also expected that all arguments are installed modules
  module_array.each do |mod|
    abort(@usage) unless mod.is_a?(String)
    abort("Can't find #{mod} in #{@module_path}") unless self.installed?(mod)
  end

  module_objects = resolve_local_module_deps(module_array)
  
  # Remove the local modules from the list of modules to install
  # so that the installation process does not overwrite whatever
  # initiated running puppet-moddeps.
  module_objects.each do |obj|
    if module_array.include?(obj.name)
      module_objects.delete(obj)
    end
  end

  # install the needed modules
  self.install_modules(module_objects)
end

#install_modules(module_objects) ⇒ Object

Installs requested modules if they are not already installed.

Parameters:

  • module_objects (Array[Puppet::Moddeps::Module])

    An array of module objects representing the modules that need to be installed



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/puppet/moddeps/installer.rb', line 184

def install_modules(module_objects)
  if Array(module_objects).size > 0
    puts "Modules will be installed into #{@module_path}"

    Array(module_objects).each do |mod|
      if self.installed?(mod.name) && self.module_versions_match?(mod.owner, mod.name, mod.version)
        puts "#{mod.owner}-#{mod.name} #{mod.version} is already installed, skipping"
      else
        self.call_puppet(mod)
      end
    end
  else
    puts 'No dependencies were marked for installation.'
  end
end

#installed?(module_name) ⇒ Boolean

Test to see if a module’s folder is present within the module path.

Parameters:

  • module_name (String)

    The name of a module

Returns:

  • (Boolean)

    Returns true if found, false otherwise



112
113
114
# File 'lib/puppet/moddeps/installer.rb', line 112

def installed?(module_name)
  File.directory?("#{@module_path}/#{module_name}")
end

#module_versions_match?(module_owner, module_name, module_version) ⇒ Boolean

Compare the owner, name, and version of an installed module to a provided set of information.

Parameters:

  • module_owner (String)

    The owner / author of a module. Ex. puppetlabs

  • module_name (String)

    The name of a module. Ex. apache

  • module_version (String)

    The semantic version of a module. Ex. 5.6.0

Returns:

  • (Boolean)

    Retruns true if the information matches, false otherwise



224
225
226
227
228
229
230
231
# File 'lib/puppet/moddeps/installer.rb', line 224

def module_versions_match?(module_owner, module_name, module_version)
   = self.(module_name)
  if ['author'].eql?(module_owner) && ['version'].eql?(module_version)
    return true
  else
    return false
  end
end

#parse_metadata(module_name) ⇒ Hash

Parses the metadata.json file of a module and returns it as Hash

Parameters:

  • module_name (String)

    The name of a module

Returns:

  • (Hash)

    A hash representing the JSON metadata



207
208
209
210
# File 'lib/puppet/moddeps/installer.rb', line 207

def (module_name)
   = File.read("#{@module_path}/#{module_name}/metadata.json")
  data     = JSON.parse()
end

#path_separator(os_string) ⇒ String

Determine the character used to separate entries in an operating system’s path environment variable.

Parameters:

  • os_string (String)

    A string representing a host’s operating system as returned by RbConfig::CONFIG

Returns:

  • (String)

    Returns “;” on Windows and “:” on everything else



125
126
127
128
129
130
131
# File 'lib/puppet/moddeps/installer.rb', line 125

def path_separator(os_string)
  if (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ os_string) != nil
    separator = ';'
  else
    separator = ':'
  end
end

#resolve_local_module_deps(modules) ⇒ Array[Puppet::Moddeps::Module]

Resolves the dependencies of one or more locally installed modules

Parameters:

  • modules (Array[String])

    An array of module names

Returns:

  • (Array[Puppet::Moddeps::Module])

    An array of module objects representing the modules that need to be installed to satisfiy the dependencies of the local module(s)



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/puppet/moddeps/installer.rb', line 141

def resolve_local_module_deps(modules)
  # Build the document model from the modules.
  model = PuppetfileResolver::Puppetfile::Document.new('')

  modules.each do |mod|
    model.add_module(
      PuppetfileResolver::Puppetfile::LocalModule.new(mod)
    )
  end

  # Make sure the Puppetfile model is valid.
  unless model.valid?
    raise "Unable to resolve dependencies for modules: #{modules.map(&:title).join(', ')}"
  end

  resolver = PuppetfileResolver::Resolver.new(model, @puppet_version)

  # Configure and resolve the dependency graph, catching any errors
  # raised by puppetfile-resolver and re-raising them as Bolt errors.
  begin
    result = resolver.resolve(
      cache:                 nil,
      ui:                    nil,
      module_paths:          [@module_path],
      allow_missing_modules: false
    )
  rescue StandardError => e
    raise e.message
  end

  # Turn specifications into module objects. This will skip over anything that is not
  # a module specification (i.e. a Puppet version specification).
  module_objects = result.specifications.each_with_object(Set.new) do |(_name, spec), acc|
    next unless spec.instance_of? PuppetfileResolver::Models::ModuleSpecification
    acc << Puppet::Moddeps::Module.new(spec.owner, spec.name, spec.version.to_s)
  end
end