lib/logical-construct/ground-control/provision.rb in logical-construct-0.0.1.localtesting vs lib/logical-construct/ground-control/provision.rb in logical-construct-0.0.1
- old
+ new
@@ -1,70 +1,187 @@
require 'mattock'
-require 'rake/packagetask'
+require 'json'
+require 'logical-construct/resolving-task'
module LogicalConstruct
module GroundControl
class Provision < Mattock::Tasklib
class WebConfigure < Mattock::Task
- setting :target_ipaddr, nil
- setting :web_port, 51076
+ include ResolutionProtocol
+
+ setting :target_protocol, "http"
+ setting :target_address, nil
+ setting :target_port, 51076
+ runtime_setting :target_url
setting :resolutions, {}
+ runtime_setting :web_resolutions
- def action
- connection = Excon.new(target_address)
- index = connection.get
- body = Nokogiri::HTML(index.body)
- resolution_needed = body.xpath('//a[@href]')
- resolution_needed.each do |link|
- href = link['href']
- connection.post(href, {"data" => resolve(href)})
- end
+ def resolve_runtime_configuration
+ super
+ self.target_url ||= "#{target_protocol}://#{target_address}:#{target_port}/"
+ self.web_resolutions = Hash[resolutions.map do |name, value|
+ [web_path(name), value]
+ end]
end
def resolve(path)
- resolved = resolutions.fetch(path)
+ resolved = web_resolutions.fetch(path)
if resolved.respond_to? :call
resolved = resolved.call
end
return resolved
+ rescue KeyError
+ puts "Can't find a resolution for #{path} in #{web_resolutions.keys.inspect} (ex #{resolutions.keys})"
+ raise
end
+
+ def uri(options)
+ uri_class = URI.scheme_list[target_protocol.upcase]
+ uri_hash = {:host => target_address, :port => target_port}
+ return uri_class.build(uri_hash.merge(options)).to_s
+ end
+
+ def resolution_needed
+ index = RestClient.get(uri(:path => '/'))
+ body = Nokogiri::HTML(index.body)
+ return body.xpath("//a[@rel='requirement']")
+ end
+
+
+ #XXX I would like this to become an actual RESTful client at some
+ #point, but seems it would mean building it from scratch
+ def action
+ require 'uri'
+ require 'rest-client'
+ require 'nokogiri'
+
+ until (link = resolution_needed.first).nil?
+ href = link['href']
+ begin
+ response = RestClient.post(uri(:path => href), :data => resolve(href))
+ rescue RestClient::InternalServerError => ex
+ require 'tempfile'
+ file = Tempfile.open('provision-error.html')
+ path = file.path
+ file.close!
+
+ File::open(path, "w") do |file|
+ file.write ex.http_body
+ end
+ puts "Written error response to #{path}"
+ puts "Try: chromium #{path}"
+ fail "Unsuccessful response from server!"
+ end
+ end
+ end
end
default_namespace :provision
setting :valise
- setting :web_port, 51076
- setting :target_ipaddr, nil
+ setting :target_protocol, "http"
+ setting(:target_address, nil).isnt(:copiable)
+ setting :target_port, 51076
setting :resolutions, {}
- setting :marshalling_path
- setting :cookbooks_path
+ setting :marshalling_path, "marshall"
+ setting(:secret_data, nested {
+ setting :path
+ setting :tarball_path
+ setting :file_list
+ })
+
+ setting(:normal_data, nested {
+ setting :path
+ setting :tarball_path
+ setting :file_list
+ })
+
+ setting(:cookbooks, nested {
+ setting :path
+ setting :tarball_path
+ setting :file_list
+ })
+
+ setting :json_attribs_path
+ setting :roles, {}
+ setting :node_attribs, { "run_list" => [] }
+ setting :json_attribs, ""
+
def default_configuration(core)
core.copy_settings_to(self)
super
+ self.cookbooks.path = "cookbooks"
+ self.secret_data.path = "data-bags/secret"
+ self.normal_data.path = "data-bags"
end
+ def resolve_configuration
+ super
+ self.json_attribs_path ||= File::join(marshalling_path, "node.json")
+
+ self.cookbooks.file_list ||= Rake::FileList[cookbooks.path + "/**/*"].exclude(%r{/[.]git/}).exclude(%r{[.]sw[.]$})
+ self.secret_data.file_list ||= Rake::FileList[secret_data.path + "/**/*"].exclude(%r{[.]sw[.]$})
+ self.normal_data.file_list ||=
+ Rake::FileList[normal_data.path + "/**/*"].exclude(%r{^#{secret_data.path}}).exclude(%r{[.]sw[.]$})
+
+ self.cookbooks.tarball_path ||= File::join(marshalling_path, "cookbooks.tgz")
+ self.secret_data.tarball_path ||= File::join(marshalling_path, "secret_data_bags.tgz")
+ self.normal_data.tarball_path ||= File::join(marshalling_path, "normal_data_bags.tgz")
+
+ resolutions["chef_config:cookbook_tarball"] ||= proc do
+ File::open(cookbooks.tarball_path, "rb")
+ end
+
+ resolutions["chef_config:secret_data_tarball"] ||= proc do
+ File::open(secret_data.tarball_path, "rb")
+ end
+
+ resolutions["chef_config:normal_data_tarball"] ||= proc do
+ File::open(normal_data.tarball_path, "rb")
+ end
+ end
+
+ include Mattock::CommandLineDSL
def define
in_namespace do
- task :collect, [:ipaddr] do |task, args|
- self.target_ipaddr = args[:ipaddr]
+ directory marshalling_path
+
+ task :collect, [:ipaddr, :role] do |task, args|
+ self.target_address = args[:ipaddr]
+ unless args[:role].nil?
+ self.node_attribs["run_list"] = roles[args[:role]]
+ end
+ self.json_attribs = JSON.pretty_generate(node_attribs)
+ resolutions["chef_config:json_attribs"] ||= json_attribs
end
- WebConfigure.new(:web_configure => :collect) do |task|
- self.copy_settings_to(task)
+ file secret_data.tarball_path => [marshalling_path] + secret_data.file_list do
+ cmd("tar", "--exclude **/*.sw?", "-czf", secret_data.tarball_path, secret_data.path).must_succeed!
end
- namespace :cookbook do
- Rake::PackageTask.new("cookbook", :noversion) do |task|
- task.need_tar_gz = true
- task.package_dir = marshalling_path
- task.package_files.include(cookbooks_path + "/**/*")
- end
+ file normal_data.tarball_path => [marshalling_path] + normal_data.file_list do
+ cmd("tar",
+ "--exclude **/*.sw?",
+ "--exclude #{secret_data.path}",
+ "-czf", normal_data.tarball_path, normal_data.path).must_succeed!
end
- end
- task root_task, [:ipaddr] => :web_configure
+ file cookbooks.tarball_path => [marshalling_path] + cookbooks.file_list do
+ cmd("tar", "--exclude .git", "--exclude **/*.sw?", "-czf", cookbooks.tarball_path, cookbooks.path).must_succeed!
+ end
+ manifest = LogicalConstruct::GenerateManifest.new(self, :manifest => [cookbooks.tarball_path, :collect]) do |manifest|
+ manifest.receiving_name = "configuration:Manifest"
+ end
+
+ WebConfigure.new(:web_configure => [:collect, :manifest, cookbooks.tarball_path]) do |task|
+ self.proxy_settings_to(task)
+ task.target_address = proxy_value.target_address
+ end
+ end
+
+ task root_task, [:ipaddr] => self[:web_configure]
end
end
end
end