vagrant-auto_network 0.2.2 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NzlhOTk0NThjMzA5MTNkYzZhYzFiNTJkZDU1ODQzOGE0YWU2NDU4Mg==
5
- data.tar.gz: !binary |-
6
- YzIxNzVkYzI0N2RlMTkyZjAyYjA3OWNlNjgzMjhlN2JhZTcyMDlkYg==
2
+ SHA1:
3
+ metadata.gz: 1d671793aef1384eda1a6563c8c5c82fb5ef080f
4
+ data.tar.gz: d1e246dfdc649d07761ae4d778557ff796fb66af
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NGUxNjYyM2JlYTRmZTEwOTI4ZjMxZGJkMmIxMzljYjRhZjUxMzBjNmQ1NGRj
10
- YTg4NjVjY2ZlNzdiOGM3ZTZhNmM4Yjk5N2QwZmIyZTAwOGY2MjNlMDFkOTVm
11
- NTlmYjBlN2JiMWI3MGY4Yjg3OWUwYTQ0NWQyMjg3ZTFkYTY1MTc=
12
- data.tar.gz: !binary |-
13
- NjgwZTBlYmMwMmZlZTUyNjM2YTUxMWY5NDgwZDg2ZmU3ZjllYTNjNmMzOGE2
14
- ZDE3NDNlNjhjZDZmNDc0MDA1MzZlNGQ2MTg5OTExOTFjMjJjMWY2YzhkMmU1
15
- YjY2YTMyODY2ZmI0NjM4MmI0ZjM1YTQ4NTRiNGRkNGY2Y2QzODU=
6
+ metadata.gz: de702cdcb9d60ab2d1f55116b9a6d7a4cd4f392892e49fba9ae4764c87fe2c0024e6916f439f963e2bec84b77d568a6b73bef3abd427e1f0a1499bb19a7a8d77
7
+ data.tar.gz: e83c9eb3a06775ccf5fa59e5ab837a6d05f767f36babc1ce9ee7a5f08a1826a7ea18107df9df2df230032cc792cb377fc1da20e67538b1c53ada63f0b1c64e5d
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown
data/CHANGELOG CHANGED
@@ -1,6 +1,32 @@
1
1
  vagrant-auto_network
2
2
  ====================
3
3
 
4
+ 1.0.0
5
+ -----
6
+
7
+ 2014-05-05
8
+
9
+ This is a mostly-backwards compatible feature release.
10
+
11
+ For this release, serialization format has been completely re-written to add
12
+ support for multiple providers and to better manage global state and guard
13
+ against race conditions. Care has been taken to support existing AutoNetwork
14
+ environments, but it is possible that some breakage will occur.
15
+
16
+ Specifically, the following issues have been addressed:
17
+
18
+ * (GH-12) Support for more than just the VirtualBox provider. The
19
+ implementation has been tested against the VMware Fusion provider but
20
+ should be general enough to support other providers as well.
21
+
22
+ * (GH-2) The infamous `0.0.0.0` hack is no longer necessary when using
23
+ AutoNetwork.
24
+
25
+ * (GH-6) The IP address pools managed by AutoNetwork are now backed by a
26
+ storage mechanism that offers more resiliance to race conditions and data
27
+ loss from aborted actions.
28
+
29
+
4
30
  0.2.2
5
31
  -----
6
32
 
data/Gemfile CHANGED
@@ -1,3 +1,12 @@
1
1
  source 'https://rubygems.org'
2
+ ruby '2.0.0'
2
3
 
3
4
  gemspec
5
+
6
+ group :development do
7
+ gem 'vagrant', :github => 'mitchellh/vagrant', :tag => 'v1.5.4'
8
+ end
9
+
10
+ if File.exists? "#{__FILE__}.local"
11
+ eval(File.read("#{__FILE__}.local"), binding)
12
+ end
data/lib/auto_network.rb CHANGED
@@ -7,6 +7,7 @@ module AutoNetwork
7
7
  require 'auto_network/mixin'
