logical-construct 0.0.1.localtesting → 0.0.1

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 (29) hide show
  1. data/lib/logical-construct/ground-control/core.rb +0 -1
  2. data/lib/logical-construct/ground-control/provision.rb +146 -29
  3. data/lib/logical-construct/ground-control/run-on-target.rb +4 -4
  4. data/lib/logical-construct/ground-control/setup.rb +5 -14
  5. data/lib/logical-construct/ground-control/setup/build-files.rb +31 -10
  6. data/lib/logical-construct/ground-control/setup/copy-files.rb +31 -19
  7. data/lib/logical-construct/ground-control/setup/create-construct-directory.rb +1 -0
  8. data/lib/logical-construct/ground-control/setup/install-init.rb +32 -0
  9. data/lib/logical-construct/resolving-task.rb +108 -5
  10. data/lib/logical-construct/satisfiable-task.rb +25 -2
  11. data/lib/logical-construct/target/chef-solo.rb +12 -15
  12. data/lib/logical-construct/target/platforms/default/chef-config.rb +57 -12
  13. data/lib/logical-construct/target/platforms/default/resolve-configuration.rb +22 -3
  14. data/lib/logical-construct/target/provision.rb +10 -0
  15. data/lib/logical-construct/target/sinatra-resolver.rb +16 -19
  16. data/lib/logical-construct/testing/resolve-configuration.rb +8 -0
  17. data/lib/templates/Gemfile.erb +3 -1
  18. data/lib/templates/chef.rb.erb +6 -1
  19. data/lib/templates/construct.init.d.erb +15 -0
  20. data/lib/templates/resolver/index.html.erb +11 -2
  21. data/lib/templates/resolver/task-file-form.html.erb +6 -0
  22. data/spec/ground-control/smoke-test.rb +23 -0
  23. data/spec/resolution.rb +147 -0
  24. data/spec/target/chef-config.rb +3 -0
  25. data/spec/target/chef-solo.rb +8 -0
  26. data/spec/target/smoke-test.rb +45 -0
  27. metadata +44 -14
  28. data/lib/logical-construct/ground-control/setup/bundle-setup.rb +0 -36
  29. data/lib/logical-construct/ground-control/setup/ensure-env.rb +0 -15
@@ -8,6 +8,7 @@ module LogicalConstruct
8
8
 
9
9
  def default_configuration(setup)
10
10
  self.construct_dir = setup.construct_dir
11
+ self.remote_server = setup.proxy_value.remote_server
11
12
  super
12
13
  end
13
14
 
@@ -0,0 +1,32 @@
1
+ require 'mattock'
2
+ require 'logical-construct/ground-control/run-on-target'
3
+
4
+ module LogicalConstruct
5
+ module GroundControl
6
+ class InstallInit < RunOnTarget
7
+ required_fields :source_path, :target_path
8
+ setting :construct_dir
9
+ setting :service_name, "logical-construct"
10
+ setting :initd_path, "/etc/init.d"
11
+
12
+ def default_configuration(setup)
13
+ super
14
+ setup.copy_settings_to(self)
15
+ end
16
+
17
+ def resolve_configuration
18
+ super
19
+ self.source_path ||= File::join(construct_dir, "construct.init.d")
20
+ self.target_path ||= File::join(initd_path, service_name)
21
+ end
22
+
23
+ def define
24
+ remote_task(:install_init) do |task|
25
+ task.command = cmd("install", "-T", source_path, target_path) &
26
+ ["rc-update", "add", service_name, "default"]
27
+ end
28
+ bracket_task(:remote_config, :install_init, :remote_setup)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,6 @@
1
1
  require 'rake/task'
2
2
  require 'mattock/task'
3
+ require 'logical-construct/satisfiable-task'
3
4
 
4
5
  module LogicalConstruct
5
6
  #Ensures that all it's deps are satisfied before proceeding - the action for
@@ -17,22 +18,124 @@ module LogicalConstruct
17
18
  #So, of note: you'll only get invoked once, ever
18
19
  #You'll only be executed if #needed?
19
20
  #Deps will get invoked (ish) even if not #needed?
20
- #
21
+ module SatisfiableManager
22
+ def default_configuration(*configurables)
23
+ super
24
+ self.satisfiables = configurables.find_all do |conf|
25
+ conf.is_a? SatisfiableTask
26
+ end.map{|sat| sat.rake_task}
27
+ end
28
+
29
+ def define
30
+ super
31
+ satisfiables.each do |sat|
32
+ sat.enhance([rake_task.name])
33
+ end
34
+ end
35
+
36
+ def add_satisfiable(task)
37
+ task = task.rake_task if task.respond_to? :rake_task
38
+ satisfiables << task
39
+ task.enhance([rake_task.name])
40
+ end
41
+ end
42
+
43
+ require 'yaml'
44
+ require 'digest'
45
+ module ResolutionProtocol
46
+ def digest
47
+ @digest ||= Digest::SHA2.new
48
+ end
49
+
50
+ def file_checksum(path)
51
+ generate_checksum(File::read(path))
52
+ end
53
+
54
+ def generate_checksum(data)
55
+ digest.reset
56
+ digest << data
57
+ digest.hexdigest
58
+ end
59
+
60
+ def web_path(task_name)
61
+ "/" + task_name.gsub(":", "/")
62
+ end
63
+ end
64
+
21
65
  class ResolvingTask < Rake::Task
22
66
  include Mattock::TaskMixin
67
+ include SatisfiableManager
68
+ setting :satisfiables, []
69
+
23
70
  def needed?
24
- prerequisite_tasks.any?{|task| task.needed?}
71
+ !unsatisfied.empty?
25
72
  end
26
73
 
27
- def unsatisfied_prerequisites
28
- prerequisite_tasks.find_all{|task| task.needed?}
74
+ def unsatisfied
75
+ satisfiables.find_all{|task| task.needed?}
29
76
  end
30
77
 
31
78
  def execute(args=nil)
32
79
  super
33
80
  if needed?
34
- raise "Task #{name} failed to satisfy: #{unsatisfied_prerequisites.inspect}"
81
+ raise "Task #{name} failed to satisfy: #{unsatisfied.inspect}"
82
+ end
83
+ end
84
+ end
85
+
86
+ class Manifest < SatisfiableTask
87
+ include SatisfiableManager
88
+ include ResolutionProtocol
89
+
90
+ setting :satisfiables, []
91
+ nil_field :manifest
92
+
93
+ default_taskname "Manifest"
94
+
95
+ def invalid_checksum(checksum, path)
96
+ return false unless File::exists?(path)
97
+ return true if checksum.nil? or checksum.empty?
98
+ return checksum != file_checksum(path)
99
+ end
100
+
101
+ def needed?
102
+ manifest.nil?
103
+ end
104
+
105
+ def fulfill(data)
106
+ self.manifest = YAML::load(data)
107
+ satisfiables.each do |sat|
108
+ path = sat.target_path
109
+ checksum = manifest[sat.name]
110
+ if invalid_checksum(checksum, path)
111
+ File::rename(path, path + ".invalid")
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ class GenerateManifest < Mattock::Task
118
+ include ResolutionProtocol
119
+ setting :hash, {}
120
+ setting :resolutions
121
+ setting :receiving_name
122
+
123
+ def default_configuration(resolution_host)
124
+ super
125
+ self.resolutions = resolution_host.resolutions
126
+ end
127
+
128
+ def data_checksum(path, data)
129
+ hash[path] = generate_checksum(data)
130
+ end
131
+
132
+ def action
133
+ resolutions.each_pair do |destination, data|
134
+ data = data.call if data.respond_to? :call
135
+ data = data.read if data.respond_to? :read
136
+ hash[destination] = generate_checksum(data)
35
137
  end
138
+ resolutions[receiving_name] = YAML::dump(hash)
36
139
  end
37
140
  end
38
141
  end
@@ -20,9 +20,24 @@ module LogicalConstruct
20
20
  #Swallowed
21
21
  end
22
22
 
23
+ def prefer_file?
24
+ false
25
+ end
26
+
23
27
  def receive(data)
24
28
  return unless needed?
25
29
  fulfill(data)
30
+ if data.respond_to? :path
31
+ fulfill_file(data)
32
+ elsif data.respond_to? :read
33
+ fulfill(data.read)
34
+ else
35
+ fulfill(data.to_s)
36
+ end
37
+ end
38
+
39
+ def receive_file(file)
40
+ fulfill(file.read)
26
41
  end
27
42
 
28
43
  def fulfill(string)
@@ -39,13 +54,21 @@ module LogicalConstruct
39
54
  class SatisfiableFileTask < SatisfiableTask
40
55
  setting :target_path
41
56
 
57
+ def prefer_file?
58
+ true
59
+ end
60
+
42
61
  def criteria(task)
43
62
  File::exists?(target_path)
44
63
  end
45
64
 
46
- def fulfill(string)
65
+ def fulfill_file(file)
66
+ FileUtils::move(file.path, target_path)
67
+ end
68
+
69
+ def fulfill(data)
47
70
  File::open(target_path, "w") do |file|
48
- file.write(string)
71
+ file.write(data)
49
72
  end
50
73
  end
51
74
  end
@@ -6,35 +6,32 @@ module LogicalConstruct
6
6
 
