ronin-wrapper 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: abbaae6f9eb9b85bdd62306744e01415bfa0ca39
4
+ data.tar.gz: a4018b391c6b73483bffda7edd671c42f0f1eedd
5
+ SHA512:
6
+ metadata.gz: 16c4662ff8236712752d680cfb57c8420b47342fda32ef06cb7ac0f48fb3413c7e0c9297f1e08f988b5f331c7bc90997e73490604faf4e3c455ecf781d3a1e89
7
+ data.tar.gz: 8b117c963b14ba526777ce57ba74ce9269ef2b024a7937f303d7f014e14099c66da2e7a29fa2838b072b8d6aa9c43463bc59781fd85a0d178faf73979e4ee50a
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ ronin
2
+ =====
3
+
4
+ A wrapper to enable masterless configuration management, using Chef and/or Puppet.
data/bin/ronin ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # Author:: Nathan Milford (<nathan@milford.io>)
3
+ # Copyright:: Copyright (c) 2013 Nathan Milford
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ require 'ronin'
18
+
19
+ Ronin.run
data/lib/ronin/chef.rb ADDED
@@ -0,0 +1,24 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require 'ronin/run_list'
17
+ require 'ronin/config'
18
+ require 'ronin/log'
19
+
20
+ module Ronin
21
+ module Chef
22
+ # tbd
23
+ end
24
+ end
@@ -0,0 +1,42 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require 'mixlib/config'
17
+
18
+ module Ronin
19
+ class Config
20
+ extend Mixlib::Config
21
+
22
+ config_file = '/etc/ronin/ronin.rb'
23
+
24
+ if File.exist?(config_file)
25
+ Ronin::Config.from_file(config_file)
26
+ else
27
+ Ronin::Log.warn("No configuration file at #{config_file}, using defaults.")
28
+ end
29
+
30
+ config_strict_mode true
31
+ default :log_path, '/var/log/ronin'
32
+ default :log_level, :info
33
+ default :update_on_change, true
34
+ default :run_list_type, :yaml
35
+ default :interpreter, :puppet
36
+ default :run_list_file, '/etc/ronin/modules.yaml'
37
+ default :module_path, '/var/lib/modules'
38
+ default :git_url, 'https://github.com/puppetlabs'
39
+ end
40
+ end
41
+
42
+
data/lib/ronin/git.rb ADDED
@@ -0,0 +1,44 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require "mixlib/shellout"
17
+ require 'ronin/config'
18
+
19
+ module Ronin
20
+ module Git
21
+ def branch(mod)
22
+ @cmd = Mixlib::ShellOut.new("git --git-dir=#{Ronin::Config[:module_path]}/#{mod}/.git --work-tree=#{Ronin::Config[:module_path]}/#{mod}/ branch")
23
+ @cmd.run_command
24
+ @branch = @cmd.stdout.chomp.split(' ')[1]
25
+ @branch
26
+ end
27
+ module_function :branch
28
+
29
+ def pull_and_report_updated(mod)
30
+ @cmd = Mixlib::ShellOut.new("git --git-dir=#{Ronin::Config[:module_path]}/#{mod}/.git --work-tree=#{Ronin::Config[:module_path]}/#{mod}/ pull")
31
+ @cmd.run_command
32
+ @updated = @cmd.stdout.include?("Updating")
33
+ @updated ? true : false
34
+ end
35
+ module_function :pull_and_report_updated
36
+
37
+ def clone(mod, branch)
38
+ @cmd = Mixlib::ShellOut.new("git clone #{Ronin::Config[:git_url]}/#{mod}/ #{Ronin::Config[:module_path]}/#{mod}/ -b #{branch}")
39
+ @cmd.run_command
40
+ puts @cmd.stdout
41
+ end
42
+ module_function :clone
43
+ end
44
+ end
data/lib/ronin/log.rb ADDED
@@ -0,0 +1,28 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require 'ronin/config'
17
+ require 'mixlib/log'
18
+
19
+ module Ronin
20
+ class Log
21
+ extend Mixlib::Log
22
+
23
+ logfile = "#{Ronin::Config[:log_path]}/ronin.log"
24
+
25
+ init(logfile)
26
+ self.level = Ronin::Config[:log_level]
27
+ end
28
+ end
@@ -0,0 +1,71 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.require 'ronin/run_list'
16
+ require 'ronin/config'
17
+ require 'ronin/git'
18
+ require 'ronin/log'
19
+ require 'fileutils'
20
+
21
+ module Ronin
22
+ class ModuleRunner
23
+ def initialize
24
+ @changes = false
25
+ @run_list = Ronin::RunList.new
26
+ end
27
+
28
+ def download_and_report_changes
29
+ @run_list.items.each do |item|
30
+ @actual_branch = Ronin::Git.branch(item[:name])
31
+
32
+ if File.exist?("#{Ronin::Config[:module_path]}/#{item[:name]}")
33
+ if item[:branch] != 'master'
34
+ Ronin::Log.info("Module #{item[:name]} is being pulled from the #{item[:branch]} branch and not master.")
35
+ end
36
+
37
+ if @actual_branch == item[:branch]
38
+ Ronin::Log.info("Module #{item[:name]} already cached, pulling updates to #{item[:branch]} from #{item[:repo]}.")
39
+ @updated = Ronin::Git.pull_and_report_updated(item[:name])
40
+ if @updated
41
+ Ronin::Log.info("Module #{item[:name]} has updates.")
42
+ @changes = true if Ronin::Config[:update_on_change]
43
+ end
44
+ else
45
+ Ronin::Log.info("Module #{item[:name]} already cached, but is the wrong branch. Deleting cached copy of branch #{@actual_branch}")
46
+ FileUtils.rm_rf("#{Ronin::Config[:module_path]}/#{item[:name]}/")
47
+ Ronin::Git.clone(item[:name], item[:branch])
48
+ @changes = true if Ronin::Config[:update_on_change]
49
+ end
50
+ else
51
+ Ronin::Log.info("Module #{item[:name]} not cached, cloning branch #{item[:branch]} of #{item[:repo]} to #{Ronin::Config[:module_path]}.")
52
+ Ronin::Git.clone(item[:name], item[:branch])
53
+ @changes = true if Ronin::Config[:update_on_change]
54
+ end
55
+ end
56
+ @changes
57
+ end
58
+
59
+ def purge_unused
60
+ @local_modules = Dir.entries(Ronin::Config[:module_path]).select { |dir| File.directory?("#{Ronin::Config[:module_path]}/#{dir}") and !(dir =='.' || dir == '..') }
61
+ @modules = @run_list.modules
62
+
63
+ @local_modules.each do |mod|
64
+ unless @modules.include?(mod)
65
+ Ronin::Log.info("No module named #{mod} in run list, but it exists in #{Ronin::Config[:module_path]}. Purging it.")
66
+ FileUtils.rm_rf("#{Ronin::Config[:module_path]}/#{mod}/")
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,52 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require 'ronin/run_list'
17
+ require 'ronin/config'
18
+ require 'ronin/log'
19
+
20
+ module Ronin
21
+ module Puppet
22
+
23
+ @run_list = "#{Ronin::Config[:module_path]}/ronin.pp"
24
+ @modules = Ronin::RunList.new.modules
25
+
26
+ def create_run_list
27
+ Ronin::Log.info("Building Puppet run list at #{@run_list}.")
28
+ File.open(@run_list, "w") do |f|
29
+ @modules.each do |mod|
30
+ Ronin::Log.info("Adding module '#{mod}' to run list.")
31
+ f.write "include #{mod}\n"
32
+ end
33
+ end
34
+ end
35
+ module_function :create_run_list
36
+
37
+ def run
38
+ self.create_run_list
39
+ Ronin::Log.info("Running Puppet, logging puppet output to #{Ronin::Config[:log_path]}/ronin-puppet.log.")
40
+ @cmd = Mixlib::ShellOut.new("puppet apply --verbose --ordering manifest --logdest #{Ronin::Config[:log_path]}/ronin-puppet.log --modulepath #{Ronin::Config[:module_path]} #{@run_list}")
41
+ @cmd.run_command
42
+ self.clean_up
43
+ end
44
+ module_function :run
45
+
46
+ def clean_up
47
+ Ronin::Log.info("Cleaning up Puppet run list at #{@run_list}.")
48
+ File.delete(@run_list)
49
+ end
50
+ module_function :clean_up
51
+ end
52
+ end
@@ -0,0 +1,44 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ $LOAD_PATH << "."
17
+ require 'ronin/module_runner'
18
+ require 'ronin/run_list'
19
+ require 'ronin/config'
20
+
21
+ module Ronin
22
+ def run
23
+
24
+ unless Process.uid == 0
25
+ puts 'You need to be root to perform this command.'
26
+ exit 1
27
+ end
28
+
29
+ Ronin::Log.level = Ronin::Config[:log_level]
30
+
31
+ @r = Ronin::ModuleRunner.new
32
+ @changes = @r.download_and_report_changes
33
+ @r.purge_unused
34
+
35
+ if @changes
36
+ if Ronin::Config[:interpreter] = :puppet
37
+ Ronin::Puppet.run
38
+ elsif Ronin::Config[:interpreter] = :chef
39
+ Ronin::Chef.run
40
+ end
41
+ end
42
+ end
43
+ module_function :run
44
+ end
@@ -0,0 +1,59 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require 'mixlib/config'
17
+ require 'yaml'
18
+
19
+ module Ronin
20
+ class RunList
21
+ include Enumerable
22
+
23
+ def initialize
24
+ @run_list = {}
25
+ if Ronin::Config['run_list_type'] = :yaml
26
+ @modules_raw = YAML.load_file(Ronin::Config['run_list_file'])['modules']
27
+ end
28
+
29
+ @modules_raw.each do |m|
30
+ if m.include?(";")
31
+ @repo = m.split(";")[0].sub(/(\/)+$/,'')
32
+ @branch = m.split(";")[1]
33
+ else
34
+ @repo = m
35
+ @branch = 'master'
36
+ end
37
+
38
+ @name = @repo.split("/").last
39
+
40
+ @run_list[@name] = { :name => @name, :repo => @repo, :branch => @branch }
41
+ end
42
+
43
+ @run_list
44
+ end
45
+
46
+ def modules
47
+ @mods = []
48
+ @run_list.each { |k,v| @mods << k }
49
+ @mods
50
+ end
51
+
52
+ def items
53
+ @items = []
54
+ @run_list.each { |k,v| @items << { :name => v[:name], :repo => v[:repo], :branch => v[:branch] } }
55
+ @items
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,18 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ module Ronin
17
+ VERSION = '0.0.6'
18
+ end
data/lib/ronin.rb ADDED
@@ -0,0 +1,24 @@
1
+ # Author:: Nathan Milford (<nathan@milford.io>)
2
+ # Copyright:: Copyright (c) 2013 Nathan Milford
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ require 'ronin/config'
17
+ require 'ronin/module_runner'
18
+ require 'ronin/run_list'
19
+ require 'ronin/version'
20
+ require 'ronin/puppet'
21
+ require 'ronin/ronin'
22
+ require 'ronin/chef'
23
+ require 'ronin/git'
24
+ require 'ronin/log'
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ronin-wrapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Milford
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-12-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: puppet
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yajl-ruby
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mixlib-log
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mixlib-config
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: mixlib-shellout
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.3'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.1'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.1'
97
+ description: A wrapper to enable masterless configuration management, using Chef and/or
98
+ Puppet.
99
+ email: nathan@milford.io
100
+ executables:
101
+ - ronin
102
+ extensions: []
103
+ extra_rdoc_files:
104
+ - README.md
105
+ files:
106
+ - README.md
107
+ - bin/ronin
108
+ - lib/ronin.rb
109
+ - lib/ronin/chef.rb
110
+ - lib/ronin/config.rb
111
+ - lib/ronin/git.rb
112
+ - lib/ronin/log.rb
113
+ - lib/ronin/module_runner.rb
114
+ - lib/ronin/puppet.rb
115
+ - lib/ronin/ronin.rb
116
+ - lib/ronin/run_list.rb
117
+ - lib/ronin/version.rb
118
+ homepage: https://github.com/nmilford/ronin
119
+ licenses:
120
+ - ASF 2.0
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.2.0
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: A framework for masterless configuration management.
142
+ test_files: []