8
8
  require 'auto_network/plugin'
9
9
  require 'auto_network/version'
10
+ require 'auto_network/pool_manager'
10
11
  end
11
12
 
12
13
  I18n.load_path << File.expand_path('../templates/locales/en.yml', File.dirname(__FILE__))
@@ -50,7 +50,7 @@ class AutoNetwork::Action::FilterNetworks
50
50
  def assign_address(machine)
51
51
  machine_auto_networks(machine).each do |net|
52
52
  addr = @pool.address_for(machine)
53
- @logger.info "Reassigning #{addr.inspect} to existing machine #{machine.id}"
53
+ @logger.info "Reassigning #{addr.inspect} to existing machine #{machine.name}"
54
54
  filter_private_network(net, addr)
55
55
  end
56
56
  end
@@ -1,5 +1,4 @@
1
1
  require 'auto_network'
2
- require 'yaml'
3
2
 
4
3
  class AutoNetwork::Action::LoadPool
5
4
 
@@ -23,7 +22,6 @@ class AutoNetwork::Action::LoadPool
23
22
  setup_ivars
24
23
  deserialize!
25
24
  @app.call(@env)
26
- serialize!
27
25
  else
28
26
  @app.call(@env)
29
27
  end
@@ -41,21 +39,6 @@ class AutoNetwork::Action::LoadPool
41
39
  end
42
40
 
43
41
  def deserialize!
44
- pool = nil
45
- if @statefile.exist?
46
- pool = YAML.load(@statefile.read)
47
- else
48
- range = AutoNetwork.default_pool
49
- @env[:ui].info "No auto_network pool available, generating a pool with the range #{range}"
50
- pool = AutoNetwork::Pool.new(range)
51
- end
52
- @env[:auto_network_pool] = pool
53
- end
54
-
55
- def serialize!
56
- @config_path.mkpath unless @config_path.exist?
57
-
58
- pool_data = YAML.dump(@env[:auto_network_pool])
59
- @statefile.open('w') { |fh| fh.write(pool_data) }
42
+ @env[:auto_network_pool] = AutoNetwork::PoolManager.new(@statefile)
60
43
  end
61
44
  end
@@ -31,7 +31,7 @@ class AutoNetwork::Action::Release
31
31
 
32
32
  def release_network_addresses
33
33
  addr = @pool.address_for(@machine)
34
- @env[:ui].info "Releasing #{addr.inspect} from #{@machine.id}", :prefix => true
34
+ @env[:ui].info "Releasing #{addr.inspect} from #{@machine.name}", :prefix => true
35
35
  @pool.release(@machine)
36
36
  end
37
37
  end
@@ -32,7 +32,7 @@ class AutoNetwork::Action::Request
32
32
  def request_address
33
33
  machine_auto_networks(@machine).each do |net|
34
34
  addr = @pool.request(@machine)
35
- @env[:ui].info "Assigning #{addr.inspect} to '#{@machine.id}'", :prefix => true
35
+ @env[:ui].info "Assigning #{addr.inspect} to '#{@machine.name}'", :prefix => true
36
36
  filter_private_network(net, addr)
37
37
  end
38
38
  end
@@ -19,14 +19,18 @@ module AutoNetwork
19
19
  hook.after(action, AutoNetwork::Action::FilterNetworks)
20
20
  end
21
21
 
22
- action_hook('Auto network: request address', :machine_action_up) do |hook|
23
- action = VagrantPlugins::ProviderVirtualBox::Action::Network
22
+ action_hook('Auto network: request address') do |hook|
23
+ action = Vagrant::Action::Builtin::ConfigValidate
24
24
  hook.before(action, AutoNetwork::Action::Request)
25
25
  end
26
26
 
27
27
  action_hook('Auto network: release address', :machine_action_destroy) do |hook|