7
7
  settings(
8
8
  :chef_solo_bin => "chef-solo",
9
- :config_file => "/etc/chef/solo.rb",
10
9
  :daemonize => nil,
11
10
  :user => nil,
12
11
  :group => nil,
13
12
  :node_name => nil
14
13
  )
15
14
 
15
+ setting :config_file
16
+
16
17
  def default_configuration(chef_config)
18
+ super
17
19
  self.config_file = chef_config.solo_rb
18
20
  end
19
21
 
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
22
  def define
31
23
  in_namespace do
32
- file config_file
33
- task :run => [config_file] do
34
- chef_command.run
24
+ Mattock::CommandTask.new(:run) do |task|
25
+ task.command = Mattock::CommandLine.new(chef_solo_bin) do |cmd|
26
+ cmd.options << "--config #{config_file}" unless config_file.nil?
27
+ cmd.options << "--daemonize" if daemonize
28
+ cmd.options << "--user #{user}" if user
29
+ cmd.options << "--group #{group}" if group
30
+ cmd.options << "--node_name #{node_name}" if node_name
31
+ end
35
32
  end
36
33
  end
37
- task :provision => self[:run]
34
+ bracket_task(:build_configs, :run, :provision)
38
35
  end
39
36
  end
40
37
  end
@@ -1,22 +1,29 @@
1
1
  require 'mattock/tasklib'
2
2
  require 'mattock/template-host'
3
+ require 'mattock/command-line'
3
4
  require 'logical-construct/satisfiable-task'
4
5
 
5
6
  module LogicalConstruct
6
7
  module Default
8
+ #XXX Should get broken into at least 2 smaller tasklibs
7
9
  class ChefConfig < Mattock::Tasklib
8
10
  include Mattock::TemplateHost
9
11
  default_namespace :chef_config
10
12
 
11
13
  required_field :construct_dir
12
- required_fields :file_cache_path, :cookbook_path, :cookbook_tarball_path, :json_attribs
14
+ required_fields :cookbook_path, :data_bags_path, :json_attribs,
15
+ :cookbook_tarball_path, :file_cache_path, :secret_data_tarball_path, :normal_data_tarball_path
13
16
  required_field :valise
14
17
  settings :solo_rb => "/etc/chef/solo.rb",
18
+ :etc_chef => "/etc/chef",
19
+ :data_bags_relpath => "data-bags",
15
20
  :cookbook_relpath => "cookbooks",
16
21
  :cookbook_tarball_relpath => "cookbooks.tgz",
22
+ :secret_data_tarball_relpath => "secret_data.tgz",
23
+ :normal_data_tarball_relpath => "normal_data.tgz",
17
24
  :json_attribs_relpath => "node.json"
18
25
 
19
- setting :resolution_task
26
+ setting :resolution
20
27
 
21
28
  nil_fields :recipe_url, :role_path, :role_relpath
22
29
 
@@ -24,23 +31,38 @@ module LogicalConstruct
24
31
  super
25
32
  self.construct_dir = provision.construct_dir
26
33
  self.valise = provision.valise
27
- self.resolution_task = resolution[:resolve]
34
+ self.resolution = resolution
28
35
  end
29
36
 
37
+ #XXX Hints about decomposing this Tasklib: there are settings for
38
+ #chef/solo.rb, which are only incidentally related to the tarball
39
+ #unpacking tasks - which are themselves closely related
30
40
  def resolve_configuration
31
41
  if unset?(file_cache_path)
32
42
  self.file_cache_path = File::expand_path('chef', construct_dir)
33
43
  end
34
-
35
44
  self.file_cache_path = File::expand_path(file_cache_path)
45
+
36
46
  if unset?(cookbook_path) and !cookbook_relpath.nil?
37
47
  self.cookbook_path = File::expand_path(cookbook_relpath, file_cache_path)
38
48
  end
39
49
 
50
+ if unset?(data_bags_path) and !data_bags_relpath.nil?
51
+ self.data_bags_path = File::expand_path(data_bags_relpath, file_cache_path)
52
+ end
53
+
40
54
  if unset?(cookbook_tarball_path) and !cookbook_tarball_relpath.nil?
41
55
  self.cookbook_tarball_path = File::expand_path(cookbook_tarball_relpath, file_cache_path)
42
56
  end
43
57
 
58
+ if unset?(secret_data_tarball_path) and !secret_data_tarball_relpath.nil?
59
+ self.secret_data_tarball_path = File::expand_path(secret_data_tarball_relpath, file_cache_path)
60
+ end
61
+
62
+ if unset?(normal_data_tarball_path) and !normal_data_tarball_relpath.nil?
63
+ self.normal_data_tarball_path = File::expand_path(normal_data_tarball_relpath, file_cache_path)
64
+ end
65
+
44
66
  self.solo_rb = File::expand_path(solo_rb, file_cache_path)
45
67
 
46
68
  if unset?(json_attribs) and !json_attribs_relpath.nil?
@@ -53,36 +75,59 @@ module LogicalConstruct
53
75
  super
54
76
  end
55
77
 
78
+ include Mattock::CommandLineDSL
56
79
  def define
57
80
  in_namespace do
81
+ directory etc_chef
58
82
  directory file_cache_path
59
83
 
60
84
  Mattock::CommandTask.new(:unpack_cookbooks => :cookbook_tarball) do |task|
61
- task.command = Mattock::CommandLine.new("tar", "-xzf", cookbook_tarball_path)
85
+ task.command = cmd("cd", file_cache_path) & cmd("tar", "-xzf", cookbook_tarball_path)
86
+ end
87
+
88
+ Mattock::CommandTask.new(:unpack_secret_data => :secret_data_tarball) do |task|
89
+ task.command = cmd("cd", file_cache_path) & cmd("tar", "-xzf", secret_data_tarball_path)
90
+ end
91
+
92
+ Mattock::CommandTask.new(:unpack_normal_data => :normal_data_tarball) do |task|
93
+ task.command = cmd("cd", file_cache_path) & cmd("tar", "-xzf", normal_data_tarball_path)
62
94
  end
63
95
 
64
- file solo_rb => [:unpack_cookbooks, :json_attribs, file_cache_path, resolution_task] do
96
+ file solo_rb => [etc_chef, :json_attribs, :unpack_cookbooks, :unpack_secret_data, :unpack_normal_data] do
65
97
  File::open(solo_rb, "w") do |file|
66
98
  file.write(render("chef.rb.erb"))
67
99
  end
68
100
  end
69
101
 
70
- SatisfiableFileTask.new(:json_attribs => file_cache_path) do |task|
102
+ resolution.add_file(SatisfiableFileTask.new(:json_attribs => file_cache_path) do |task|
71
103
  task.target_path = json_attribs
72
- end
104
+ end)
73
105
 
74
- SatisfiableFileTask.new(:cookbook_tarball => file_cache_path) do |task|
106
+ resolution.add_file(SatisfiableFileTask.new(:cookbook_tarball => file_cache_path) do |task|
75
107
  task.target_path = cookbook_tarball_path
76
- end
108
+ end)
109
+
110
+ resolution.add_file(SatisfiableFileTask.new(:secret_data_tarball => file_cache_path) do |task|
111
+ task.target_path = secret_data_tarball_path
112
+ end)
113
+
114
+ resolution.add_file(SatisfiableFileTask.new(:normal_data_tarball => file_cache_path) do |task|
115
+ task.target_path = normal_data_tarball_path
116
+ end)
77
117
 
78
118
  unless role_path.nil?
79
119
  directory role_path
80
120
  file solo_rb => role_path
81
121
  end
122
+
123
+ desc "Delete all the chef config files (to re-provision)"
124
+ task :clobber do
125
+ cmd("rm", "-rf", file_cache_path)
126
+ end
82
127
  end
83
128
 
84
- task resolution_task => self[:cookbook_tarball]
85
- task resolution_task => self[:json_attribs]
129
+ file solo_rb => resolution[:Manifest]
130
+ task :build_configs => solo_rb
86
131
  end
87
132
  end
88
133
  end
@@ -8,16 +8,35 @@ module LogicalConstruct
8
8
  setting :port, 51076
9
9
  setting :valise
10
10
 
11
+ def initialize(*args, &block)
12
+ @pending_satisfiables = []
13
+ @resolver = nil
14
+ @manifest = nil
15
+ super
16
+ end
17
+
11
18
  def default_configuration(provision)
19
+ super
12
20
  self.valise = provision.valise
13
21
  end
14
22
 
23
+ def add_file(file_satisfiable)
24
+ if @resolver.nil?
25
+ @pending_satifiables << file_satisfiable
26
+ else
27
+ @resolver.add_satisfiable(file_satisfiable)
28
+ @manifest.add_satisfiable(file_satisfiable)
29
+ end
30
+ end
31
+
15
32
  def define
16
33
  in_namespace do
17
- resolver = LogicalConstruct::SinatraResolver.new do |task|
18
- task.task_name = "resolve"
34
+ @manifest = LogicalConstruct::Manifest.new(*@pending_satisfiables)
35
+
36
+ @resolver = LogicalConstruct::SinatraResolver.new(*([@manifest] + @pending_satisfiables)) do |task|
37
+ copy_settings_to(task)
19
38
  end
20
- copy_settings_to(resolver)
39
+ @pending_satisfiables.clear
21
40
  end
22
41
  end
23
42
  end