Skip to content
This repository was archived by the owner on Feb 11, 2022. It is now read-only.

Additional Network Interfaces Support #358

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ This provider exposes quite a few provider-specific configuration options:
for credentials.
* `block_device_mapping` - Amazon EC2 Block Device Mapping Property
* `elb` - The ELB name to attach to the instance.
* `additional_network_interfaces` - An array of the extra network interfaces to create and attach once the machine is up

These can be set like typical provider-specific configuration:

Expand Down Expand Up @@ -265,6 +266,38 @@ Vagrant.configure("2") do |config|
end
```

### Additional Network Adapters

You can add extra network adapters to your instance after boot.

```ruby
Vagrant.configure("2") do |config|
# ... other stuff

config.vm.provider "aws" do |aws|

# subnet & security groups for primary network interface with device index 0
aws.subnet_id = 'subnet-caba8084'
aws.security_groups = 'sg-edb6e09b'

# add additonal interfaces after boot
aws.additional_network_interfaces = [
{
:device_index => 1,
:subnet_id => 'subnet-2f76b4e7',
:security_groups => ['sg-b2a58ce3', 'sg-008f7950'],
:private_ip_address => '172.16.110.200' #optional
},
{
:device_index => 2,
:subnet_id => 'subnet-e9725abc',
:security_groups => ['sg-0ded8ff6']
}
]
end
end
```

## Development

To work on the `vagrant-aws` plugin, clone this repository out, and use
Expand All @@ -283,10 +316,7 @@ $ bundle exec rake
If those pass, you're ready to start developing the plugin. You can test
the plugin without installing it into your Vagrant environment by just
creating a `Vagrantfile` in the top level of this directory (it is gitignored)
and add the following line to your `Vagrantfile`
```ruby
Vagrant.require_plugin "vagrant-aws"
```

Use bundler to execute Vagrant:
```
$ bundle exec vagrant up --provider=aws
Expand Down
8 changes: 6 additions & 2 deletions lib/vagrant-aws/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ def self.action_destroy
next
end
b3.use ConnectAWS
b3.use ElbDeregisterInstance
b3.use TerminateInstance
b3.use DestroyAdditionalNetworkInterfaces
b3.use ElbDeregisterInstance
b3.use TerminateInstance
b3.use ProvisionerCleanup if defined?(ProvisionerCleanup)
end
else
Expand Down Expand Up @@ -157,6 +158,7 @@ def self.action_up
else
b1.use action_prepare_boot
b1.use RunInstance # launch a new instance
b1.use RegisterAdditionalNetworkInterfaces
end
end
end
Expand Down Expand Up @@ -204,6 +206,8 @@ def self.action_reload
autoload :WarnNetworks, action_root.join("warn_networks")
autoload :ElbRegisterInstance, action_root.join("elb_register_instance")
autoload :ElbDeregisterInstance, action_root.join("elb_deregister_instance")
autoload :RegisterAdditionalNetworkInterfaces, action_root.join("network_adapters_register")
autoload :DestroyAdditionalNetworkInterfaces, action_root.join("network_adapters_destroy")
end
end
end
31 changes: 31 additions & 0 deletions lib/vagrant-aws/action/network_adapters_destroy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
require 'vagrant-aws/util/network_adapters'

module VagrantPlugins
module AWS
module Action
class DestroyAdditionalNetworkInterfaces
include NetworkAdapter

def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_aws::action::network_adapters_register")
end

def call(env)

interfaces = env[:machine].provider_config.additional_network_interfaces

interfaces.each do |intf|
env[:ui].info(I18n.t("vagrant_aws.destroy_network_interface"))
env[:ui].info(" -- Device Index: #{intf[:device_index]}")
env[:ui].info(" -- Attached To: #{env[:machine].id}")
destroy_adapter env, intf[:device_index], env[:machine].id
end

@app.call(env)

end
end
end
end
end
33 changes: 33 additions & 0 deletions lib/vagrant-aws/action/network_adapters_register.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require 'vagrant-aws/util/network_adapters'

module VagrantPlugins
module AWS
module Action
class RegisterAdditionalNetworkInterfaces
include NetworkAdapter

def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_aws::action::network_adapters_register")
end

def call(env)

@app.call(env)

interfaces = env[:machine].provider_config.additional_network_interfaces