28
- action = VagrantPlugins::ProviderVirtualBox::Action::Destroy
29
- hook.before(action, AutoNetwork::Action::Release)
28
+ # This is redundant, but the VirtualBox Destroy Action flushes UUID
29
+ # values. So we double the hook here as it is our only chance to clean
30
+ # old-style IDs out of the cache.
31
+ hook.before(VagrantPlugins::ProviderVirtualBox::Action::Destroy, AutoNetwork::Action::Release)
32
+
33
+ hook.append(AutoNetwork::Action::Release)
30
34
  end
31
35
  end
32
36
  end
@@ -1,28 +1,43 @@
1
1
  require 'ipaddr'
2
+ require 'vagrant/errors'
2
3
 
3
4
  module AutoNetwork
5
+ # The Pool is a class that manages a range of IP addresses and manages the
6
+ # allocation of specific addresses to individual Vagrant machines.
4
7
  class Pool
5
8
 
9
+ # An error class raised when no allocatable addresses remain in the Pool.
10
+ #
11
+ # @api private
6
12
  class PoolExhaustedError < Vagrant::Errors::VagrantError
7
13
  error_key(:pool_exhausted, 'vagrant_auto_network')
8
14
  end
9
15
 
10
- # @param network_addr [String] The network address range to use as the
16
+ # @!attribute [r] network_range
17
+ # @return [String] The address range manged by this Pool instance.
18
+ attr_reader :network_range
19
+
20
+ # Create a new Pool object that manages a range of IP addresses.
21
+ #
22
+ # @param network_range [String] The network address range to use as the
11
23
  # address pool.
12
24
  def initialize(network_range)
13
25
  @network_range = network_range
14
26
  generate_pool
15
27
  end
16
28
 
17
- # Retrieve an IP address for the given machine. If a machine already has
18
- # an IP address requested, then return that.
29
+ # Allocate an IP address for the given machine. If a machine already has an
30
+ # IP address allocated, then return that.
19
31
  #
20
32
  # @param machine [Vagrant::Machine]
33
+ # @return [IPAddr] the IP address assigned to the machine.
34
+ # @raise [PoolExhaustedError] if no allocatable addresses remain in the
35
+ # range managed by the pool.
21
36
  def request(machine)
22
37
  if (address = address_for(machine))
23
38
  return address
24
39
  elsif (address = next_available_lease)
25
- @pool[address] = machine.id
40
+ @pool[address] = id_for(machine)
26
41
  return address
27
42
  else
28
43
  raise PoolExhaustedError,
@@ -31,20 +46,41 @@ module AutoNetwork
31
46
  end
32
47
  end
33
48
 
34
- # Release an IP address associated with a machine
49
+ # Release an IP address associated with a machine.
35
50
  #
36
51
  # @param machine [Vagrant::Machine]
52
+ # @return [nil]
37
53
  def release(machine)
38
54
  if (address = address_for(machine))
39
55
  @pool[address] = nil
40
56
  end
41
57
  end
42
58
 
59
+ # Look up the address assigned to a given machine.
60
+ #
61
+ # @param machine [Vagrant::Machine]
62
+ # @return [IPAddr] the IP address assigned to the machine.
63
+ # @return [nil] if the machine has no address assigned.
43
64
  def address_for(machine)
44
- return nil if machine.id.nil?
45
- next_addr, _ = @pool.find { |(addr, id)| machine.id == id }
65
+ machine_id = id_for(machine)
66
+ addr, _ = @pool.find do |(addr, id)|
67
+ if id.is_a?(String)
68
+ # Check for old-style UUID values. These should eventually cycle out
69
+ # as machines are destroyed.
70
+ id == machine.id
71
+ else
72
+ id == machine_id
73
+ end
74
+ end
46
75
 
47
- next_addr
76
+ addr
77
+ end
78
+
79
+ def id_for(machine)
80
+ {
81
+ 'path' => machine.env.root_path.to_s,
82
+ 'name' => machine.name.to_s,
83
+ }
48
84
  end
49
85
 
50
86
  private
