ironfan 4.12.3 → 5.0.0

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.
@@ -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