Singleton to provide management of cartridges installed on the system
FIXME: move to node.conf
Filesystem path to where cartridges are installed
Instantiate a cartridge in a gear;
If the cartridge manifest_path is :url then source_url is used to obtain cartridge source Otherwise the cartridge source is copied from the cartridge_repository source_hash is used to ensure the download was successful. CartridgeRepository.instantiate_cartridge(perl_cartridge, '/var/lib/.../mock') => nil
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 365 def self.instantiate_cartridge(cartridge, target, failure_remove = true) FileUtils.mkpath target if :url == cartridge.manifest_path downloadable = true end if downloadable uri = URI(cartridge.source_url) temporary = PathUtils.join(File.dirname(target), File.basename(cartridge.source_url)) cartridge.validate_vendor_name cartridge.check_reserved_vendor_name cartridge.validate_cartridge_name case when 'git' == uri.scheme || cartridge.source_url.end_with?('.git') Utils::oo_spawn(%Q(set -xe; git clone #{cartridge.source_url} #{cartridge.name}; GIT_DIR=./#{cartridge.name}/.git git repack), chdir: Pathname.new(target).parent.to_path, expected_exitstatus: 0) when uri.scheme =~ /^https*/ && cartridge.source_url =~ /\.zip/ begin uri_copy(URI(cartridge.source_url), temporary, cartridge.source_md5) extract(:zip, temporary, target) ensure FileUtils.rm(temporary) end when uri.scheme =~ /^https*/ && cartridge.source_url =~ /(\.tar\.gz|\.tgz)$/ begin uri_copy(URI(cartridge.source_url), temporary, cartridge.source_md5) extract(:tgz, temporary, target) ensure FileUtils.rm(temporary) end when uri.scheme =~ /^https*/ && cartridge.source_url =~ /\.tar$/ begin uri_copy(URI(cartridge.source_url), temporary, cartridge.source_md5) extract(:tar, temporary, target) ensure FileUtils.rm(temporary) end when 'file' == uri.scheme entries = Dir.glob(PathUtils.join(uri.path, '*'), File::FNM_DOTMATCH) filesystem_copy(entries, target, %w(. ..)) else raise ArgumentError.new("CLIENT_ERROR: Unsupported URL(#{cartridge.source_url}) for downloading a private cartridge") end else entries = Dir.glob(PathUtils.join(cartridge.repository_path, '*'), File::FNM_DOTMATCH) filesystem_copy(entries, target, %w(. .. usr)) source_usr = PathUtils.join(cartridge.repository_path, 'usr') target_usr = PathUtils.join(target, 'usr') FileUtils.rm(target_usr) if File.symlink?(target_usr) FileUtils.symlink(source_usr, target_usr) if File.exist?(source_usr) && !File.exist?(target_usr) end valid_cartridge_home(cartridge, target) if downloadable manifest_on_disk = PathUtils.join(target, %w(metadata manifest.yml)) IO.write(manifest_on_disk, YAML.dump(cartridge.manifest)) end rescue => e FileUtils.rm_rf target if failure_remove raise e end
Overlay new code over existing cartridge in a gear;
If the cartridge manifest_path is :url then source_url is used to obtain cartridge source Otherwise the cartridge source is copied from the cartridge_repository source_hash is used to ensure the download was successful. CartridgeRepository.overlay_cartridge(perl_cartridge, '/var/lib/.../mock') => nil
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 351 def self.overlay_cartridge(cartridge, target) instantiate_cartridge(cartridge, target, false) end
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 489 def self.extract(method, source, target) case method when :zip Utils.oo_spawn("/usr/bin/unzip -d #{target} #{source}", expected_exitstatus: 0) when :tgz Utils.oo_spawn("/bin/tar -C #{target} -zxpf #{source}", expected_exitstatus: 0) when :tar Utils.oo_spawn("/bin/tar -C #{target} -xpf #{source}", expected_exitstatus: 0) else raise "Packaging method #{method} not yet supported." end files = Dir.glob(PathUtils.join(target, '*')) if 1 == files.size # A directory of one file is not legal move everyone up a level (github zip's are this way) to_delete = files.first + '.to_delete' File.rename(files.first, to_delete) entries = Dir.glob(PathUtils.join(to_delete, '*'), File::FNM_DOTMATCH).delete_if do |e| %w(. ..).include? File.basename(e) end FileUtils.move(entries, target) FileUtils.rm_rf(to_delete) end end
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 478 def self.filesystem_copy(entries, target, black_list) entries.delete_if do |e| black_list.include? File.basename(e) end raise ArgumentError.new('CLIENT_ERROR: No cartridge sources found to install.') if entries.empty? Utils.oo_spawn("/bin/cp -ad #{entries.join(' ')} #{target}", expected_exitstatus: 0) end
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 442 def self.uri_copy(uri, temporary, md5 = nil) content_length = nil File.open(temporary, 'w') do |output| uri.open(ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE, content_length_proc: lambda { |l| content_length = l } ) do |input| input.meta begin total = 0 while true partial = input.readpartial(4096) total += output.write partial if content_length && content_length < total raise Net::HTTPBadResponse.new("CLIENT_ERROR: Download of '#{uri}' exceeded Content-Length of #{content_length}. Download aborted.") end end rescue EOFError # we are done end end end if content_length && content_length != File.size(temporary) raise Net::HTTPBadResponse.new( "CLIENT_ERROR: Download of '#{uri}' failed, expected Content-Length of #{content_length} received #{File.size(temporary)}") end if md5 digest = Digest::MD5.file(temporary).hexdigest if digest != md5 raise IOError.new("CLIENT_ERROR: Failed to download cartridge, checksum failed: #{md5} expected, #{digest} actual") end end end
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 521 def self.valid_cartridge_home(cartridge, path) errors = [] [ [File, :directory?, %w(metadata)], [File, :directory?, %w(bin)], [File, :file?, %w(metadata manifest.yml)] ].each do |clazz, method, target| relative = PathUtils.join(target) absolute = PathUtils.join(path, relative) unless clazz.method(method).(absolute) errors << "#{relative} is not #{method}" end end unless errors.empty? raise MalformedCartridgeError.new( "CLIENT_ERROR: Malformed cartridge (#{cartridge.name}, #{cartridge.version}, #{cartridge.cartridge_version})", errors ) end end
Clear all entries from the memory index. Nothing is removed from the disk.
CartridgeRepository.instance.clear #=> nil
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 105 def clear @index = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) } end
Process each unique cartridge
CartridgeRepository.instance.each {|c| puts c.name}
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 291 def each return to_enum(:each) unless block_given? cartridges = Set.new @index.each_pair do |_, sw_hash| sw_hash.each_pair do |_, cart_hash| cart_hash.each_pair do |_, cartridge| cartridges.add(cartridge) end end end cartridges.each { |c| yield c } self end
Erase given version of a cartridge from the cartridge repository and remove from index. This cannot be undone.
CartridgeRepository.instance.erase('php', '3.5', '1.0') #=> Cartridge
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 197 def erase(cartridge_name, version, cartridge_version) unless exist?(cartridge_name, cartridge_version, version) raise KeyError.new("key not found: (#{cartridge_name}, #{version}, #{cartridge_version})") end entry = nil $OpenShift_CartridgeRepository_SEMAPHORE.synchronize do # find a "template" entry entry = select(cartridge_name, version, cartridge_version) # Now go back and find all occurrences of the "template" @index[cartridge_name].each_key do |k2| @index[cartridge_name][k2].each_pair do |k3, v3| if v3.eql?(entry) remove(cartridge_name, k2, k3) end end end FileUtils.rm_r(entry.repository_path) parent = Pathname.new(entry.repository_path).parent FileUtils.rm_r(parent) if 0 == parent.children.count end entry end
Is there an entry in the repository for this tuple?
CartridgeRepository.instance.erase('cobol', '2002', '1.0') #=> false
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 230 def exist?(cartridge_name, cartridge_version, version) @index.key?(cartridge_name) && @index[cartridge_name].key?(version) && @index[cartridge_name][version].key?(cartridge_version) end
print out all index entries in a table
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 324 def inspect @index.inject("<CartridgeRepository:\n") do |memo, (name, sw_hash)| sw_hash.inject(memo) do |memo, (sw_ver, cart_hash)| cart_hash.inject(memo) do |memo, (cart_ver, cartridge)| memo << "(#{name}, #{sw_ver}, #{cart_ver}): " << cartridge.to_s << "\n" end end << '>' end end
Copies a cartridge's source into the cartridge repository from a
directory
. The Cartridge will additionally be indexed and
available from a CartridgeRepository.instance
CartridgeRepository.instance.install('/usr/libexec/openshift/cartridges/openshift-origin-php') #=> Cartridge
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 171 def install(directory) raise ArgumentError.new("Illegal path to cartridge source: '#{directory}'") unless directory && File.directory?(directory) raise ArgumentError.new("Source cannot be: '#{@path}'") if directory == @path manifest_path = PathUtils.join(directory, 'metadata', 'manifest.yml') raise ArgumentError.new("Cartridge manifest.yml missing: '#{manifest_path}'") unless File.file?(manifest_path) entry = nil $OpenShift_CartridgeRepository_SEMAPHORE.synchronize do entry = insert(Manifest.new(manifest_path, nil, @path)) FileUtils.rm_r(entry.repository_path) if File.exist?(entry.repository_path) FileUtils.mkpath(entry.repository_path) Utils.oo_spawn("shopt -s dotglob; /bin/cp -ad #{directory}/* #{entry.repository_path}", expected_exitstatus: 0) end entry end
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 307 def latest_versions cartridges = Set.new @index.each_pair do |_, sw_hash| sw_hash.each_pair do |_, cart_version_hash| latest_version = Manifest.sort_versions(cart_version_hash.keys).last.to_s cartridges.add(cart_version_hash[latest_version]) unless cart_version_hash[latest_version].instance_of?(Hash) end end if block_given? cartridges.each { |c| yield c } end cartridges end
Read cartridge manifests from the CARTRIDGE_REPO_DIR
or the provided directory
.
CartridgeRepository.instance.load("/var/lib/openshift/.cartridge_repository") #=> 24
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 115 def load(directory = nil) $OpenShift_CartridgeRepository_SEMAPHORE.synchronize do load_via_url = directory.nil? find_manifests(directory || @path) do |manifest_path| logger.debug { "Loading cartridge from #{manifest_path}" } # we check the vendor and cartridge names only when loading via URL c = insert(Manifest.new(manifest_path, nil, @path, load_via_url)) logger.debug { "Loaded cartridge (#{c.name}, #{c.version}, #{c.cartridge_version})" } end end count end
Select a cartridge from repository
Each version parameter you provide narrows the search to the exact revision of the Cartridge you are requesting. If you do not provide cartridge_version then the latest is assumed, for version and cartridge_name. If you do not provide cartridge_version and version, then the latest cartridge_name will be returned.
Latest is determined from the Version elements provided in the cartridge's manifest, when the cartridge is loaded.
Assuming PHP, 3.5 and 0.1 are all the latest each of these calls would return the same cartridge.
CartridgeRepository.instance.select('php', '3.5', '0.1') #=> Cartridge CartridgeRepository.instance.select('php', '3.5') #=> Cartridge CartridgeRepository.instance.select('php') #=> Cartridge CartridgeRepository.instance['php', '3.5', '0.1'] #=> Cartridge CartridgeRepository.instance['php', '3.5'] #=> Cartridge CartridgeRepository.instance['php'] #=> Cartridge
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 154 def select(cartridge_name, version = '_', cartridge_version = '_') unless exist?(cartridge_name, cartridge_version, version) raise KeyError.new("key not found: (#{cartridge_name}, #{version}, #{cartridge_version})") end @index[cartridge_name][version][cartridge_version] end
print out all indexed cartridges in a table
# File lib/openshift-origin-node/model/cartridge_repository.rb, line 335 def to_s each_with_object("") do |c, memo| memo << "(#{c.cartridge_vendor}, #{c.name}, #{c.version}, #{c.cartridge_version})\n" end end