@@ -0,0 +1,130 @@
1
+ require 'auto_network/pool'
2
+ require 'auto_network/pool_storage'
3
+ require 'ipaddr'
4
+
5
+ module AutoNetwork
6
+ # The `PoolManager` class manages the mapping between providers and pools of
7
+ # IP addresses. Each `PoolManager` instance is backed by a file that persists
8
+ # state and attempts to prevent race conditions between multiple Vagrant
9
+ # processes.
10
+ #
11
+ # Once created, `PoolManager` instances proxy the public interface of the
12
+ # {AutoNetwork::Pool} instances they manage. New pools will be allocated as
13
+ # needed and all pool operations are wrapped in transactions that ensure
14
+ # state is synced to the file system.
15
+ #
16
+ # @see AutoNetwork::PoolStorage The object used to implement file-based
17
+ # persistance for this class.
18
+ # @see AutoNetwork::Pool The objects managed by this class.
19
+ class PoolManager
20
+ # Create a new `PoolManager` instance with persistent storage.
21
+ #
22
+ # @param path [String, Pathname] the location at which to persist the state
23
+ # of `AutoNetwork` pools.
24
+ def initialize(path)
25
+ # Ensure newly created files start with a skeleton data structure.
26
+ AutoNetwork::PoolStorage.init(path) unless File.file?(path)
27
+ @pool_storage = AutoNetwork::PoolStorage.new(path)
28
+ end
29
+
30
+ # Looks up the pool associated with the provider for a given machine and
31
+ # sets up a transaction where the state of the pool can be safely inspected
32
+ # or modified. If a pool does not exist for the machine provider, one will
33
+ # automatically be created.
34
+ #
35
+ # @param machine [Vagrant::Machine]
36
+ # @param read_only [Boolean] whether to create a read_only transaction.
37
+ # @yieldparam pool [AutoNetwork::Pool]
38
+ def with_pool_for(machine, read_only=false)
39
+ @pool_storage.transaction(read_only) do
40
+ pool = lookup_pool_for(machine)
41
+ pool ||= generate_pool_for(machine)
42
+
43
+ yield pool
44
+ end
45
+ end
46
+
47
+ # {include:AutoNetwork::Pool#request}
48
+ #
49
+ # @see AutoNetwork::Pool#request
50
+ def request(machine)
51
+ with_pool_for(machine) do |pool|
52
+ pool.request(machine)
53
+ end
54
+ end
55
+
56
+ # {include:AutoNetwork::Pool#release}
57
+ #
58
+ # @see AutoNetwork::Pool#release
59
+ def release(machine)
60
+ with_pool_for(machine) do |pool|
61
+ pool.release(machine)
62
+ end
63
+ end
64
+
65
+ # {include:AutoNetwork::Pool#address_for}
66
+ #
67
+ # @see AutoNetwork::Pool#address_for
68
+ def address_for(machine)
69
+ with_pool_for(machine, read_only=true) do |pool|
70
+ pool.address_for(machine)
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ # Retrieve the {AutoNetwork::Pool} assigned to the provider of a given
77
+ # machine.
78
+ #
79
+ # @note This must be executed within a transaction.
80
+ # @api private
81
+ #
82
+ # @param machine [Vagrant::Machine]
83
+ # @return [AutoNetwork::Pool] the pool associated with the machine
84
+ # provider.
85
+ # @return [nil] if no pool exists for the machine provider.
86
+ def lookup_pool_for(machine)
87
+ @pool_storage['pools'][machine.provider_name.to_s]
88
+ end
89
+
90
+ # Create an {AutoNetwork::Pool} assigned to the provider of a given
91
+ # machine.
92
+ #
93
+ # @note This must be executed within a transaction.
94
+ # @api private
95
+ #
96
+ # @param machine [Vagrant::Machine]
97
+ # @return [AutoNetwork::Pool] the pool associated with the machine
98
+ # provider.
99
+ def generate_pool_for(machine)
100
+ if lookup_pool_for(machine).nil?
101
+ @pool_storage['pools'][machine.provider_name.to_s] = AutoNetwork::Pool.new(next_pool_range)
102
+ end
103
+
104
+ lookup_pool_for(machine)
105
+ end
106
+
107
+ # Scan the list of allocated pools and determine the next usable address
108
+ # range. Assumes all Pools use a "/24" address range and share the same
109
+ # "/16" range.
110
+ #
111
+ # @note This must be executed within a transaction.
112
+ # @api private
113
+ #
114
+ # @return [String] an IP range ending in "/24".
115
+ def next_pool_range
116
+ # Fetch the list of pools under management. Return nil if no pools exist.
117
+ pools = @pool_storage.fetch('pools', nil)
118
+
119
+ if pools.empty?
120
+ # If no pools have been created, use the default range.
121
+ AutoNetwork.default_pool
122
+ else
123
+ # Look up the highest "XX.XX.YY.XX/24" range in use.
124
+ last_pool_range = IPAddr.new(pools.values.map{|v| v.network_range}.sort.last)
125
+ # Increment "YY" by one to generate a new "/24" range.
126
+ ((last_pool_range >> 8).succ << 8).to_s + '/24'
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,64 @@
1
+ require 'yaml/store'
2
+ require 'auto_network/pool'
3
+
4
+ module AutoNetwork
5
+ # This is a specialized subclass of `YAML::Store` that knows how to
6
+ # initialize and upgrade AutoNetwork Pool files.
7
+ #
8
+ # @api private
9
+ class PoolStorage < YAML::Store
10
+ POOLFILE_VERSION = 2
11
+ POOLFILE_SKELETON = {
12
+ 'poolfile_version' => POOLFILE_VERSION,
13
+ 'pools' => {},
14
+ }
15
+
16
+ # Creates a new pool file at a target location and fills it with default
17
+ # data.
18
+ #
19
+ # @param path [String, Pathname] the location of the new pool file.
20
+ # @return [void]
21
+ def self.init(path)
22
+ File.write(path, POOLFILE_SKELETON.to_yaml)
23
+ end
24
+
25
+ private
26
+
27
+ # Override the method inherited from `YAML::Store`. All `PStore` object
28
+ # expect load to strictly return a `Hash`. This override allows us to
29
+ # perform on-the-fly upgrading of data loaded from old pool files and
30
+ # ensure the right structure is returned.
31
+ #
32
+ # @api private
33
+ #
34
+ # @param content [String] serialized YAML read from the pool file.
35
+ # @return [Hash]
36
+ def load(content)
37
+ data = super(content)
38
+
39
+ if data.is_a? AutoNetwork::Pool
40
+ upgrade_from_version_1! data
41
+ else
42
+ data
43
+ end
44
+ end
45
+
46
+ # The loosely defined "version 1" of the pool file just serialized a single
47
+ # {AutoNetwork::Pool} object. All AutoNetwork releases that used Version 1
48
+ # files only supported the Vagrant VirtualBox provider, so we return a new
49
+ # Hash-based data structure that includes the old Pool.
50
+ #
51
+ # @api private
52
+ #
53
+ # @param data [AutoNetwork::Pool] the old pool object.
54
+ # @return [Hash] a hash containing the old pool object.
55
+ def upgrade_from_version_1!(data)
56
+ {
57
+ 'poolfile_version' => POOLFILE_VERSION,
58
+ 'pools' => {
59
+ 'virtualbox' => data,
60
+ },
61
+ }
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,3 @@
1
1
  module AutoNetwork
