logical-construct 0.0.1.localtesting

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/lib/logical-construct/ground-control.rb +3 -0
  2. data/lib/logical-construct/ground-control/core.rb +33 -0
  3. data/lib/logical-construct/ground-control/provision.rb +70 -0
  4. data/lib/logical-construct/ground-control/run-on-target.rb +32 -0
  5. data/lib/logical-construct/ground-control/setup.rb +57 -0
  6. data/lib/logical-construct/ground-control/setup/build-files.rb +64 -0
  7. data/lib/logical-construct/ground-control/setup/bundle-setup.rb +36 -0
  8. data/lib/logical-construct/ground-control/setup/copy-files.rb +66 -0
  9. data/lib/logical-construct/ground-control/setup/create-construct-directory.rb +21 -0
  10. data/lib/logical-construct/ground-control/setup/ensure-env.rb +15 -0
  11. data/lib/logical-construct/resolving-task.rb +38 -0
  12. data/lib/logical-construct/satisfiable-task.rb +64 -0
  13. data/lib/logical-construct/target.rb +4 -0
  14. data/lib/logical-construct/target/chef-solo.rb +40 -0
  15. data/lib/logical-construct/target/platforms.rb +51 -0
  16. data/lib/logical-construct/target/platforms/aws.rb +8 -0
  17. data/lib/logical-construct/target/platforms/default/chef-config.rb +89 -0
  18. data/lib/logical-construct/target/platforms/default/resolve-configuration.rb +25 -0
  19. data/lib/logical-construct/target/platforms/default/volume.rb +11 -0
  20. data/lib/logical-construct/target/platforms/virtualbox.rb +8 -0
  21. data/lib/logical-construct/target/platforms/virtualbox/volume.rb +15 -0
  22. data/lib/logical-construct/target/provision.rb +26 -0
  23. data/lib/logical-construct/target/sinatra-resolver.rb +102 -0
  24. data/lib/logical-construct/target/unpack-cookbook.rb +40 -0
  25. data/lib/logical-construct/testing/resolve-configuration.rb +24 -0
  26. data/lib/logical-construct/testing/resolving-task.rb +15 -0
  27. data/lib/templates/Gemfile.erb +3 -0
  28. data/lib/templates/Rakefile.erb +14 -0
  29. data/lib/templates/chef.rb.erb +4 -0
  30. data/lib/templates/resolver/finished.html.erb +1 -0
  31. data/lib/templates/resolver/index.html.erb +8 -0
  32. data/lib/templates/resolver/task-form.html.erb +6 -0
  33. data/spec/target/chef-config.rb +64 -0
  34. data/spec/target/chef-solo.rb +47 -0
  35. data/spec/target/platforms.rb +36 -0
  36. data/spec_help/file-sandbox.rb +164 -0
  37. data/spec_help/gem_test_suite.rb +17 -0
  38. data/spec_help/mock-resolve.rb +21 -0
  39. data/spec_help/spec_helper.rb +13 -0
  40. data/spec_help/ungemmer.rb +36 -0
  41. metadata +131 -0
@@ -0,0 +1,64 @@
1
+ require 'mattock/task'
2
+
3
+ module LogicalConstruct
4
+ #This task won't kill the run if it fails - the assumption is that there's a
5
+ #ResolvingTask that depends on this task to make it work.
6
+ #
7
+ #Based on my reasoning about Rake (c.f. ResolvingTask):
8
+ # Each ST should have a configured #needed? that checks it's responsibility
9
+ # Execute needs to catch errors
10
+ class SatisfiableTask < Rake::Task
11
+ include Mattock::TaskMixin
12
+
13
+ def execute(args=nil)
14
+ super
15
+ if application.options.trace and needed?
16
+ $stderr.puts "** Unsatisfied: #{name}"
17
+ end
18
+ rescue Object => ex
19
+ warn "#{ex.class}: #{ex.message} while performing #{name}"
20
+ #Swallowed
21
+ end
22
+
23
+ def receive(data)
24
+ return unless needed?
25
+ fulfill(data)
26
+ end
27
+
28
+ def fulfill(string)
29
+ end
30
+
31
+ def needed?
32
+ return !criteria(self)
33
+ end
34
+
35
+ def criteria(me)
36
+ end
37
+ end
38
+
39
+ class SatisfiableFileTask < SatisfiableTask
40
+ setting :target_path
41
+
42
+ def criteria(task)
43
+ File::exists?(target_path)
44
+ end
45
+
46
+ def fulfill(string)
47
+ File::open(target_path, "w") do |file|
48
+ file.write(string)
49
+ end
50
+ end
51
+ end
52
+
53
+ class SatisfiableEnvTask < SatisfiableTask
54
+ setting :target_name
55
+
56
+ def criteria(task)
57
+ ENV.has_key?(target_name)
58
+ end
59
+
60
+ def fulfill(string)
61
+ ENV[target_name] = string
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,4 @@
1
+ require 'logical-construct/target/platforms'
2
+ require 'logical-construct/target/provision'
3
+ require 'logical-construct/target/chef-solo'
4
+ require 'logical-construct/target/unpack-cookbook'
@@ -0,0 +1,40 @@
1
+ require 'mattock/tasklib'
2
+
3
+ module LogicalConstruct
4
+ class ChefSolo < Mattock::TaskLib
5
+ default_namespace :chef_solo
6
+
7
+ settings(
8
+ :chef_solo_bin => "chef-solo",
9
+ :config_file => "/etc/chef/solo.rb",
10
+ :daemonize => nil,
11
+ :user => nil,
12
+ :group => nil,
13
+ :node_name => nil
14
+ )
15
+
16
+ def default_configuration(chef_config)
17
+ self.config_file = chef_config.solo_rb
18
+ end
19
+
20
+ def chef_command
21
+ Mattock::CommandLine.new(chef_solo_bin) do |cmd|
22
+ cmd.options << "--config #{config_file}" unless config_file.nil?
23
+ cmd.options << "--daemonize" if daemonize
24
+ cmd.options << "--user #{user}" if user
25
+ cmd.options << "--group #{group}" if group
26
+ cmd.options << "--node_name #{node_name}" if node_name
27
+ end
28
+ end
29
+
30
+ def define
31
+ in_namespace do
32
+ file config_file
33
+ task :run => [config_file] do
34
+ chef_command.run
35
+ end
36
+ end
37
+ task :provision => self[:run]
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,51 @@
1
+ module LogicalConstruct
2
+ def self.platforms
3
+ @platforms ||= {}
4
+ end
5
+
6
+ def self.register_platform(mod)
7
+ name = mod.name.split('::').last
8
+ platforms[name] = mod
9
+ end
10
+
11
+ def self.require_platform_files(platform, mod = nil)
12
+ [
13
+ ['volume', :Volume],
14
+ ['chef-config', :ChefConfig],
15
+ ['resolve-configuration', :ResolveConfiguration],
16
+ ].each do |file, classname|
17
+ begin
18
+ require File::join('logical-construct', 'target', 'platforms', platform, file)
19
+ rescue LoadError
20
+ raise if mod.nil?
21
+ klass = Class.new(LogicalConstruct::Default.const_get(classname))
22
+ mod.const_set(classname, klass)
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.Platform(explicit = nil)
28
+ name = explicit || $DEPLOYMENT_PLATFORM || ENV['LOGCON_DEPLOYMENT_PLATFORM']
29
+ return platforms.fetch(name)
30
+ rescue KeyError
31
+ puts "Cannot find platform specified:"
32
+ puts " explicit argument: #{explicit.inspect}"
33
+ puts " $DEPLOYMENT_PLATFORM: #{$DEPLOYMENT_PLATFORM.inspect}"
34
+ puts " ENV['LOGCON_DEPLOYMENT_PLATFORM']: #{ENV['LOGCON_DEPLOYMENT_PLATFORM'].inspect}"
35
+ puts " available: #{platforms.keys.inspect}"
36
+ puts
37
+ raise
38
+ end
39
+
40
+ module PlatformSpecific
41
+ def register_platform(name)
42
+ LogicalConstruct.register_platform(self)
43
+ LogicalConstruct.require_platform_files(name, self)
44
+ end
45
+ end
46
+
47
+ require_platform_files('default')
48
+ end
49
+
50
+ require 'logical-construct/target/platforms/virtualbox'
51
+ require 'logical-construct/target/platforms/aws'
@@ -0,0 +1,8 @@
1
+ require 'logical-construct/target/platforms'
2
+
3
+ module LogicalConstruct
4
+ module AWS
5
+ extend PlatformSpecific
6
+ register_platform('aws')
7
+ end
8
+ end
@@ -0,0 +1,89 @@
1
+ require 'mattock/tasklib'
2
+ require 'mattock/template-host'
3
+ require 'logical-construct/satisfiable-task'
4
+
5
+ module LogicalConstruct
6
+ module Default
7
+ class ChefConfig < Mattock::Tasklib
8
+ include Mattock::TemplateHost
9
+ default_namespace :chef_config
10
+
11
+ required_field :construct_dir
12
+ required_fields :file_cache_path, :cookbook_path, :cookbook_tarball_path, :json_attribs
13
+ required_field :valise
14
+ settings :solo_rb => "/etc/chef/solo.rb",
15
+ :cookbook_relpath => "cookbooks",
16
+ :cookbook_tarball_relpath => "cookbooks.tgz",
17
+ :json_attribs_relpath => "node.json"
18
+
19
+ setting :resolution_task
20
+
21
+ nil_fields :recipe_url, :role_path, :role_relpath
22
+
23
+ def default_configuration(provision, resolution)
24
+ super
25
+ self.construct_dir = provision.construct_dir
26
+ self.valise = provision.valise
27
+ self.resolution_task = resolution[:resolve]
28
+ end
29
+
30
+ def resolve_configuration
31
+ if unset?(file_cache_path)
32
+ self.file_cache_path = File::expand_path('chef', construct_dir)
33
+ end
34
+
35
+ self.file_cache_path = File::expand_path(file_cache_path)
36
+ if unset?(cookbook_path) and !cookbook_relpath.nil?
37
+ self.cookbook_path = File::expand_path(cookbook_relpath, file_cache_path)
38
+ end
39
+
40
+ if unset?(cookbook_tarball_path) and !cookbook_tarball_relpath.nil?
41
+ self.cookbook_tarball_path = File::expand_path(cookbook_tarball_relpath, file_cache_path)
42
+ end
43
+
44
+ self.solo_rb = File::expand_path(solo_rb, file_cache_path)
45
+
46
+ if unset?(json_attribs) and !json_attribs_relpath.nil?
47
+ self.json_attribs = File::expand_path(json_attribs_relpath, file_cache_path)
48
+ end
49
+
50
+ if role_path.nil? and !role_relpath.nil?
51
+ self.role_path = File::expand_path(role_relpath, file_cache_path)
52
+ end
53
+ super
54
+ end
55
+
56
+ def define
57
+ in_namespace do
58
+ directory file_cache_path
59
+
60
+ Mattock::CommandTask.new(:unpack_cookbooks => :cookbook_tarball) do |task|
61
+ task.command = Mattock::CommandLine.new("tar", "-xzf", cookbook_tarball_path)
62
+ end
63
+
64
+ file solo_rb => [:unpack_cookbooks, :json_attribs, file_cache_path, resolution_task] do
65
+ File::open(solo_rb, "w") do |file|
66
+ file.write(render("chef.rb.erb"))
67
+ end
68
+ end
69
+
70
+ SatisfiableFileTask.new(:json_attribs => file_cache_path) do |task|
71
+ task.target_path = json_attribs
72
+ end
73
+
74
+ SatisfiableFileTask.new(:cookbook_tarball => file_cache_path) do |task|
75
+ task.target_path = cookbook_tarball_path
76
+ end
77
+
78
+ unless role_path.nil?
79
+ directory role_path
80
+ file solo_rb => role_path
81
+ end
82
+ end
83
+
84
+ task resolution_task => self[:cookbook_tarball]
85
+ task resolution_task => self[:json_attribs]
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,25 @@
1
+ require 'logical-construct/target/sinatra-resolver'
2
+ module LogicalConstruct
3
+ module Default
4
+ class ResolveConfiguration < Mattock::Tasklib
5
+ default_namespace 'configuration'
6
+
7
+ setting :bind, '0.0.0.0'
8
+ setting :port, 51076
9
+ setting :valise
10
+
11
+ def default_configuration(provision)
12
+ self.valise = provision.valise
13
+ end
14
+
15
+ def define
16
+ in_namespace do
17
+ resolver = LogicalConstruct::SinatraResolver.new do |task|
18
+ task.task_name = "resolve"
19
+ end
20
+ copy_settings_to(resolver)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ require 'mattock/tasklib'
2
+
3
+ module LogicalConstruct
4
+ module Default
5
+ class Volume < Mattock::Tasklib
6
+ def define
7
+
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ require 'logical-construct/target/platforms'
2
+
3
+ module LogicalConstruct
4
+ module VirtualBox
5
+ extend PlatformSpecific
6
+ register_platform('virtualbox')
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ require 'logical-construct/target/platforms/virtualbox'
2
+
3
+ module LogicalConstruct
4
+ module VirtualBox
5
+ class Volume < Default::Volume
6
+ def define
7
+ Mattock::CommandTask.new(self) do |task|
8
+ task.command = Mattock::CommandLine.new("mount") do |mount|
9
+ mount.options = [device, mountpoint]
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ require 'mattock'
2
+ require 'mattock/template-host'
3
+
4
+ module LogicalConstruct
5
+ class Provision < Mattock::Tasklib
6
+ include Mattock::ValiseManager
7
+ extend Mattock::ValiseManager
8
+
9
+ settings(
10
+ :construct_dir => "/var/logical-construct",
11
+ :attr_source => nil,
12
+ :config_path => nil
13
+ )
14
+ setting :valise
15
+ setting :search_paths, [rel_dir(__FILE__)]
16
+
17
+ def resolve_configuration
18
+ self.valise = default_valise(search_paths)
19
+ super
20
+ end
21
+
22
+ def define
23
+ task_spine(:preflight, :approve_host, :build_configs, :provision)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,102 @@
1
+ require 'logical-construct/resolving-task'
2
+ require 'mattock/task'
3
+ require 'mattock/template-host'
4
+ require 'sinatra'
5
+
6
+ module LogicalConstruct
7
+ class SinatraResolver < ResolvingTask
8
+ include Mattock::TemplateHost
9
+
10
+ def web_path(task)
11
+ "/" + task.name.gsub(":", "/")
12
+ end
13
+
14
+ def build_collector(resolver, prereqs)
15
+ klass = Class.new(Sinatra::Application) do
16
+ class << self
17
+ attr_accessor :running_server
18
+ end
19
+
20
+ set :show_exceptions => true
21
+
22
+ get '/' do
23
+ resolver.render('resolver/index.html.erb')
24
+ end
25
+
26
+ prereqs.each do |task|
27
+ path = resolver.web_path(task)
28
+
29
+ get path do
30
+ resolver.render('resolver/task-form.html.erb') do |locals|
31
+ locals[:task_path] = path
32
+ end
33
+ end
34
+
35
+ post path do
36
+ task.fulfill(request.params["data"])
37
+ if resolver.needed?
38
+ redirect to("/")
39
+ else
40
+ resolver.render('resolver/finished.html.erb')
41
+ quit!
42
+ end
43
+ end
44
+
45
+ put path do
46
+ request.body.rewind
47
+ task.fulfill(request.body.read)
48
+ if resolver.needed?
49
+ redirect to("/")
50
+ else
51
+ resolver.render('resolver/finished.html.erb')
52
+ quit!
53
+ end
54
+ end
55
+ end
56
+
57
+ def self.rack_handler
58
+ handler = detect_rack_handler
59
+ end
60
+
61
+ def quit!
62
+ self.class.quit!(self.class.running_server, "A server")
63
+ end
64
+ end
65
+ return klass
66
+ end
67
+
68
+ setting :bind, "0.0.0.0"
69
+ setting :port, 51076 #JDL's birthday
70
+ setting :valise, Mattock::ValiseManager.default_valise("lib")
71
+
72
+ def action
73
+ puts
74
+ puts "STARTING WEB LISTENER TO RESOLVE PREREQUISITES"
75
+ puts
76
+
77
+ collector = build_collector(self, prerequisite_tasks)
78
+ handler = collector.rack_handler
79
+ handler_name = handler.name
80
+
81
+ old_handlers = nil
82
+ handler.run collector, :Host => bind, :Port => port do |server|
83
+ old_handlers = Hash[
84
+ [:INT, :TERM].map { |sig| [sig, trap(sig) { collector.quit!(server, handler_name) }] }
85
+ ]
86
+ collector.running_server = server
87
+ if server.respond_to? :threaded=
88
+ server.threaded = settings.threaded
89
+ end
90
+ puts "Listening on #{port} with #{handler.name}"
91
+ end
92
+
93
+ old_handlers.each_pair do |signal, handler|
94
+ trap(signal, handler)
95
+ end
96
+
97
+ rescue Errno::EADDRINUSE => e
98
+ puts "Port #{port} in use!"
99
+ exit 1
100
+ end
101
+ end
102
+ end