interfaces.each do |intf|
env[:ui].info(I18n.t("vagrant_aws.creating_network_interface"))
env[:ui].info(" -- Device Index: #{intf[:device_index]}")
env[:ui].info(" -- Subnet ID: #{intf[:subnet_id]}")
env[:ui].info(" -- Security Groups: #{intf[:security_groups]}")
env[:ui].info(" -- IP: #{intf[:private_ip_address]}")
register_adapter env, intf[:device_index], intf[:subnet_id], intf[:security_groups], intf[:private_ip_address], env[:machine].id
end

end
end
end
end
end
4 changes: 2 additions & 2 deletions lib/vagrant-aws/action/run_instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def call(env)
iam_instance_profile_name = region_config.iam_instance_profile_name
monitoring = region_config.monitoring
ebs_optimized = region_config.ebs_optimized
associate_public_ip = region_config.associate_public_ip
associate_public_ip = region_config.associate_public_ip

# If there is no keypair then warn the user
if !keypair
Expand Down Expand Up @@ -90,7 +90,7 @@ def call(env)
:instance_initiated_shutdown_behavior => terminate_on_shutdown == true ? "terminate" : nil,
:monitoring => monitoring,
:ebs_optimized => ebs_optimized,
:associate_public_ip => associate_public_ip
:associate_public_ip => associate_public_ip
}
if !security_groups.empty?
security_group_key = options[:subnet_id].nil? ? :groups : :security_group_ids
Expand Down
9 changes: 8 additions & 1 deletion lib/vagrant-aws/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ class Config < Vagrant.plugin("2", :config)
# @return [String]
attr_accessor :elb

# The additional network adapters which should
# be attached to instance
#
# @return [Array<Hash>]
attr_accessor :additional_network_interfaces

def initialize(region_specific=false)
@access_key_id = UNSET_VALUE
@ami = UNSET_VALUE
Expand Down Expand Up @@ -190,6 +196,7 @@ def initialize(region_specific=false)
@ebs_optimized = UNSET_VALUE
@associate_public_ip = UNSET_VALUE
@elb = UNSET_VALUE
@additional_network_interfaces = []

# Internal state (prefix with __ so they aren't automatically
# merged)
Expand Down Expand Up @@ -389,7 +396,7 @@ def validate(machine)
end

errors << I18n.interpolate("vagrant_aws.config.ami_required", :region => @region) if config.ami.nil?
end
end

{ "AWS Provider" => errors }
end
Expand Down
66 changes: 66 additions & 0 deletions lib/vagrant-aws/util/network_adapters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
module VagrantPlugins
module AWS
module NetworkAdapter

def ip_attributes(ips)
return {} if ips.nil?

attrs = { 'PrivateIpAddresses.0.Primary' => true }

if ips.kind_of?(Array)
ips.each_with_index do |ip, i|
attrs["PrivateIpAddresses.#{i}.PrivateIpAddress"] = ip
end
else
attrs["PrivateIpAddresses.0.PrivateIpAddress"] = ips
end

attrs
end

def security_group_attributes(security_groups)
attrs = {}

if security_groups.kind_of?(Array)
security_groups.each_with_index do |sid, i|
attrs["SecurityGroupId.#{i + 1}"] = sid
end
else
attrs["SecurityGroupId.1"] = security_groups
end

attrs
end

def register_adapter(env, device_index, subnet_id, security_groups, private_ip_address, instance_id)

options = {}
options.merge! security_group_attributes(security_groups)
options.merge! ip_attributes(private_ip_address)

interface = env[:aws_compute].create_network_interface(
subnet_id,
options
).body['networkInterface']

env[:aws_compute].attach_network_interface(interface['networkInterfaceId'], instance_id, device_index)
end

def destroy_adapter(env, device_index, instance_id)
interface = env[:aws_compute].network_interfaces.all('attachment.instance-id' => instance_id, 'attachment.device-index' => device_index ).first

if interface.nil?
return
end

if !interface.attachment.nil? && interface.attachment != {}
env[:aws_compute].detach_network_interface(interface.attachment['attachmentId'], true)
interface.wait_for { attachment.nil? || attachment == {} }
end

interface.destroy
end

end
end
end
4 changes: 4 additions & 0 deletions locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ en:
will_not_destroy: |-
The instance '%{name}' will not be destroyed, since the confirmation
was declined.
creating_network_interface: |-
Creating additional network interface with the following settings...
destroy_network_interface: |-
Destroying additional network interface...

config:
access_key_id_required: |-
Expand Down
1 change: 1 addition & 0 deletions spec/vagrant-aws/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
its("monitoring") { should == false }
its("ebs_optimized") { should == false }
its("associate_public_ip") { should == false }
its("additional_network_interfaces") { should == [] }
end

describe "overriding defaults" do
Expand Down