2
- VERSION = '0.2.2'
2
+ VERSION = '1.0.0.beta1'
3
3
  end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe AutoNetwork::Pool do
4
+ let(:ip_range) { '10.20.1.0/24' }
5
+ let(:machine_a) do
6
+ machine = double(
7
+ :name => 'machine_a',
8
+ :id => 'some-uuid',
9
+ )
10
+ machine.stub_chain(:env, :root_path, :to_s).and_return('/some/Vagrantfile')
11
+
12
+ machine
13
+ end
14
+ let(:machine_b) do
15
+ machine = double(
16
+ :name => 'machine_b',
17
+ :id => 'some-uuid',
18
+ )
19
+ machine.stub_chain(:env, :root_path, :to_s).and_return('/some/Vagrantfile')
20
+
21
+ machine
22
+ end
23
+
24
+ subject { AutoNetwork::Pool.new(ip_range) }
25
+
26
+ describe 'requesting an address for a machine' do
27
+
28
+ it 'returns the next available address' do
29
+ expect(subject.request(machine_a)).to eq('10.20.1.2')
30
+ end
31
+
32
+ it 'is idempotent' do
33
+ subject.request(machine_a)
34
+ expect(subject.request(machine_a)).to eq('10.20.1.2')
35
+ end
36
+
37
+ context 'when the pool is full' do
38
+ subject { AutoNetwork::Pool.new('10.20.1.0/30') }
39
+
40
+ it 'raises an error' do
41
+ subject.request(machine_a)
42
+ expect { subject.request(machine_b) }.to raise_error(AutoNetwork::Pool::PoolExhaustedError)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ describe 'releasing an address from a machine' do
49
+
50
+ it 'makes the address available' do
51
+ subject.request(machine_a)
52
+ subject.release(machine_a)
53
+ expect(subject.request(machine_b)).to eq('10.20.1.2')
54
+ end
55
+
56
+ end
57
+
58
+ describe 'looking up an address for a machine' do
59
+
60
+ it 'returns the address assigned' do
61
+ subject.request(machine_a)
62
+ expect(subject.address_for(machine_a)).to eq('10.20.1.2')
63
+ end
64
+
65
+ it 'returns nil for unassigned machines' do
66
+ expect(subject.address_for(machine_b)).to be_nil
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ require 'rspec'
4
+ require 'auto_network'
@@ -17,4 +17,6 @@ Gem::Specification.new do |gem|
17
17
  gem.require_path = 'lib'
