class Vanagon::Platform

Vanagon classes generally don’t implement JSON or Hash functionality so those need to be monkey-patched for useful inspection.

Constants

PLATFORM_REGEX

Platform names currently contain some information about the platform. Fields within the name are delimited by the ‘-’ character, and this regex can be used to extract those fields.

VERSION_REGEX

Attributes

abs_resource_name[RW]

Always-Be-Scheduling engine specific

architecture[RW]
aws_ami[RW]

AWS engine specific

aws_instance_type[RW]
aws_key[RW]
aws_key_name[RW]
aws_region[RW]
aws_shutdown_behavior[RW]
aws_subnet_id[RW]
aws_user_data[RW]
aws_vpc_id[RW]
brew[RW]
build_dependencies[RW]

Stores an Array of OpenStructs, each representing a complete command to be run to install external the needed toolchains and build dependencies for a given target platform.

build_hosts[RW]

Hardware engine specific

cflags[RW]

Hold a string containing the values that a given platform should use when a Makefile is run - resolves to the CFLAGS and LDFLAGS variables. This should be changed to take advantage of the {Vanagon::Environment}, so that we can better leverage Make’s {www.gnu.org/software/make/manual/html_node/Implicit-Variables.html Implicit Variables}.

It should also be extended to support CXXFLAGS and CPPFLAGS ASAP.

codename[RW]
copy[RW]

