erchef-expander 11.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,83 @@
1
+ #
2
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
3
+ # Author:: Seth Falcon (<seth@opscode.com>)
4
+ # Author:: Chris Walters (<cw@opscode.com>)
5
+ # Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ require 'yajl'
22
+ require 'chef/expander/node'
23
+ require 'chef/expander/loggable'
24
+
25
+ module Chef
26
+ module Expander
27
+ class VNodeTable
28
+
29
+ include Loggable
30
+
31
+ class InvalidVNodeTableUpdate < ArgumentError; end
32
+
33
+ attr_reader :vnodes_by_node
34
+
35
+ def initialize(vnode_supervisor)
36
+ @node_update_mutex = Mutex.new
37
+ @vnode_supervisor = vnode_supervisor
38
+ @vnodes_by_node = {}
39
+ end
40
+
41
+ def nodes
42
+ @vnodes_by_node.keys
43
+ end
44
+
45
+ def update_table(table_update)
46
+ case table_update[:update]
47
+ when "add", "update"
48
+ update_node(table_update)
49
+ when "remove"
50
+ remove_node(table_update)
51
+ else
52
+ raise InvalidVNodeTableUpdate, "no action or action not acceptable: #{table_update.inspect}"
53
+ end
54
+ log.debug { "current vnode table: #{@vnodes_by_node.inspect}" }
55
+ end
56
+
57
+ def update_node(node_info)
58
+ @node_update_mutex.synchronize do
59
+ @vnodes_by_node[Node.from_hash(node_info)] = node_info[:vnodes]
60
+ end
61
+ end
62
+
63
+ def remove_node(node_info)
64
+ @node_update_mutex.synchronize do
65
+ @vnodes_by_node.delete(Node.from_hash(node_info))
66
+ end
67
+ end
68
+
69
+ def leader_node
70
+ if @vnodes_by_node.empty?
71
+ nil
72
+ else
73
+ Array(@vnodes_by_node).reject { |node| node[1].empty? }.sort { |a,b| a[1].min <=> b[1].min }.first[0]
74
+ end
75
+ end
76
+
77
+ def local_node_is_leader?
78
+ (Node.local_node == leader_node) || (@vnodes_by_node[Node.local_node].include?(0))
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
4
+ # Author:: Seth Falcon (<seth@opscode.com>)
5
+ # Author:: Chris Walters (<cw@opscode.com>)
6
+ # Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+
22
+ ###############################################################################
23
+ # check_queue_size
24
+ # A Nagios Check for Chef Server Queue Backlogs
25
+ ###############################################################################
26
+
27
+ require 'rubygems'
28
+
29
+ Dir.chdir(File.join(File.expand_path(File.dirname(__FILE__)), "..")) do
30
+
31
+ require 'bunny'
32
+
33
+ $:.unshift(File.expand_path('./lib'))
34
+ require 'chef/expander'
35
+ require 'chef/expander/version'
36
+ require 'chef/expander/configuration'
37
+
38
+ include Chef
39
+
40
+ Expander.init_config([])
41
+
42
+ config = {:warn => 100, :crit => 200}
43
+
44
+ option_parser = OptionParser.new do |o|
45
+ o.banner = "Usage: check_queue_size [options]"
46
+
47
+ o.on('-w', '--warn WARN_THRESHOLD', 'number of messages to trigger a warning') do |i|
48
+ config[:warn] = i.to_i
49
+ end
50
+
51
+ o.on('-c', '--critical CRITICAL_THRESHOLD', 'the number of messages to trigger a critical') do |n|
52
+ config[:crit] = n.to_i
53
+ end
54
+
55
+ o.on_tail('-h', '--help', 'show this message') do
56
+ puts "chef-expander #{Expander.version}"
57
+ puts "queue size monitor"
58
+ puts ''
59
+ puts o
60
+ exit 127
61
+ end
62
+ end
63
+
64
+ option_parser.parse!(ARGV.dup)
65
+
66
+ message_counts = []
67
+
68
+ begin
69
+ amqp_client = Bunny.new(Expander.config.amqp_config)
70
+ amqp_client.start
71
+
72
+ 0.upto(Expander::VNODES - 1) do |vnode|
73
+ q = amqp_client.queue("vnode-#{vnode}", :durable => true)
74
+ message_counts << q.status[:message_count]
75
+ end
76
+ total_messages = message_counts.inject(:+)
77
+
78
+ if total_messages >= config[:crit]
79
+ puts "Chef Expander Queue Size CRITICAL - messages: #{total_messages}"
80
+ exit(2)
81
+ elsif total_messages >= config[:warn]
82
+ puts "Chef Expander Queue Size WARNING - messages: #{total_messages}"
83
+ exit(1)
84
+ else
85
+ puts "Chef Expander Queue Size OK - messages: #{total_messages}"
86
+ exit(0)
87
+ end
88
+
89
+ ensure
90
+ amqp_client.stop if defined?(amqp_client) && amqp_client && amqp_client.connected?
91
+ end
92
+
93
+ end
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'munin_plugin'
5
+ Dir.chdir(File.join(File.expand_path(File.dirname(__FILE__)), "..")) do
6
+ require 'bunny'
7
+
8
+ $:.unshift(File.expand_path('../../lib', __FILE__))
9
+ require 'chef/expander'
10
+ require 'chef/expander/version'
11
+ require 'chef/expander/configuration'
12
+
13
+ include Chef
14
+
15
+ munin_plugin do
16
+ graph_title "Expander Queue Size"
17
+ graph_vlabel "Events"
18
+ graph_category "Opscode"
19
+ graph_info "Events in the Expander Queue waiting to be consumed by Solr."
20
+ queuesize.label "events"
21
+ queuesize.draw "LINE"
22
+ queuesize.warning "100"
23
+ queuesize.critical "200"
24
+
25
+ collect do
26
+
27
+ Expander.init_config([])
28
+
29
+ message_counts = []
30
+
31
+ begin
32
+ amqp_client = Bunny.new(Expander.config.amqp_config)
33
+ amqp_client.start
34
+
35
+ 0.upto(Expander::VNODES - 1) do |vnode|
36
+ q = amqp_client.queue("vnode-#{vnode}", :durable => true)
37
+ message_counts << q.status[:message_count]
38
+ end
39
+ total_messages = message_counts.inject(:+)
40
+
41
+ ensure
42
+ amqp_client.stop if defined?(amqp_client) && amqp_client && amqp_client.connected?
43
+ end
44
+
45
+ queuesize.value total_messages
46
+
47
+ end
48
+
49
+
50
+ end
51
+ end
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
4
+ # Author:: Seth Falcon (<seth@opscode.com>)
5
+ # Author:: Chris Walters (<cw@opscode.com>)
6
+ # Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+
22
+ require "rubygems"
23
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
24
+
25
+ require 'yajl'
26
+ require 'chef/expander/solrizer'
27
+
28
+ USAGE = <<-EOH
29
+ #{$0} [file ...]
30
+
31
+ Convert Chef object JSON files into XML documents of the same name but
32
+ with a ".xml" extension containing the XML used for Solr indexing.
33
+ EOH
34
+
35
+ if ARGV.size == 0
36
+ abort USAGE
37
+ end
38
+
39
+ ARGV.each do |obj_file|
40
+ raw_json = open(obj_file, "r").read
41
+ item_json = Yajl::Parser.parse(raw_json)
42
+ payload = {
43
+ :item => item_json,
44
+ :type => item_json["chef_type"].to_s,
45
+ :database => "riak_search_test",
46
+ :id => item_json["name"],
47
+ :enqueued_at => Time.now.to_i
48
+ }
49
+ update_obj = {:action => "add", :payload => payload}
50
+ update_json = Yajl::Encoder.encode(update_obj)
51
+ solrizer = Chef::Expander::Solrizer.new(update_json) { :no_op }
52
+ solrizer.log.init(StringIO.new)
53
+
54
+ out = File.basename(obj_file).sub(/\.json$/, "") + ".xml"
55
+ open(out, "w") do |f|
56
+ f.write(solrizer.pointyize_add)
57
+ end
58
+ end
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
4
+ # Author:: Seth Falcon (<seth@opscode.com>)
5
+ # Author:: Chris Walters (<cw@opscode.com>)
6
+ # Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+
22
+ require "rubygems"
23
+
24
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
25
+
26
+ require 'pp'
27
+ require 'bunny'
28
+ require 'yajl'
29
+ require 'uuidtools'
30
+ require 'word_salad'
31
+
32
+ require 'chef_search/expander/configuration'
33
+
34
+ Chef::Expander.init_config(ARGV)
35
+
36
+ MESSAGES_TO_SEND = 10_000
37
+
38
+ NUM_RAND_KEY_PAIRS = 50
39
+ NUM_RAND_VALUE_PAIRS = 50
40
+
41
+ PERSISTENT_MESSAGES = true
42
+
43
+ KEYS = NUM_RAND_VALUE_PAIRS.words
44
+
45
+ SAMPLE_NODES = []
46
+ Dir.glob(File.expand_path(File.dirname(__FILE__)) + '/../data/*_node.json') do |node_file|
47
+ SAMPLE_NODES << Yajl::Parser.parse(IO.read(node_file))
48
+ end
49
+
50
+ NUM_NODES = SAMPLE_NODES.size
51
+ puts "Read #{NUM_NODES} sample nodes"
52
+
53
+ puts "Using rabbitmq config #{Chef::Expander.config.amqp_config.inspect}"
54
+
55
+ puts "connecting to rabbitmq"
56
+ amqp_client = Bunny.new(Chef::Expander.config.amqp_config)
57
+ amqp_client.start
58
+
59
+ puts 'declaring queues'
60
+ queues = {}
61
+ 0.upto(1023) do |vnode|
62
+ queues[vnode] = amqp_client.queue("vnode-#{vnode}", :durable => true)
63
+ end
64
+
65
+ def add_rand_keys(node)
66
+ rand_key_vals = Hash[*((2 * NUM_RAND_KEY_PAIRS).words)]
67
+ rand_vals = Hash[*(KEYS.zip(NUM_RAND_VALUE_PAIRS.words)).flatten]
68
+ node.merge(rand_key_vals.merge(rand_vals))
69
+ end
70
+
71
+ puts "sending #{MESSAGES_TO_SEND} messages"
72
+ start_time = Time.now
73
+ sent_messages = 0
74
+ 1.upto(MESSAGES_TO_SEND) do
75
+ node = SAMPLE_NODES[rand(NUM_NODES)]
76
+ node = add_rand_keys(node)
77
+ index_data = {:action => :add}
78
+ index_data[:payload] = {:item => node}
79
+ index_data[:payload][:type] = :node
80
+ index_data[:payload][:database] = :testdb
81
+ index_data[:payload][:enqueued_at] = Time.now.utc.to_i
82
+
83
+ id = node["name"]
84
+ vnode = rand(1024)
85
+ index_data[:payload][:id] = id
86
+
87
+ puts "queue: vnode-#{vnode} (#{sent_messages} / #{MESSAGES_TO_SEND})"
88
+ amqp_client.tx_select if PERSISTENT_MESSAGES
89
+ queues[vnode].publish(Yajl::Encoder.encode(index_data), :persistent => PERSISTENT_MESSAGES)
90
+ amqp_client.tx_commit if PERSISTENT_MESSAGES
91
+ sent_messages += 1
92
+ end
93
+ end_time = Time.now
94
+
95
+ total_time = end_time - start_time
96
+ rate = MESSAGES_TO_SEND.to_f / total_time
97
+ puts "done (#{total_time}s, #{rate} msg/s)"
metadata ADDED
@@ -0,0 +1,284 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: erchef-expander
3
+ version: !ruby/object:Gem::Version
4
+ version: 11.4.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Adam Jacob
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mixlib-log
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.2.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.2.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: amqp
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.6.7
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.6.7
46
+ - !ruby/object:Gem::Dependency
47
+ name: eventmachine
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.12.10
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.12.10
62
+ - !ruby/object:Gem::Dependency
63
+ name: em-http-request
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.2.11
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.2.11
78
+ - !ruby/object:Gem::Dependency
79
+ name: yajl-ruby
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: '1.0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '1.0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: uuidtools
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 2.1.1
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 2.1.1
110
+ - !ruby/object:Gem::Dependency
111
+ name: bunny
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 0.6.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 0.6.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: fast_xs
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ version: 0.7.3
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ~>
140
+ - !ruby/object:Gem::Version
141
+ version: 0.7.3
142
+ - !ruby/object:Gem::Dependency
143
+ name: highline
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ~>
148
+ - !ruby/object:Gem::Version
149
+ version: 1.6.1
150
+ type: :runtime
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ version: 1.6.1
158
+ - !ruby/object:Gem::Dependency
159
+ name: rake
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ - !ruby/object:Gem::Dependency
175
+ name: rspec-core
176
+ requirement: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ type: :development
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ! '>='
188
+ - !ruby/object:Gem::Version
189
+ version: '0'
190
+ - !ruby/object:Gem::Dependency
191
+ name: rspec-expectations
192
+ requirement: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ! '>='
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ type: :development
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ - !ruby/object:Gem::Dependency
207
+ name: rspec-mocks
208
+ requirement: !ruby/object:Gem::Requirement
209
+ none: false
210
+ requirements:
211
+ - - ! '>='
212
+ - !ruby/object:Gem::Version
213
+ version: '0'
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ none: false
218
+ requirements:
219
+ - - ! '>='
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ description: A systems integration framework, built to bring the benefits of configuration
223
+ management to your entire infrastructure.
224
+ email: adam@opscode.com
225
+ executables:
226
+ - chef-expander
227
+ - chef-expander-vnode
228
+ - chef-expanderctl
229
+ extensions: []
230
+ extra_rdoc_files:
231
+ - README.rdoc
232
+ - LICENSE
233
+ files:
234
+ - LICENSE
235
+ - README.rdoc
236
+ - scripts/check_queue_size
237
+ - scripts/check_queue_size_munin
238
+ - scripts/make_solr_xml
239
+ - scripts/traffic-creator
240
+ - conf/chef-expander.rb.example
241
+ - lib/chef/expander/cluster_supervisor.rb
242
+ - lib/chef/expander/configuration.rb
243
+ - lib/chef/expander/control.rb
244
+ - lib/chef/expander/daemonizable.rb
245
+ - lib/chef/expander/flattener.rb
246
+ - lib/chef/expander/loggable.rb
247
+ - lib/chef/expander/logger.rb
248
+ - lib/chef/expander/node.rb
249
+ - lib/chef/expander/solrizer.rb
250
+ - lib/chef/expander/version.rb
251
+ - lib/chef/expander/vnode.rb
252
+ - lib/chef/expander/vnode_supervisor.rb
253
+ - lib/chef/expander/vnode_table.rb
254
+ - lib/chef/expander.rb
255
+ - bin/chef-expander
256
+ - bin/chef-expander-vnode
257
+ - bin/chef-expanderctl
258
+ homepage: http://wiki.opscode.com/display/chef
259
+ licenses: []
260
+ post_install_message:
261
+ rdoc_options: []
262
+ require_paths:
263
+ - lib
264
+ required_ruby_version: !ruby/object:Gem::Requirement
265
+ none: false
266
+ requirements:
267
+ - - ! '>='
268
+ - !ruby/object:Gem::Version
269
+ version: '0'
270
+ required_rubygems_version: !ruby/object:Gem::Requirement
271
+ none: false
272
+ requirements:
273
+ - - ! '>='
274
+ - !ruby/object:Gem::Version
275
+ version: '0'
276
+ requirements: []
277
+ rubyforge_project:
278
+ rubygems_version: 1.8.25
279
+ signing_key:
280
+ specification_version: 3
281
+ summary: A systems integration framework, built to bring the benefits of configuration
282
+ management to your entire infrastructure.
283
+ test_files: []
284
+ has_rdoc: true