18
18
 
19
19
  gem.license = 'Apache 2.0'
20
+
21
+ gem.add_development_dependency 'rspec', '~> 2.14.0'
20
22
  end
metadata CHANGED
@@ -1,21 +1,36 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-auto_network
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 1.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrien Thebo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-19 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2014-05-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 2.14.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 2.14.0
13
27
  description:
14
28
  email: adrien@somethingsinistral.net
15
29
  executables: []
16
30
  extensions: []
17
31
  extra_rdoc_files: []
18
32
  files:
33
+ - .yardopts
19
34
  - CHANGELOG
20
35
  - Gemfile
21
36
  - README.markdown
@@ -30,8 +45,12 @@ files:
30
45
  - lib/auto_network/mixin.rb
31
46
  - lib/auto_network/plugin.rb
32
47
  - lib/auto_network/pool.rb
48
+ - lib/auto_network/pool_manager.rb
49
+ - lib/auto_network/pool_storage.rb
33
50
  - lib/auto_network/version.rb
34
51
  - lib/vagrant-auto_network.rb
52
+ - spec/auto_network/pool/pool_spec.rb
53
+ - spec/spec_helper.rb
35
54
  - templates/locales/en.yml
36
55
  - vagrant-auto_network.gemspec
37
56
  homepage: https://github.com/adrienthebo/vagrant-auto_network
@@ -44,19 +63,18 @@ require_paths:
44
63
  - lib
45
64
  required_ruby_version: !ruby/object:Gem::Requirement
46
65
  requirements:
47
- - - ! '>='
66
+ - - '>='
48
67
  - !ruby/object:Gem::Version
49
68
  version: '0'
50
69
  required_rubygems_version: !ruby/object:Gem::Requirement
51
70
  requirements:
52
- - - ! '>='
71
+ - - '>'
53
72
  - !ruby/object:Gem::Version
54
- version: '0'
73
+ version: 1.3.1
55
74
  requirements: []
56
75
  rubyforge_project:
57
- rubygems_version: 2.2.1
76
+ rubygems_version: 2.0.14
58
77
  signing_key:
59
78
  specification_version: 4
60
79
  summary: Automatically create an internal network for all vagrant boxes
61
80
  test_files: []
62
- has_rdoc: