Created
February 5, 2016 20:12
-
-
Save sbotman/9289a0223f82831c8f59 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# file: /opt/opscode/embedded/service/opscode-erchef/lib/chef_objects-12.2.0/priv/depselector_rb/depselector.rb | |
# ensure that the Gemfile is in the cwd | |
Dir.chdir(File.dirname(__FILE__)) | |
require 'rubygems' | |
require 'bundler/setup' | |
require 'dep_selector' | |
require 'erlectricity' | |
require 'json' | |
require 'pp' | |
def log(comment) | |
file = "/var/tmp/ruby_sander" | |
File.open(file, 'a') { |file| file.write(Time.now.to_s + ": " + comment + "\n") } | |
end | |
def run_list_func(comment) | |
file = "/var/tmp/run_list" | |
File.open(file, 'w') { |file| file.write(comment) } | |
end | |
def data_func(comment) | |
file = "/var/tmp/data.json" | |
File.open(file, 'w') { |file| file.write(comment) } | |
end | |
def all_versions_func(comment) | |
file = "/var/tmp/all_versions" | |
File.open(file, 'w') { |file| file.write(comment) } | |
end | |
def translate_constraint(constraint) | |
case constraint | |
when Symbol | |
case constraint | |
when :gt then ">" | |
when :gte then ">=" | |
when :lt then "<" | |
when :lte then "<=" | |
when :eq then "=" | |
when :pes then "~>" | |
else constraint.to_s | |
end | |
when NilClass | |
"=" | |
else | |
constraint | |
end | |
end | |
def constraint_to_str(constraint, constraint_version) | |
return nil unless constraint_version | |
"#{translate_constraint(constraint)} #{constraint_version}" | |
end | |
receive do |m| | |
log("step0") | |
m.when([:get_pid]) do | |
m.send!(Process.pid) | |
m.receive_loop | |
end | |
m.when([:solve, Erl.hash]) do |data| | |
data_func(data.to_json) | |
begin | |
# create dependency graph from cookbooks | |
log("step1") | |
graph = DepSelector::DependencyGraph.new | |
env_constraints = data[:environment_constraints].inject({}) do |acc, env_constraint| | |
name, version, constraint = env_constraint | |
acc[name] = DepSelector::VersionConstraint.new(constraint_to_str(constraint, version)) | |
acc | |
end | |
all_versions = [] | |
data[:all_versions].each do | vsn| | |
name, version_constraints = vsn | |
version_constraints.each do |version_constraint| # todo: constraints become an array in ruby | |
# due to the erlectricity conversion from | |
# tuples | |
version, constraints = version_constraint | |
# filter versions based on environment constraints | |
env_constraint = env_constraints[name] | |
if (!env_constraint || env_constraint.include?(DepSelector::Version.new(version))) | |
package_version = graph.package(name).add_version(DepSelector::Version.new(version)) | |
constraints.each do |package_constraint| | |
constraint_name, constraint_version, constraint = package_constraint | |
version_constraint = DepSelector::VersionConstraint.new(constraint_to_str(constraint, constraint_version)) | |
dependency = DepSelector::Dependency.new(graph.package(constraint_name), version_constraint) | |
package_version.dependencies << dependency | |
end | |
end | |
end | |
# regardless of filter, add package reference to all_packages | |
all_versions << graph.package(name) | |
end | |
run_list = data[:run_list].map do |run_list_item| | |
item_name, item_constraint_version, item_constraint = run_list_item | |
version_constraint = DepSelector::VersionConstraint.new(constraint_to_str(item_constraint, | |
item_constraint_version)) | |
DepSelector::SolutionConstraint.new(graph.package(item_name), version_constraint) | |
end | |
log("step2") | |
timeout_ms = data[:timeout_ms] | |
selector = DepSelector::Selector.new(graph, (timeout_ms / 1000.0)) | |
log("step3") | |
answer = begin | |
log("step4") | |
#log("runlist1" + run_list.class.to_s) | |
run_list.each do |object| | |
#log("runlist item" + object.class.to_s + ":" + object.package.class.to_s + ":" + object.contraint.class.to_s) | |
log("runlist item" + object.class.to_s + ":" + object.package.name.to_s) | |
object.package.versions.each do |version| | |
log("gimme version: " + version.to_s) | |
end | |
end | |
all_versions.each do |object| | |
log("runlist item version" + object.name.to_s) | |
end | |
#log("runlist2" + all_versions.o_s) | |
solution = selector.find_solution(run_list, all_versions) | |
log("step4.5") | |
packages = Erl::List.new | |
log("step5") | |
solution.each do |package, v| | |
log ("step5.5") | |
packages << [package, [v.major, v.minor, v.patch]] | |
end | |
[:ok, packages] | |
log("step6") | |
rescue DepSelector::Exceptions::InvalidSolutionConstraints => e | |
non_existent_cookbooks = e.non_existent_packages.inject(Erl::List.new) do |list, constraint| | |
list << constraint.package.name | |
end | |
constrained_to_no_versions = e.constrained_to_no_versions.inject(Erl::List.new) do |list, constraint| | |
list << constraint.to_s | |
end | |
error_detail = Erl::List.new([[:non_existent_cookbooks, non_existent_cookbooks], | |
[:constraints_not_met, constrained_to_no_versions]]) | |
[:error, :invalid_constraints, error_detail] | |
rescue DepSelector::Exceptions::NoSolutionExists => e | |
most_constrained_cookbooks = e.disabled_most_constrained_packages.inject(Erl::List.new) do |list, package| | |
# WTF: this is the reported error format but I can't find this anywhere in the ruby code | |
list << "#{package.name} = #{package.versions.first.to_s}" | |
end | |
non_existent_cookbooks = e.disabled_non_existent_packages.inject(Erl::List.new) do |list, package| | |
list << package.name | |
end | |
error_detail = Erl::List.new([[:message, e.message], | |
[:unsatisfiable_run_list_item, e.unsatisfiable_solution_constraint.to_s], | |
[:non_existent_cookbooks, non_existent_cookbooks], | |
[:most_constrained_cookbooks, most_constrained_cookbooks]]) | |
[:error, :no_solution, error_detail] | |
rescue DepSelector::Exceptions::TimeBoundExceeded, | |
DepSelector::Exceptions::TimeBoundExceededNoSolution => e | |
# While dep_selector differentiates between the two solutions, the opscode-chef | |
# API returns the same error regardless of the timeout type. We'll swallow the | |
# difference here and return a unified timeout to erchef | |
[:error, :resolution_timeout] | |
end | |
m.send!(answer) | |
m.receive_loop | |
rescue => e | |
answer = [:error, :exception, e.message, Erl::List.new(e.backtrace)] | |
m.send!(answer) | |
m.receive_loop | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment