logical-construct 0.0.1.localtesting

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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