Each of these holds the path or name of the command in question, e.g. ‘copy = “/usr/local/bin/gcp”`, or `copy = “cp”`

cross_compiled[RW]

Determines if a platform should be treated as cross-compiled or natively compiled.

defaultdir[RW]

Where does a given platform’s init system expect to find something resembling ‘defaults’ files. Most likely to apply to Linux systems that use SysV-ish, upstart, or systemd init systems.

dist[W]
docker_image[RW]

Docker engine specific

docker_run_args[RW]
environment[RW]

The overall {Vanagon::Environment} that a given platform should pass to each component

find[RW]
install[RW]
ldflags[RW]
make[RW]
mktemp[RW]
name[RW]

Basic generic information related to a given instance of Platform. e.g. The name we call it, the platform triplet (name-version-arch), etc.

num_cores[RW]

A string, containing the script that will be executed on the remote build target to determine how many CPU cores are available on that platform. Vanagon will use that count to determine how many build threads should be initialized for compilations.

os_name[RW]
os_version[RW]
output_dir[RW]

Stores the local path where retrieved artifacts will be saved.

package_type[RW]

The name of the sort of package type that a given platform expects, e.g. msi, rpm,

patch[RW]
platform_triple[RW]
provisioning[RW]

Stores an Array of Strings, which will be passed in as a shell script as part of the provisioning step for a given build target

rpmbuild[RW]
sed[RW]
servicedir[RW]

Where does a given platform expect to find init scripts/service files? e.g. /etc/init.d, /usr/lib/systemd/system

servicetype[RW]

The name of the sort of init system that a given platform uses

servicetypes[RW]

Array of OpenStructs containing the servicetype and the corresponding servicedir

settings[RW]

Freeform Hash of leftover settings

shasum[RW]
shell[RW]

Stores a string, pointing at the shell that should be used if a user needs to change the path or name of the shell that Make will run build recipes in.

sort[RW]
source_output_dir[RW]

Stores the local path where source artifacts will be saved.

ssh_port[RW]

Generic engine

tar[RW]
target_user[RW]

Username to use when connecting to a build target

use_docker_exec[RW]
valid_operators[RW]
vmpooler_template[RW]

VMpooler engine specific

Public Class Methods

load_platform(platform_name, config_directory) click to toggle source

Loads a platform from the config/platforms directory

@param platform_name [String] the name of the platform @param config_directory [String] the path to the platform config file @return [Vanagon::Platform] the platform as specified in the platform config @raise if the instance_eval on Platform fails, the exception is reraised

# File lib/vanagon/platform.rb, line 154
def self.load_platform(platform_name, config_directory)
  platform_name = File.basename(platform_name, '.rb')
  platform_file_name = "#{platform_name}.rb"
  platform_path = File.join(config_directory, platform_file_name)

  begin
    platform_definition = File.read(platform_path)
  rescue Errno::ENOENT, Errno::EACCES => e
    VanagonLogger.error "Error loading '#{platform_name}': #{e}"
    exit 1
  end

  dsl = Vanagon::Platform::DSL.new(platform_name)
  begin
    dsl.instance_eval(platform_definition, platform_path, 1)
    dsl._platform
  rescue StandardError => e
    VanagonLogger.error "Error loading platform '#{platform_name}' using '#{platform_path}':"
    VanagonLogger.error(e)
    VanagonLogger.error e.backtrace.join("\n")
    raise e
  end
end
new(name) click to toggle source

Platform constructor. Takes just the name. Also sets the @name, @os_name, os_version and @architecture instance attributes as a side effect

@param name [String] name of the platform @return [Vanagon::Platform] the platform with the given name

# File lib/vanagon/platform.rb, line 239
def initialize(name) # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize
  @name = name
  @settings = {}
  @os_name = os_name
  @os_version = os_version
  @architecture = architecture
  @ssh_port = 22
  # Environments are like Hashes but with specific constraints
  # around their keys and values.
  @environment = Vanagon::Environment.new
  @provisioning = []
  @install ||= "install"
  @mktemp ||= "mktemp -d -p /var/tmp"
  @target_user ||= "root"
  @find ||= "find"
  @sed ||= "sed"
  @sort ||= "sort"
  @copy ||= "cp"
  @shasum ||= "sha1sum"

  @use_docker_exec = false

  # Our first attempt at defining metadata about a platform
  @cross_compiled ||= false
  @valid_operators ||= ['<', '>', '<=', '>=', '=']
  @servicetypes = []
end

Public Instance Methods

[](key) click to toggle source

This allows instance variables to be accessed using the hash lookup syntax

# File lib/vanagon/platform.rb, line 272
def [](key)
  if instance_variable_get("@#{key}")
    instance_variable_get("@#{key}")
  end
end
add_build_repository(*args) click to toggle source

Generic adder for build repositories

@param *args [Array<String>] List of arguments to pass on to the platform specific method @raise [Vanagon::Error] an arror is raised if the current platform does not define add_repository

# File lib/vanagon/platform.rb, line 509
def add_build_repository(*args)
  if self.respond_to?(:add_repository)
    self.provision_with self.send(:add_repository, *args)
  else
    raise Vanagon::Error, "Adding a build repository not defined for #{name}"
  end
end
add_group(user) click to toggle source

Generate the scripts required to add a group to the package generated. This will also update the group if it has changed.

@param user [Vanagon::Common::User] the user to reference for the group @return [String] the commands required to add a group to the system

# File lib/vanagon/platform.rb, line 183
    def add_group(user)
      cmd_args = ["'#{user.group}'"]
      cmd_args.unshift '--system' if user.is_system

      groupadd_args = cmd_args.join "\s"
      groupmod_args = (cmd_args - ["--system"]).join "\s"

      return <<-HERE.undent
        if getent group '#{user.group}' > /dev/null 2>&1; then
          /usr/sbin/groupmod #{groupmod_args}
        else
          /usr/sbin/groupadd #{groupadd_args}
        fi
      HERE
    end
add_user(user) click to toggle source

Generate the scripts required to add a user to the package generated. This will also update the user if it has changed.

@param user [Vanagon::Common::User] the user to create @return [String] the commands required to add a user to the system

# File lib/vanagon/platform.rb, line 204
    def add_user(user) # rubocop:disable Metrics/AbcSize
      cmd_args = ["'#{user.name}'"]
      cmd_args.unshift "--home '#{user.homedir}'" if user.homedir
      if user.shell
        cmd_args.unshift "--shell '#{user.shell}'"
      elsif user.is_system
        cmd_args.unshift "--shell '/usr/sbin/nologin'"
      end
      cmd_args.unshift "--gid '#{user.group}'" if user.group
      cmd_args.unshift '--system' if user.is_system

      # Collapse the cmd_args array into a string that can be used
      # as an argument to `useradd`
      useradd_args = cmd_args.join "\s"

      # Collapse the cmd_args array into a string that can be used
      # as an argument to `usermod`; If this is a system account,
      # then specify it as such for user addition only (strip
      # --system from usermod_args)
      usermod_args = (cmd_args - ["--system"]).join "\s"

      return <<-HERE.undent
        if getent passwd '#{user.name}' > /dev/null 2>&1; then
          /usr/sbin/usermod #{usermod_args}
        else
          /usr/sbin/useradd #{useradd_args}
        fi
      HERE
    end
dist() click to toggle source

Get the value of @dist, or derive it from the value of @os_name and @os_version. This is relatively RPM specific but ‘#codename’ is defined in Platform, and that’s just as Deb/Ubuntu specific. All of the accessors in the top-level Platform namespace should be refactored, but dist will live here for now. @return [String] the %dist name that RPM will use to build new RPMs

# File lib/vanagon/platform.rb, line 304
def dist
  @dist ||= @os_name.tr('-', '_') + @os_version
end
generate_compiled_archive(project) click to toggle source

Save the generic compiled archive and relevant metadata as packaging output. This will include a json file with all of the components/versions that were built and a bill of materials when relevant. The archive will be a gzipped tarball.

@param project The Vanagon::Project to run this on @return array of commands to be run

# File lib/vanagon/platform.rb, line 524
def generate_compiled_archive(project)
  name_and_version = "#{project.name}-#{project.version}"
  name_and_version_and_platform = "#{name_and_version}.#{name}"
  name_and_platform = "#{project.name}.#{name}"
  final_archive = "output/#{name_and_version_and_platform}.tar.gz"
  archive_directory = "#{project.name}-archive"

  # previously, we weren't properly handling the case of custom BOM paths.
  # If we have a custom BOM path, during Makefile execution, the top-level
  # BOM is moved to the custom path. So, when cleaning up BOMs for non-custom
  # paths we just want to remove the BOM at the top level of the tarball.
  # But, if we have a custom BOM path we want to move it back to where it
  # was prior to the Makefile execution so we can preserve it as an artifact
  # but not leave it to conflict if it's installed in the same custom path
  # as a project using this archive.
  bill_of_materials_command = 'rm -f bill-of-materials'
  if project.bill_of_materials
    bill_of_materials_command = "mv .#{project.bill_of_materials.path}/bill-of-materials ../.."
  end

  [
    "mkdir output",
    "mkdir #{archive_directory}",
    "gunzip -c #{name_and_version}.tar.gz | '#{tar}' -C #{archive_directory} -xf -",
    "rm #{name_and_version}.tar.gz",
    "cd #{archive_directory}/#{name_and_version}; #{bill_of_materials_command}; #{tar} cf ../../#{name_and_version_and_platform}.tar *",
    "gzip -9c #{name_and_version_and_platform}.tar > #{name_and_version_and_platform}.tar.gz",
    "cp build_metadata.#{name_and_platform}.json output/#{name_and_version_and_platform}.json",
    "cp bill-of-materials output/#{name_and_version_and_platform}-bill-of-materials ||:",
    "cp #{name_and_version_and_platform}.tar.gz output",
    "#{shasum} #{final_archive} > #{final_archive}.sha1"
  ]
end
get_service_dir(servicetype = '') click to toggle source

Get configured service dir (added through plat.servicedir, or plat.servicetype ‘foo’, servicedir: ‘bar’) @param servicetype the service type you want the service dir for (optional) @raises VanagonError if more than one service dir is found

# File lib/vanagon/platform.rb, line 606
def get_service_dir(servicetype = '')
  if @servicetypes.empty?
    return @servicedir
  end
  servicedir = @servicetypes.select { |s| s.servicetype.include?(servicetype) }.flat_map(&:servicedir).compact

  if servicedir.size > 1
    raise Vanagon::Error, "You can only have one service dir for each service type. Found '#{servicedir.join(',')}' for service type #{servicetype}"
  end

  servicedir.first
end
get_service_types() click to toggle source

Get all configured service types (added through plat.servicetype) @return array of service types, empty array if none have been configured

# File lib/vanagon/platform.rb, line 593
def get_service_types
  if @servicetypes.any?
    @servicetypes.flat_map(&:servicetype).compact
  elsif @servicetype
    [@servicetype]
  else
    []
  end
end
is_aix?() click to toggle source

Utility matcher to determine is the platform is an aix variety

@return [true, false] true if it is an aix variety, false otherwise

# File lib/vanagon/platform.rb, line 407
def is_aix?
  return !!@name.match(/^aix-.*$/)
end
is_amazon?() click to toggle source

Utility matcher to determine is the platform is a amazon linux variety

@return [true, false] true if it is a amazon linux variety, false otherwise

# File lib/vanagon/platform.rb, line 386
def is_amazon?
  return !!@name.match(/^amazon-.*$/)
end
is_cisco_wrlinux?() click to toggle source

Utility matcher to determine is the platform is a cisco-wrlinux variety

@return [true, false] true if it is a cisco-wrlinux variety, false otherwise

# File lib/vanagon/platform.rb, line 430
def is_cisco_wrlinux?
  return !!@name.match(/^cisco-wrlinux-.*$/)
end
is_cross_compiled?() click to toggle source

Utility matcher to determine if the platform is a cross-compiled variety

@return [true, false] true if it is a cross-compiled variety, false otherwise

# File lib/vanagon/platform.rb, line 483
def is_cross_compiled?
  return @cross_compiled
end
is_cross_compiled_linux?() click to toggle source

Utility matcher to determine if the platform is a cross-compiled Linux variety. Many of the customizations needed to cross-compile for Linux are similar, so it’s useful to group them together vs. other cross-compiled OSes.

@return [true, false] true if it is a cross-compiled Linux variety, false otherwise

# File lib/vanagon/platform.rb, line 492
def is_cross_compiled_linux?
  is_cross_compiled? && is_linux?
end
is_deb?() click to toggle source

Utility matcher to determine is the platform is a debian variety

@return [true, false] true if it is a debian variety, false otherwise

# File lib/vanagon/platform.rb, line 335
def is_deb?
  return !!@name.match(/^(debian|ubuntu|cumulus|huaweios)-.*$/)
end
is_debian?() click to toggle source

Utility matcher to determine is the platform is a debian variety

@return [true, false] true if it is a debian variety, false otherwise

# File lib/vanagon/platform.rb, line 393
def is_debian?
  return !!@name.match(/^debian-.*$/)
end
is_el8?() click to toggle source

Utility matcher to determine if the platform is of an EL 8 variety

@return [true, false] true if it is an EL 8 variety, false otherwise

# File lib/vanagon/platform.rb, line 358
def is_el8?
  return !!@name.match(/^(el|redhat|redhatfips)-8.*$/)
end
is_el?() click to toggle source

Utility matcher to determine is the platform is an enterprise linux variety

@return [true, false] true if it is a enterprise linux variety, false otherwise

# File lib/vanagon/platform.rb, line 351
def is_el?
  return !!@name.match(/^(el|redhat|redhatfips)-.*$/)
end
is_eos?() click to toggle source

Utility matcher to determine is the platform is an eos variety

@return [true, false] true if it is an eos variety, false otherwise

# File lib/vanagon/platform.rb, line 414
def is_eos?
  return !!@name.match(/^eos-.*$/)
end
is_fedora?() click to toggle source

Utility matcher to determine is the platform is a fedora variety

@return [true, false] true if it is a fedora variety, false otherwise

# File lib/vanagon/platform.rb, line 379
def is_fedora?
  return !!@name.match(/^fedora-.*$/)
end
is_fips?() click to toggle source

Utility matcher to determine if the platform is a FIPS platform

@return [true, false] true if it is a FIPS platform, false otherwise

# File lib/vanagon/platform.rb, line 365
def is_fips?
  return @name.include?('fips')
end
is_huaweios?() click to toggle source

Utility matcher to determine is the platform is a HuaweiOS variety

@return [true, false] true if it is a HuaweiOS variety, false otherwise

# File lib/vanagon/platform.rb, line 421
def is_huaweios?
  return !!@name.match(/^huaweios-.*$/)
end
is_linux?() click to toggle source

Utility matcher to determine is the platform is a linux variety

@return [true, false] true if it is a linux variety, false otherwise

# File lib/vanagon/platform.rb, line 476
def is_linux?
  !is_windows? && !is_unix?
end
is_macos?() click to toggle source

Utility matcher to determine if the platform is a macos or osx variety is_osx is a deprecated method that calls is_macos We still match for osx currently but this will change

@return [true, false] true if it is a macos or osx variety, false otherwise

# File lib/vanagon/platform.rb, line 448
def is_macos?
  !!(@name =~ /^macos-.*$/ || @name =~ /^osx-.*$/)
end
is_osx?() click to toggle source

Utility matcher to determine if the platform is an osx variety

@deprecated Please use is_macos? instead @return [true, false] true if it is an osx variety, false otherwise

# File lib/vanagon/platform.rb, line 438
def is_osx?
  VanagonLogger.info "is_osx? is a deprecated method, please use #is_macos? instead."
  is_macos?
end
is_rpm?() click to toggle source

Utility matcher to determine is the platform is a redhat variety or uses rpm under the hood

@return [true, false] true if it is a redhat variety or uses rpm under the hood, false otherwise

# File lib/vanagon/platform.rb, line 344
def is_rpm?
  return !!@name.match(/^(aix|cisco-wrlinux|el|eos|fedora|sles|redhat|redhatfips)-.*$/)
end
is_sles?() click to toggle source

Utility matcher to determine is the platform is a sles variety

@return [true, false] true if it is a sles variety, false otherwise

# File lib/vanagon/platform.rb, line 372
def is_sles?
  return !!@name.match(/^sles-.*$/)
end
is_solaris?() click to toggle source

Utility matcher to determine is the platform is a solaris variety

@return [true, false] true if it is an solaris variety, false otherwise

# File lib/vanagon/platform.rb, line 455
def is_solaris?
  return !!@name.match(/^solaris-.*$/)
end
is_ubuntu?() click to toggle source

Utility matcher to determine is the platform is a ubuntu variety

@return [true, false] true if it is a ubuntu variety, false otherwise

# File lib/vanagon/platform.rb, line 400
def is_ubuntu?
  return !!@name.match(/^ubuntu-.*$/)
end
is_unix?() click to toggle source

Utility matcher to determine is the platform is a unix variety

@return [true, false] true if it is a unix variety, false otherwise

# File lib/vanagon/platform.rb, line 462
def is_unix?
  return !!@name.match(/^(solaris|aix|osx)-.*$/)
end
is_windows?() click to toggle source

Utility matcher to determine is the platform is a windows variety

@return [true, false] true if it is a windows variety, false otherwise

# File lib/vanagon/platform.rb, line 469
def is_windows?
  return !!@name.match(/^windows.*$/)
end
package_override(project, var) click to toggle source

Pass in a packaging override. This needs to be implemented for each individual platform so that this input ends up in the right place.

@param project @param var the string that should be added to the build script.

# File lib/vanagon/platform.rb, line 501
def package_override(project, var)
  fail "I don't know how to set package overrides for #{name}, teach me?"
end
provision_with(command) click to toggle source

Set the command to turn the target machine into a builder for vanagon

@param command [String] Command to enable the target machine to build packages for the platform

# File lib/vanagon/platform.rb, line 561
def provision_with(command)
  provisioning << command
  provisioning.flatten!
end
validate_operator(operator_string) click to toggle source
# File lib/vanagon/platform.rb, line 587
def validate_operator(operator_string)
  valid_operators.include?(operator_string)
end
version_munger(version_string, default: '=') click to toggle source

version strings for dependencies, conflicts, replaces, etc need some munging based on platform.

@param version_string operator(<,>,=,<=,>=) and version to be munged, like

'<1.2.3'

@param default [deprecated] default operator to use if version string doesn’t

contain an operator
# File lib/vanagon/platform.rb, line 573
def version_munger(version_string, default: '=')
  match = version_string.match(VERSION_REGEX)

  if match.nil?
    VanagonLogger.info "Passing a version without an operator is deprecated!"
    operator = default
    version = version_string
  end
  operator ||= match[1]
  version ||= match[2]
  fail "Operator '#{operator}' is invalid" unless validate_operator(operator)
  "#{operator} #{version}"
end