ironfan 4.12.3 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,266 @@
1
+ require 'diff-lcs'
2
+
3
+ module Gorillib
4
+ module AnsiColors
5
+ def cyan str
6
+ "\e[36m#{str}\e[0m"
7
+ end
8
+ end
9
+
10
+ module DiffDisplayTools
11
+ def display_key_header key
12
+ indent; @stream.puts("#{key}:")
13
+ end
14
+
15
+ #-------------------------------------------------------------------------------------------------
16
+
17
+ def only_left_key key
18
+ indent; @stream.puts("only on #{b_left}")
19
+ end
20
+
21
+ def only_right_key key
22
+ indent; @stream.puts("only on #{b_right}")
23
+ end
24
+
25
+ #-------------------------------------------------------------------------------------------------
26
+
27
+ def display_hetero this, other
28
+ indent; @stream.puts("#{b_left} class is #{this.class} but #{b_right} class is #{other.class}")
29
+ end
30
+
31
+ #-------------------------------------------------------------------------------------------------
32
+
33
+ def display_noteql_atoms this, other
34
+ indent; @stream.puts("#{b_left}: #{this.inspect}")
35
+ indent; @stream.puts("#{b_right}: #{other.inspect}")
36
+ end
37
+
38
+ #-------------------------------------------------------------------------------------------------
39
+
40
+ def display_eql(it)
41
+ indent; @stream.puts("#{'='} #{it}")
42
+ end
43
+
44
+ def display_add(itl, itr)
45
+ indent
46
+ if itl.nil?
47
+ @stream.puts("#{b_right}: #{itr}")
48
+ else
49
+ @stream.puts("#{b_left}: #{itl}")
50
+ end
51
+ end
52
+
53
+ #-------------------------------------------------------------------------------------------------
54
+
55
+ def indent
56
+ @stream.write(" " * @indentation)
57
+ end
58
+
59
+ def display_indices(ixl, ixr)
60
+ indent; @stream.puts("#{b_left} ix: #{ixl}, #{b_right} ix: #{ixr}")
61
+ end
62
+
63
+ #------------------------------------------------------------------------------------------------
64
+
65
+ def b_left
66
+ "[#{header(@left)}]"
67
+ end
68
+
69
+ def b_right
70
+ "[#{header(@right)}]"
71
+ end
72
+
73
+ def decrease_indentation
74
+ @indentation -= @tab_width
75
+ end
76
+
77
+ def header str
78
+ cyan(str)
79
+ end
80
+
81
+ def increase_indentation
82
+ @indentation += @tab_width
83
+ end
84
+ end
85
+
86
+ module DiffDrawerMethods
87
+ def for_subhash(key)
88
+ display_key_header(key)
89
+ increase_indentation
90
+ yield
91
+ decrease_indentation
92
+ end
93
+
94
+ #-------------------------------------------------------------------------------------------------
95
+
96
+ def display_diff_indices diff_subset
97
+ return if diff_subset.nil? or diff_subset.empty?
98
+ diff_subset.first.tap do |cchange|
99
+ display_indices(cchange.old_position, cchange.new_position)
100
+ end
101
+ end
102
+
103
+ def display_eql_items diff_subset
104
+ return if diff_subset.nil?
105
+ diff_subset.each do |cchange|
106
+ display_eql(cchange.old_element)
107
+ end
108
+ end
109
+
110
+ def display_noteql_items diff_subset
111
+ return if diff_subset.nil?
112
+ diff_subset.each do |cchange|
113
+ display_noteql_atoms(cchange.old_element, cchange.new_element)
114
+ end
115
+ end
116
+
117
+ def display_add_items diff_subset
118
+ return if diff_subset.nil?
119
+ diff_subset.each do |cchange|
120
+ display_add(cchange.old_element, cchange.new_element)
121
+ end
122
+ end
123
+ end
124
+
125
+ class DiffDrawer
126
+ include AnsiColors
127
+ include DiffDisplayTools
128
+ include DiffDrawerMethods
129
+
130
+ def initialize options = {}
131
+ @stream = options[:stream] || $stdout
132
+ @left = options[:left] || 'left'
133
+ @right = options[:right] || 'right'
134
+ @indentation = options[:indentation] || 0
135
+ @tab_width = options[:tab_width] || 4
136
+ end
137
+ end
138
+
139
+ class DiffFormatter
140
+ def initialize(options = {})
141
+ @drawer = (options[:drawer] ||
142
+ DiffDrawer.new(stream: options.delete(:stream),
143
+ left: options.delete(:left),
144
+ right: options.delete(:right),
145
+ indentation: options.delete(:indentation),
146
+ tab_width: options.delete(:tab_width)))
147
+
148
+ @context_atoms = options[:context_atoms] || 0
149
+ end
150
+
151
+ def display_diff(this, other)
152
+ setup
153
+ if this.is_a?(Hash) && other.is_a?(Hash)
154
+ display_diff_hash(this, other)
155
+ elsif this.is_a?(Array) && other.is_a?(Array)
156
+ display_diff_arr(this, other)
157
+ elsif ((this.is_a?(Hash) != other.is_a?(Hash)) ||
158
+ (this.is_a?(Array) != other.is_a?(Array)))
159
+ display_diff_hetero(this, other)
160
+ else
161
+ display_diff_atom(this, other)
162
+ end
163
+ end
164
+
165
+ private
166
+
167
+ #-------------------------------------------------------------------------------------------------
168
+
169
+ def setup
170
+ @display_last_suffix = display_last_suffix_p
171
+ @display_this_prefix = nop_p
172
+ end
173
+
174
+ #-------------------------------------------------------------------------------------------------
175
+
176
+ def display_diff_hash(this, other)
177
+ (this.keys & other.keys).each do |key|
178
+ if this[key] != other[key]
179
+ @drawer.for_subhash(key){ display_diff(this[key], other[key]) }
180
+ end
181
+ end
182
+ (this.keys - other.keys).each do |key|
183
+ @drawer.for_subhash(key){ @drawer.only_left_key(key) }
184
+ end
185
+ (other.keys - this.keys).each do |key|
186
+ @drawer.for_subhash(key){ @drawer.only_right_key(key) }
187
+ end
188
+ end
189
+
190
+ def display_diff_hetero(this, other)
191
+ @drawer.display_hetero(this, other)
192
+ end
193
+
194
+ def display_diff_atom(this, other)
195
+ if this != other
196
+ @drawer.display_noteql_atoms(this, other)
197
+ end
198
+ end
199
+
200
+ def display_diff_arr(this, other)
201
+ Diff::LCS.sdiff(this, other).chunk{|x| type_of(x)}.each do |type, diff_atoms|
202
+ case type
203
+ when '=' then next_step(diff_atoms, type)
204
+ when '+' then next_step(diff_atoms, type){ @drawer.display_add_items(diff_atoms) }
205
+ when '!' then next_step(diff_atoms, type){ @drawer.display_noteql_items(diff_atoms) }
206
+ end
207
+ end
208
+ end
209
+
210
+ #-------------------------------------------------------------------------------------------------
211
+
212
+ def next_step(diff_atoms, type)
213
+ if type == '='
214
+ @display_this_prefix.call diff_atoms
215
+ yield(diff_atoms) if block_given?
216
+ @display_last_suffix = display_last_suffix_p diff_atoms
217
+ @display_this_prefix = nop_p
218
+ else
219
+ @display_last_suffix.call
220
+ yield(diff_atoms) if block_given?
221
+ @display_last_suffix = nop_p
222
+ @display_this_prefix = display_this_prefix_p
223
+ end
224
+ end
225
+
226
+ #-------------------------------------------------------------------------------------------------
227
+
228
+ def display_this_prefix_p()
229
+ ->(diff_subset) do
230
+ diff_subset = diff_subset[0...@context_atoms]
231
+ @drawer.display_eql_items(diff_subset)
232
+ end
233
+ end
234
+
235
+ def display_last_suffix_p(diff_subset = [])
236
+ ->() do
237
+ to_display = diff_subset[[0, (diff_subset.size - @context_atoms)].max..-1]
238
+ if diff_subset.empty?
239
+ @drawer.display_indices(0,0)
240
+ elsif to_display.empty?
241
+ @drawer.
242
+ display_indices(diff_subset.first.old_position + diff_subset.map(&:old_element).compact.size,
243
+ diff_subset.first.new_position + diff_subset.map(&:new_element).compact.size)
244
+ else
245
+ @drawer.display_indices(to_display.first.old_position, to_display.first.new_position)
246
+ end
247
+
248
+ @drawer.display_eql_items(to_display)
249
+ end
250
+ end
251
+
252
+ def nop_p() ->(*_) {} end
253
+
254
+ #-------------------------------------------------------------------------------------------------
255
+
256
+ def type_of(diff_atom)
257
+ if diff_atom.old_element == diff_atom.new_element
258
+ '='
259
+ elsif diff_atom.old_element.nil? || diff_atom.new_element.nil?
260
+ '+'
261
+ else
262
+ '!'
263
+ end
264
+ end
265
+ end
266
+ end
@@ -0,0 +1,30 @@
1
+ require 'delegate'
2
+
3
+ class NilCheckDelegate < Delegator
4
+ def initialize(obj)
5
+ super
6
+ @delegate_sd_obj = obj
7
+ @depth = 0
8
+ end
9
+
10
+ def nilcheck_depth(depth = 0)
11
+ @depth = depth
12
+ self
13
+ end
14
+
15
+ def _wrap(obj)
16
+ ((@depth -= 1) >= 0) ? self.class.new(obj) : obj
17
+ end
18
+
19
+ def method_missing m, *args, &blk
20
+ _wrap(__getobj__.nil? ? nil : super(m, *args, &blk))
21
+ end
22
+
23
+ def __getobj__
24
+ @delegate_sd_obj
25
+ end
26
+
27
+ def __setobj__(obj)
28
+ @delegate_sd_obj = obj
29
+ end
30
+ end
@@ -76,6 +76,9 @@ module Ironfan
76
76
  ensure_dependencies
77
77
  iaas_provider.machine_class.create! self
78
78
  node.announce_state :started
79
+ server.to_machine_manifest.components.each do |component|
80
+ component.announce_to(node)
81
+ end
79
82
  save
80
83
  self
81
84
  end
@@ -3,6 +3,11 @@ module Ironfan
3
3
 
4
4
  class Cluster < Ironfan::Dsl::Compute
5
5
  collection :facets, Ironfan::Dsl::Facet, :resolver => :deep_resolve
6
+ include Ironfan::Plugin::Base; register_with Ironfan::Dsl::Realm
7
+
8
+ def children
9
+ facets.to_a + components.to_a
10
+ end
6
11
 
7
12
  def initialize(attrs={},&block)
8
13
  super
@@ -21,6 +26,11 @@ module Ironfan
21
26
  def cluster_name
22
27
  name
23
28
  end
29
+
30
+ def self.plugin_hook owner, attrs, plugin_name, full_name, &blk
31
+ owner.cluster(plugin_name, new(attrs.merge(name: full_name, owner: owner)))
32
+ _project cluster, &blk
33
+ end
24
34
  end
25
35
  end
26
36
  end
@@ -0,0 +1,157 @@
1
+ module Ironfan
2
+ class Dsl
3
+ class Component < Ironfan::Dsl
4
+ include Gorillib::Builder
5
+ include Gorillib::Concern
6
+ include Ironfan::Plugin::Base; register_with Ironfan::Dsl::Compute
7
+
8
+ field :cluster_name, Symbol
9
+ field :facet_name, Symbol
10
+ field :realm_name, Symbol
11
+ field :name, Symbol
12
+
13
+ def initialize(attrs, &blk)
14
+ attrs.merge!(facet_name: (attrs[:owner].name unless attrs[:owner].nil? or not attrs[:owner].is_a?(Facet)),
15
+ cluster_name: (attrs[:owner].cluster_name unless attrs[:owner].nil?),
16
+ realm_name: (attrs[:owner].realm_name unless attrs[:owner].nil?))
17
+ super attrs, &blk
18
+ end
19
+
20
+ def self.plugin_hook owner, attrs, plugin_name, full_name, &blk
21
+ (this = new(attrs.merge(owner: owner, name: full_name), &blk))._project(owner)
22
+ this
23
+ end
24
+
25
+ def announce_to node
26
+ node.set['components']["#{cluster_name}-#{name}"]['name'] = name
27
+ end
28
+
29
+ def self.to_node
30
+ super.tap do |node|
31
+ node.set['cluster_name'] = cluster_name
32
+ end
33
+ end
34
+
35
+ def self.from_node(node = NilCheckDelegate.new(nil))
36
+ cluster_name = node['cluster_name'].to_s
37
+ super(node).tap{|x| x.receive!(cluster_name: cluster_name,
38
+ realm_name: cluster_name.split('_').first)}
39
+ end
40
+
41
+ def self.announce_name
42
+ plugin_name
43
+ end
44
+
45
+ def announce_name
46
+ self.class.announce_name
47
+ end
48
+
49
+ def _project(compute)
50
+ compute.component name, self
51
+ project(compute)
52
+ end
53
+
54
+ def realm_announcements
55
+ (@@realm_announcements ||= {})
56
+ end
57
+
58
+ def realm_subscriptions component_name
59
+ (@@realm_subscriptions ||= {})[component_name] ||= []
60
+ end
61
+
62
+ def announce(component_name)
63
+ Chef::Log.debug("announced #{announce_name} for #{cluster_name}")
64
+ realm_announcements[[realm_name, component_name]] = [cluster_name, facet_name]
65
+ realm_subscriptions(component_name).each{|blk| blk.call(cluster_name, facet_name)}
66
+ end
67
+
68
+ def discover(component_name, &blk)
69
+ if already_announced = realm_announcements[[realm_name, component_name]]
70
+ yield *already_announced
71
+ else
72
+ Chef::Log.debug("#{cluster_name}: no one announced #{announce_name}. subscribing")
73
+ realm_subscriptions(component_name) << blk
74
+ end
75
+ end
76
+ end
77
+
78
+ module Discovery
79
+ include Gorillib::Builder
80
+ extend Gorillib::Concern
81
+
82
+ magic :server_cluster, Symbol
83
+ magic :bidirectional, :boolean, default: false
84
+
85
+ (@_dependencies ||= []) << Gorillib::Builder
86
+
87
+ module ClassMethods
88
+ def default_to_bidirectional default=true
89
+ fields[:bidirectional].default = default
90
+ end
91
+ end
92
+
93
+ def set_discovery compute, keys
94
+ if server_cluster
95
+ wire_to(compute, full_server_cluster, facet_name, keys)
96
+ else
97
+ discover(announce_name) do |cluster_name, facet_name|
98
+ wire_to(compute, cluster_name, facet_name, keys)
99
+ end
100
+ end
101
+ end
102
+
103
+ def wire_to(compute, cluster_name, facet_name, keys)
104
+ discovery = {discovers: keys.reverse.inject(cluster_name){|hsh,key| {key => hsh}}}
105
+ (compute.facet_role || compute.cluster_role).override_attributes(discovery)
106
+
107
+ # FIXME: This is Ec2-specific and probably doesn't belong here.
108
+ client_group_v = client_group(compute)
109
+ server_group_v = server_group(cluster_name, facet_name)
110
+
111
+ group_edge(compute.cloud(:ec2), client_group_v, server_group_v)
112
+ group_edge(compute.cloud(:ec2), server_group_v, client_group_v) if bidirectional
113
+
114
+ Chef::Log.debug("discovered #{announce_name} for #{cluster_name}: #{discovery}")
115
+ end
116
+
117
+ protected
118
+
119
+ def client_group(compute)
120
+ security_group(compute.cluster_name, (compute.name if compute.is_a?(Facet)))
121
+ end
122
+
123
+ def full_server_cluster
124
+ "#{realm_name}_#{server_cluster}"
125
+ end
126
+
127
+ def group_edge(cloud, group_1, group_2)
128
+ cloud.security_group(group_1).authorize_group(group_2)
129
+ Chef::Log.debug("component.rb: allowing access from security group #{group_1} to #{group_2}")
130
+ end
131
+
132
+ def security_group(cluster_name, facet_name)
133
+ facet_name ? [cluster_name, facet_name].join('-') : cluster_name
134
+ end
135
+
136
+ def server_group(cluster_name, facet_name)
137
+ security_group(cluster_name, facet_name)
138
+ end
139
+ end
140
+
141
+ module Announcement
142
+ include Gorillib::Builder
143
+
144
+ def _project(compute)
145
+ announce announce_name
146
+ super compute
147
+ end
148
+ end
149
+ def to_manifest
150
+ to_wire.reject{|k,_| _skip_fields.include? k}
151
+ end
152
+
153
+ def _skip_fields() skip_fields << :_type; end
154
+
155
+ def skip_fields() [] end
156
+ end
157
+ end
@@ -1,3 +1,5 @@
1
+ require 'gorillib/metaprogramming/concern'
2
+
1
3
  module Ironfan
2
4
  class Dsl
3
5
 
@@ -16,6 +18,7 @@ module Ironfan
16
18
  field :name, String
17
19
 
18
20
  # Resolve each of the following as a merge of their container's attributes and theirs
21
+ collection :components, Ironfan::Dsl::Component, :resolver => :merge_resolve, :key_method => :name
19
22
  collection :run_list_items, RunListItem, :resolver => :merge_resolve, :key_method => :name
20
23
  collection :clouds, Ironfan::Dsl::Cloud, :resolver => :merge_resolve, :key_method => :name
21
24
  collection :volumes, Ironfan::Dsl::Volume, :resolver => :merge_resolve, :key_method => :name
@@ -30,6 +33,14 @@ module Ironfan
30
33
  magic :cluster_names, Whatever
31
34
  magic :realm_name, Symbol
32
35
 
36
+ field :source_file, String
37
+
38
+ extend Gorillib::Concern
39
+
40
+ def self._project compute, &blk
41
+ compute.around &blk
42
+ end
43
+
33
44
  def initialize(attrs={},&block)
34
45
  self.underlay = attrs[:owner] if attrs[:owner]
35
46
  super
@@ -89,8 +100,18 @@ module Ironfan
89
100
  raise "run_list placement must be one of :first, :normal, :last or nil (also means :normal)" unless [:first, :last, :own, nil].include?(placement)
90
101
  placement = :normal if placement.nil?
91
102
  @@run_list_rank += 1
103
+ # Rank is a global order that tells what order this was encountered in.
92
104
  run_list_items[item] = { :name => item, :rank => @@run_list_rank, :placement => placement }
93
105
  end
106
+
107
+ def around &blk
108
+ before
109
+ instance_eval(&blk)
110
+ after
111
+ end
112
+
113
+ def after() end
114
+ def before() end
94
115
  end
95
116
 
96
117
  end
@@ -2,6 +2,8 @@ module Ironfan
2
2
  class Dsl
3
3
 
4
4
  class Facet < Ironfan::Dsl::Compute
5
+ include Ironfan::Plugin::Base; register_with Ironfan::Dsl::Cluster
6
+
5
7
  magic :instances, Integer, :default => 1
6
8
  collection :servers, Ironfan::Dsl::Server, :resolver => :deep_resolve
7
9
  field :cluster_name, String
@@ -16,7 +18,16 @@ module Ironfan
16
18
  for i in 0 .. instances-1; server(i); end
17
19
  end
18
20
 
21
+ def children
22
+ servers.to_a + components.to_a
23
+ end
24
+
19
25
  def full_name() "#{cluster_name}-#{name}"; end
26
+
27
+ def self.plugin_hook owner, attrs, plugin_name, full_name, &blk
28
+ facet = owner.facet(plugin_name, new(attrs.merge(name: plugin_name, owner: owner)))
29
+ _project facet, &blk
30
+ end
20
31
  end
21
32
  end
22
33
  end
@@ -4,30 +4,33 @@ module Ironfan
4
4
  class Realm < Ironfan::Dsl::Compute
5
5
  collection :clusters, Ironfan::Dsl::Cluster, :resolver => :deep_resolve
6
6
 
7
+ def children
8
+ clusters.to_a
9
+ end
10
+
7
11
  magic :cluster_suffixes, Whatever
8
12
 
9
13
  def initialize(attrs={},&block)
10
14
  cluster_names({})
11
15
  realm_name attrs[:name] if attrs[:name]
12
- super
16
+ attrs[:environment] = realm_name unless attrs.has_key?(:environment)
17
+ super(attrs, &block)
13
18
  end
14
19
 
15
20
  def cluster(label, attrs={},&blk)
16
21
  new_name = [realm_name, label].join('_').to_sym
17
- cluster = Ironfan::Dsl::Cluster.new(name: new_name, owner: self, cluster_names: cluster_names)
18
- cluster_names[label] = new_name
19
- cluster.receive!(attrs, &blk)
20
- super(new_name, cluster)
21
- end
22
22
 
23
- def cluster_name suffix
24
- clusters.fetch([realm_name, suffix.to_s].join('_').to_sym).name.to_sym
25
- end
26
-
27
- def cluster_suffix suffix
28
- clusters.
29
- fetch([realm_name, suffix.to_s].join('_').to_sym).name.to_s.
30
- gsub(/^#{realm_name}_/, '').to_sym
23
+ if clusters.keys.include? new_name
24
+ clusters[new_name].tap do |cl|
25
+ cl.receive!(attrs)
26
+ cl.instance_eval(&blk) if block_given?
27
+ end
28
+ else
29
+ cluster = Ironfan::Dsl::Cluster.new(name: new_name, owner: self, cluster_names: cluster_names)
30
+ cluster_names[label] = new_name
31
+ cluster.receive!(attrs, &blk)
32
+ super(new_name, cluster)
33
+ end
31
34
  end
32
35
  end
33
36
  end