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
Always-Be-Scheduling engine specific
AWS engine specific
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.
Hardware engine specific
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.
Each of these holds the path or name of the command in question, e.g. ‘copy = “/usr/local/bin/gcp”`, or `copy = “cp”`
Determines if a platform should be treated as cross-compiled or natively compiled.
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.
Docker engine specific
The overall {Vanagon::Environment} that a given platform should pass to each component
Basic generic information related to a given instance of Platform
. e.g. The name we call it, the platform triplet (name-version-arch), etc.
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.
Stores the local path where retrieved artifacts will be saved.
The name of the sort of package type that a given platform expects, e.g. msi, rpm,
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
Where does a given platform expect to find init scripts/service files? e.g. /etc/init.d, /usr/lib/systemd/system
The name of the sort of init system that a given platform uses
Array of OpenStructs containing the servicetype and the corresponding servicedir
Freeform Hash of leftover settings
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.
Stores the local path where source artifacts will be saved.
Generic engine
Username to use when connecting to a build target
VMpooler engine specific
Public Class Methods
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
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
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
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
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
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
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
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 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 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
# File lib/vanagon/platform.rb, line 587 def validate_operator(operator_string) valid_operators.include?(operator_string) end
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