Class: VirtualBox::ForwardedPort

Inherits:
AbstractModel show all
Defined in:
lib/virtualbox/forwarded_port.rb

Overview

When a VM uses NAT as its NIC type, VirtualBox acts like its own private router for all virtual machines. Because of this, the host machine can't access services within the guest machine. To get around this, NAT supports port forwarding, which allows the guest machine services to be forwarded to some port on the host machine. Port forwarding is done completely through ExtraData, but is a complicated enough procedure that this class was made to faciliate it.

Note: After changing any forwarded ports, the entire VirtualBox process must be restarted completely for them to take effect. When working with the ruby library, this isn't so much of an issue, but if you have any VMs running, they must all be shut down and restarted.

Adding a new Forwarded Port

Since forwarded ports rely on being part of a VM, we're going to assume that vm points to a VM which has already been found.

port = VirtualBox::ForwardedPort.new
port.name = "apache" # This can be anything
port.guestport = 80
port.hostport = 8080
vm.forwarded_ports << port
port.save # Or vm.save

Modifying an Existing Forwarded Port

This is assuming that vm is a local variable storing a VM object which has already been found.

vm.forwarded_ports.first.hostport = 1919
vm.save

Deleting a Forwarded Port

To delete a forwarded port, you simply destroy it like any other model:

vm.forwarded_ports.first.destroy

Attributes and Relationships

Properties of the model are exposed using standard ruby instance methods which are generated on the fly. Because of this, they are not listed below as available instance methods.

These attributes can be accessed and modified via standard ruby-style instance.attribute and instance.attribute= methods. The attributes are listed below.

Relationships are also accessed like attributes but can't be set. Instead, they are typically references to other objects such as an AttachedDevice which in turn have their own attributes which can be modified.

Attributes

This is copied directly from the class header, but lists all available attributes. If you don't understand what this means, read Attributable.

attribute :parent, :readonly => true
attribute :name
attribute :instance, :default => "0"
attribute :device, :default => "pcnet"
attribute :protocol, :default => "TCP"
attribute :guestport
attribute :hostport

Class Method Summary

Instance Method Summary

Methods inherited from AbstractModel

#errors, #existing_record!, #inspect, #lazy_attribute?, #lazy_relationship?, #new_record!, #new_record?, #populate_attributes, #populate_relationship, #populate_relationships, reload!, #reload!, reload?, reloaded!, #save_attribute, #set_relationship, #write_attribute

Methods included from AbstractModel::Attributable

#attributes, #has_attribute?, included, #lazy_attribute?, #loaded_attribute?, #populate_attributes, #read_attribute, #readonly_attribute?, #write_attribute

Methods included from AbstractModel::Dirty

#changed?, #changes, #clear_dirty!, #ignore_dirty, #method_missing, #set_dirty!

Methods included from AbstractModel::Relatable

#destroy_relationship, #destroy_relationships, #has_relationship?, included, #lazy_relationship?, #loaded_relationship?, #populate_relationship, #populate_relationships, #read_relationship, #relationship_data, #save_relationship, #save_relationships, #set_relationship

Methods included from AbstractModel::Validatable

#add_error, #clear_errors, #errors, #valid?, #validates_presence_of

Constructor Details

- (ForwardedPort) initialize(data = {})

A new instance of ForwardedPort

Parameters:

  • (Hash) data (defaults to: {}) — The initial attributes to populate.


120
121
122
123
# File 'lib/virtualbox/forwarded_port.rb', line 120

def initialize(data={})
  super()
  populate_attributes(data)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class VirtualBox::AbstractModel::Dirty

Class Method Details

+ (Array<ForwardedPort>) populate_relationship(caller, data)

Populates a relationship with another model.

This method typically won't be used except internally.

Returns:



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/virtualbox/forwarded_port.rb', line 84

def populate_relationship(caller, data)
  relation = Proxies::Collection.new(caller)

  caller.extra_data.each do |key, value|
    next unless key =~ /^(VBoxInternal\/Devices\/(.+?)\/(.+?)\/LUN#0\/Config\/(.+?)\/)Protocol$/i

    port = new({
      :parent => caller,
      :name => $4.to_s,
      :instance => $3.to_s,
      :device => $2.to_s,
      :protocol => value,
      :guestport => caller.extra_data["#{$1.to_s}GuestPort"],
      :hostport => caller.extra_data["#{$1.to_s}HostPort"]
    })

    port.existing_record!

    relation.push(port)
  end

  relation
end

+ (Object) save_relationship(caller, data)

Saves the relationship. This simply calls #save on every member of the relationship.

This method typically won't be used except internally.



112
113
114
115
116
# File 'lib/virtualbox/forwarded_port.rb', line 112

def save_relationship(caller, data)
  data.each do |fp|
    fp.save
  end
end

Instance Method Details

- (Object) added_to_relationship(parent)

Relationship callback when added to a collection. This is automatically called by any relationship collection when this object is added.



182
183
184
# File 'lib/virtualbox/forwarded_port.rb', line 182

def added_to_relationship(parent)
  write_attribute(:parent, parent)
end

- (Boolean) destroy(raise_errors = false)

Destroys the port forwarding mapping.

Parameters:

Returns:

  • (Boolean) — True if command was successful, false otherwise.


166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/virtualbox/forwarded_port.rb', line 166

def destroy(raise_errors=false)
  results = []

  if !new_record?
    results << parent.extra_data.delete("#{key_prefix(true)}Protocol", raise_errors)
    results << parent.extra_data.delete("#{key_prefix(true)}GuestPort", raise_errors)
    results << parent.extra_data.delete("#{key_prefix(true)}HostPort", raise_errors)

    new_record!
  end

  results.empty? || results.all? { |o| o == true }
end

- (String) key_prefix(old_name = false)

Returns the prefix to be used for the extra data key. Forwarded ports are created by simply setting ExtraData on a VM. This class hides most of the inner workings of it, but it requires a common prefix. This method generates that.

Returns:

  • (String)


192
193
194
195
# File 'lib/virtualbox/forwarded_port.rb', line 192

def key_prefix(old_name=false)
  name_value = old_name && name_changed? ? name_was : name
  "VBoxInternal\/Devices\/#{device}\/#{instance}\/LUN#0\/Config\/#{name_value}\/"
end

- (Boolean) save(raise_errors = false)

Saves the forwarded port.

Parameters:

Returns:

  • (Boolean) — True if command was successful, false otherwise.


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/virtualbox/forwarded_port.rb', line 140

def save(raise_errors=false)
  return true if !new_record? && !changed?

  if !valid?
    raise Exceptions::ValidationFailedException.new(errors) if raise_errors
    return false
  end

  destroy(raise_errors) if name_changed?

  parent.extra_data["#{key_prefix}Protocol"] = protocol
  parent.extra_data["#{key_prefix}GuestPort"] = guestport
  parent.extra_data["#{key_prefix}HostPort"] = hostport
  result = parent.extra_data.save(raise_errors)

  clear_dirty!
  existing_record!

  result
end

- (Object) validate

Validates a forwarded port.



126
127
128
129
130
131
132
133
# File 'lib/virtualbox/forwarded_port.rb', line 126

def validate
  super

  validates_presence_of :parent
  validates_presence_of :name
  validates_presence_of :guestport
  validates_presence_of :hostport
end