Module: Unix::Pkg

Includes:
Beaker::CommandFactory
Included in:
Host
Defined in:
lib/beaker/host/unix/pkg.rb

Instance Attribute Summary

Attributes included from Beaker::CommandFactory

#assertions

Instance Method Summary collapse

Methods included from Beaker::CommandFactory

#execute, #fail_test

Instance Method Details

#check_for_command(name) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/beaker/host/unix/pkg.rb', line 11

def check_for_command(name)
  result = exec(Beaker::Command.new("which #{name}"), :accept_all_exit_codes => true)
  case self['platform']
  when /solaris-10/
    # solaris 10 appears to have considered `which` to have run successfully,
    # even if the command didn't exist, so it'll return a 0 exit code in
    # either case. Instead we match for the phrase output when a match isn't
    # found: "no #{name} in $PATH", reversing it to match our API
    !(result.stdout.match(/^no\ #{name}\ in\ /))
  else
    result.exit_code == 0
  end
end

#check_for_package(name, opts = {}) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/beaker/host/unix/pkg.rb', line 25

def check_for_package(name, opts = {})
  opts = { :accept_all_exit_codes => true }.merge(opts)
  case self['platform']
  when /sles-10/
    result = execute("zypper se -i --match-exact #{name}", opts) { |result| result }
    result.stdout.include?('No packages found') ? (return false) : (return result.exit_code == 0)
  when /opensuse|sles-/
    if !self[:sles_rpmkeys_nightly_pl_imported]
      # The `:sles_rpmkeys_nightly_pl_imported` key is only read here at this
      # time. It's just to make sure that we only do the key import once, &
      # isn't for setting or use outside of beaker.
      execute('rpmkeys --import http://nightlies.puppetlabs.com/07BB6C57', opts)
      self[:sles_rpmkeys_nightly_pl_imported] = true
    end
    result = execute("zypper --gpg-auto-import-keys se -i --match-exact #{name}", opts) { |result| result }
  when /amazon|fedora|centos|redhat|el-/
    result = execute("rpm -q #{name}", opts) { |result| result }
  when /ubuntu|debian/
    result = execute("dpkg -s #{name}", opts) { |result| result }
  when /solaris-11/
    result = execute("pkg info #{name}", opts) { |result| result }
  when /solaris-10/
    result = execute("pkginfo #{name}", opts) { |result| result }
    result = execute("pkginfo CSW#{name}", opts) { |result| result } if result.exit_code == 1
  when /openbsd/
    result = execute("pkg_info #{name}", opts) { |result| result }
  when /archlinux/
    result = execute("pacman -Q #{name}", opts) { |result| result }
  else
    raise "Package #{name} cannot be queried on #{self}"
  end
  result.exit_code == 0
end

#determine_if_x86_64Boolean

Examine the host system to determine the architecture

Returns:

  • (Boolean)

    true if x86_64, false otherwise



224
225
226
227
228
229
230
231
232
# File 'lib/beaker/host/unix/pkg.rb', line 224

def determine_if_x86_64
  if self[:platform].include?('solaris')
    result = exec(Beaker::Command.new("uname -a | grep x86_64"), :accept_all_exit_codes => true)
    result.exit_code == 0
  else
    result = exec(Beaker::Command.new("arch | grep x86_64"), :accept_all_exit_codes => true)
    result.exit_code == 0
  end
end

#extract_rpm_proxy_options(url) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Extract RPM command’s proxy options from URL

Parameters:

Returns:

  • (String)

    httpproxy and httport options for rpm

Raises:

  • (StandardError)

    When encountering a string that cannot be parsed



242
243
244
245
246
247
248
249
250
251
# File 'lib/beaker/host/unix/pkg.rb', line 242

def extract_rpm_proxy_options(url)
  begin
    host, port = url.match(/https?:\/\/(.*):(\d*)/)[1, 2]
    raise if host.empty? or port.empty?

    "--httpproxy #{host} --httpport #{port}"
  rescue
    raise "Cannot extract host and port from '#{url}'"
  end
end

#install_local_package(onhost_package_file, onhost_copy_dir = nil) ⇒ Object

Installs a package already located on a SUT

Parameters:

  • onhost_package_file (String)

    Path to the package file to install

  • onhost_copy_dir (String) (defaults to: nil)

    Path to the directory where the package file is located. Used on solaris only

Returns:

  • nil



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/beaker/host/unix/pkg.rb', line 260

def install_local_package(onhost_package_file, onhost_copy_dir = nil)
  variant, version, _arch, _codename = self['platform'].to_array
  case variant
  when /^(amazon|fedora|el|redhat|centos)$/
    command_name = 'yum'
    command_name = 'dnf' if (variant == 'fedora' && version.to_i > 21) || (variant == 'amazon' && version.to_i >= 2023)
    execute("#{command_name} --nogpgcheck localinstall -y #{onhost_package_file}")
  when /^(opensuse|sles)$/
    execute("zypper --non-interactive --no-gpg-checks in #{onhost_package_file}")
  when /^(debian|ubuntu)$/
    execute("dpkg -i --force-all #{onhost_package_file}")
    # -qq: Only output errors to stdout
    execute("apt-get update -qq")
  when /^solaris$/
    self.solaris_install_local_package(onhost_package_file, onhost_copy_dir)
  when /^osx$/
    install_package(onhost_package_file)
  else
    msg = "Platform #{variant} is not supported by the method "
    msg << 'install_local_package'
    raise ArgumentError, msg
  end
end

#install_package(name, cmdline_args = '', version = nil, opts = {}) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/beaker/host/unix/pkg.rb', line 86

def install_package(name, cmdline_args = '', version = nil, opts = {})
  case self['platform']
  when /opensuse|sles-/
    execute("zypper --non-interactive --gpg-auto-import-keys in #{name}", opts)
  when /amazon-2023|el-(8|9|1[0-9])|fedora/
    name = "#{name}-#{version}" if version
    execute("dnf -y #{cmdline_args} install #{name}", opts)
  when /amazon-(2|7)|centos|redhat|el-[1-7]-/
    name = "#{name}-#{version}" if version
    execute("yum -y #{cmdline_args} install #{name}", opts)
  when /ubuntu|debian/
    name = "#{name}=#{version}" if version
    update_apt_if_needed
    execute("apt-get install --force-yes #{cmdline_args} -y #{name}", opts)
  when /solaris-11/
    if opts[:acceptable_exit_codes]
      opts[:acceptable_exit_codes] << 4
    else
      opts[:acceptable_exit_codes] = [0, 4] unless opts[:accept_all_exit_codes]
    end
    execute("pkg #{cmdline_args} install #{name}", opts)
  when /solaris-10/
    if !check_for_command('pkgutil')
      # https://www.opencsw.org/package/pkgutil/
      noask_text = self.noask_file_text
      noask_file = File.join(external_copy_base, 'noask')
      create_remote_file(self, noask_file, noask_text)
      execute("pkgadd -d http://get.opencsw.org/now -a #{noask_file} -n all", opts)
      execute('/opt/csw/bin/pkgutil -U', opts)
      execute('/opt/csw/bin/pkgutil -y -i pkgutil', opts)
    end
    execute("pkgutil -i -y #{cmdline_args} #{name}", opts)
  when /openbsd/
    begin
      execute("pkg_add -I #{cmdline_args} #{name}", opts) do |command|
        # Handles where there are multiple rubies, installs the latest one
        if (match = /^Ambiguous: #{name} could be (.+)$/.match(command.stderr))
          name = match[1].chomp.split(' ').collect do |x|
            # FIXME: Ruby 3.2 compatibility?
            x =~ /-(\d[^-p]+)/
            [x, $1]
          end.select do |x|
            # Blacklist Ruby 2.2.0+ for the sake of Puppet 3.x
            Gem::Version.new(x[1]) < Gem::Version.new('2.2.0')
          end.sort do |a, b|
            Gem::Version.new(b[1]) <=> Gem::Version.new(a[1])
          end.collect do |x|
            x[0]
          end.first
          raise ArgumentException
        end
        # If the package advises symlinks to be created, do it
        command.stdout.split("\n").select { |x| /^\s+ln\s/.match?(x) }.each do |ln|
          execute(ln, opts)
        end
      end
    rescue
      retry
    end
  when /archlinux/
    update_pacman_if_needed
    execute("pacman -S --noconfirm #{cmdline_args} #{name}", opts)
  else
    raise "Package #{name} cannot be installed on #{self}"
  end
end

#install_package_with_rpm(name, cmdline_args = '', opts = {}) ⇒ Object

Install a package using RPM

Parameters:

  • name (String)

    The name of the package to install. It may be a filename or a URL.

  • cmdline_args (String) (defaults to: '')

    Additional command line arguments for the package manager.

  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • :package_proxy (String)

    A proxy of form host:port

Returns:

  • nil



163
164
165
166
167
# File 'lib/beaker/host/unix/pkg.rb', line 163

def install_package_with_rpm(name, cmdline_args = '', opts = {})
  proxy = ''
  proxy = extract_rpm_proxy_options(opts[:package_proxy]) if name&.start_with?('http') and opts[:package_proxy]
  execute("rpm #{cmdline_args} -Uvh #{name} #{proxy}")
end

#pkg_initializeObject

This method overrides Beaker::Host#pkg_initialize to provide unix-specific package management setup



6
7
8
9
# File 'lib/beaker/host/unix/pkg.rb', line 6

def pkg_initialize
  @apt_needs_update = true
  @pacman_needs_update = true
end

#solaris_install_local_package(package_path, noask_directory = nil) ⇒ Beaker::Result

Installs a local package file on a solaris host

Parameters:

  • package_path (String)

    Path to the package file on the host

  • noask_directory (String) (defaults to: nil)

    Path to the directory for the noask file (only needed for solaris 10).

Returns:

Raises:

  • (ArgumentError)


323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
# File 'lib/beaker/host/unix/pkg.rb', line 323

def solaris_install_local_package(package_path, noask_directory = nil)
  variant, version, _arch, _codename = self['platform'].to_array

  version = version.split('.')[0] # packages are only published for major versions

  error_message = nil
  unless variant == 'solaris'
    error_message = "Can not call solaris_install_local_package for the "
    error_message << "non-solaris platform '#{variant}'"
  end
  if version != '10' && version != '11'
    error_message = "Solaris #{version} is not supported by the method "
    error_message << 'solaris_install_local_package'
  end
  raise ArgumentError, error_message if error_message

  if version == '10'
    noask_text = self.noask_file_text
    create_remote_file self, File.join(noask_directory, 'noask'), noask_text

    install_cmd = "gunzip -c #{package_path} | pkgadd -d /dev/stdin -a noask -n all"
  elsif version == '11'
    install_cmd = "pkg install -g #{package_path} puppet-agent"
  end
  self.exec(Beaker::Command.new(install_cmd))
end

#uncompress_local_tarball(onhost_tar_file, onhost_base_dir, download_file) ⇒ Object

Uncompresses a tarball on the SUT

Parameters:

  • onhost_tar_file (String)

    Path to the tarball to uncompress

  • onhost_base_dir (String)

    Path to the directory to uncompress to

  • download_file (String)

    Name of the file after uncompressing

Returns:

  • nil



291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/beaker/host/unix/pkg.rb', line 291

def uncompress_local_tarball(onhost_tar_file, onhost_base_dir, download_file)
  variant, version, _arch, _codename = self['platform'].to_array
  case variant
  when /^(amazon|fedora|el|centos|redhat|opensuse|sles|debian|ubuntu)$/
    execute("tar -zxvf #{onhost_tar_file} -C #{onhost_base_dir}")
  when /^solaris$/
    # uncompress PE puppet-agent tarball
    if version == '10'
      execute("gunzip #{onhost_tar_file}")
      tar_file_name = File.basename(download_file, '.gz')
      execute("tar -xvf #{tar_file_name}")
    elsif version == '11'
      execute("tar -zxvf #{onhost_tar_file}")
    else
      msg = "Solaris #{version} is not supported by the method "
      msg << 'uncompress_local_tarball'
      raise ArgumentError, msg
    end
  else
    msg = "Platform #{variant} is not supported by the method "
    msg << 'uncompress_local_tarball'
    raise ArgumentError, msg
  end
end

#uninstall_package(name, cmdline_args = '', opts = {}) ⇒ Object



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/beaker/host/unix/pkg.rb', line 169

def uninstall_package(name, cmdline_args = '', opts = {})
  case self['platform']
  when /opensuse|sles-/
    execute("zypper --non-interactive rm #{name}", opts)
  when /amazon-2023|el-(8|9|1[0-9])|fedora/
    execute("dnf -y #{cmdline_args} remove #{name}", opts)
  when /amazon-(2|7)|centos|redhat|el-[1-7]-/
    execute("yum -y #{cmdline_args} remove #{name}", opts)
  when /ubuntu|debian/
    execute("apt-get purge #{cmdline_args} -y #{name}", opts)
  when /solaris-11/
    execute("pkg #{cmdline_args} uninstall #{name}", opts)
  when /solaris-10/
    execute("pkgrm -n #{cmdline_args} #{name}", opts)
  when /aix/
    execute("rpm #{cmdline_args} -e #{name}", opts)
  when /archlinux/
    execute("pacman -R --noconfirm #{cmdline_args} #{name}", opts)
  else
    raise "Package #{name} cannot be installed on #{self}"
  end
end

#update_apt_if_neededObject

If apt has not been updated since the last repo deployment it is updated. Otherwise this is a noop



61
62
63
64
65
66
67
68
# File 'lib/beaker/host/unix/pkg.rb', line 61

def update_apt_if_needed
  return unless /debian|ubuntu/.match?(self['platform'])
  return unless @apt_needs_update

  # -qq: Only output errors to stdout
  execute("apt-get update -qq")
  @apt_needs_update = false
end

#update_pacman_if_neededObject

Arch Linux is a rolling release distribution. We need to ensure that it is up2date Except for the kernel. An upgrade will purge the modules for the currently running kernel Before upgrading packages, we need to ensure we’ve the latest keyring



73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/beaker/host/unix/pkg.rb', line 73

def update_pacman_if_needed
  return unless self['platform'].include?('archlinux')
  return unless @pacman_needs_update

  # creates a GPG key + local keyring
  execute("pacman-key --init")
  # `archlinux-keyring` contains GPG keys that will be imported into the local keyring
  # used to verify package signatures
  execute("pacman --sync --noconfirm --noprogressbar --refresh archlinux-keyring")
  execute("pacman --sync --noconfirm --noprogressbar --refresh --sysupgrade --ignore linux --ignore linux-docs --ignore linux-headers")
  @pacman_needs_update = false
end

#upgrade_package(name, cmdline_args = '', opts = {}) ⇒ Object

Upgrade an installed package to the latest available version

Parameters:

  • name (String)

    The name of the package to update

  • cmdline_args (String) (defaults to: '')

    Additional command line arguments for the package manager



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/beaker/host/unix/pkg.rb', line 197

def upgrade_package(name, cmdline_args = '', opts = {})
  case self['platform']
  when /opensuse|sles-/
    execute("zypper --non-interactive --no-gpg-checks up #{name}", opts)
  when /fedora/
    execute("dnf -y #{cmdline_args} update #{name}", opts)
  when /centos|redhat|el-/
    execute("yum -y #{cmdline_args} update #{name}", opts)
  when /ubuntu|debian/
    update_apt_if_needed
    execute("apt-get install -o Dpkg::Options::='--force-confold' #{cmdline_args} -y --force-yes #{name}", opts)
  when /solaris-11/
    if opts[:acceptable_exit_codes]
      opts[:acceptable_exit_codes] << 4
    else
      opts[:acceptable_exit_codes] = [0, 4] unless opts[:accept_all_exit_codes]
    end
    execute("pkg #{cmdline_args} update #{name}", opts)
  when /solaris-10/
    execute("pkgutil -u -y #{cmdline_args} #{name}", opts)
  else
    raise "Package #{name} cannot be upgraded on #{self}"
  end
end