From ac2610c85f443ef65e1bc262c4e6df9c300ecfd1 Mon Sep 17 00:00:00 2001 From: geemus Date: Wed, 9 Mar 2011 17:03:15 -0800 Subject: [PATCH] [virtualbox|compute] rough initial implementation --- Gemfile.lock | 5 + fog.gemspec | 1 + lib/fog/bin.rb | 3 +- lib/fog/bin/virtual_box.rb | 52 ++++ lib/fog/compute.rb | 9 +- lib/fog/compute/aws.rb | 6 - lib/fog/compute/models/virtual_box/medium.rb | 87 +++++++ .../models/virtual_box/medium_format.rb | 34 +++ lib/fog/compute/models/virtual_box/mediums.rb | 32 +++ .../compute/models/virtual_box/nat_engine.rb | 65 +++++ .../models/virtual_box/nat_redirect.rb | 91 +++++++ .../models/virtual_box/nat_redirects.rb | 41 +++ .../models/virtual_box/network_adapter.rb | 82 ++++++ .../models/virtual_box/network_adapters.rb | 42 +++ lib/fog/compute/models/virtual_box/server.rb | 241 ++++++++++++++++++ lib/fog/compute/models/virtual_box/servers.rb | 41 +++ .../models/virtual_box/storage_controller.rb | 83 ++++++ .../models/virtual_box/storage_controllers.rb | 38 +++ lib/fog/compute/virtual_box.rb | 48 ++++ lib/fog/core.rb | 1 + lib/fog/core/attributes.rb | 4 +- lib/fog/dns.rb | 6 +- lib/fog/providers.rb | 3 +- lib/fog/providers/virtual_box.rb | 11 + 24 files changed, 1011 insertions(+), 15 deletions(-) create mode 100644 lib/fog/bin/virtual_box.rb create mode 100644 lib/fog/compute/models/virtual_box/medium.rb create mode 100644 lib/fog/compute/models/virtual_box/medium_format.rb create mode 100644 lib/fog/compute/models/virtual_box/mediums.rb create mode 100644 lib/fog/compute/models/virtual_box/nat_engine.rb create mode 100644 lib/fog/compute/models/virtual_box/nat_redirect.rb create mode 100644 lib/fog/compute/models/virtual_box/nat_redirects.rb create mode 100644 lib/fog/compute/models/virtual_box/network_adapter.rb create mode 100644 lib/fog/compute/models/virtual_box/network_adapters.rb create mode 100644 lib/fog/compute/models/virtual_box/server.rb create mode 100644 lib/fog/compute/models/virtual_box/servers.rb create mode 100644 lib/fog/compute/models/virtual_box/storage_controller.rb create mode 100644 lib/fog/compute/models/virtual_box/storage_controllers.rb create mode 100644 lib/fog/compute/virtual_box.rb create mode 100644 lib/fog/providers/virtual_box.rb diff --git a/Gemfile.lock b/Gemfile.lock index 88f55d07c..cce6a4283 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,6 +16,8 @@ GEM specs: builder (3.0.0) excon (0.5.6) + ffi (0.6.3) + rake (>= 0.8.7) formatador (0.0.16) json (1.5.1) mime-types (1.16) @@ -26,6 +28,8 @@ GEM ruby-hmac (0.4.0) shindo (0.2.2) formatador (>= 0.0.16) + virtualbox (0.8.3) + ffi (~> 0.6.3) PLATFORMS ruby @@ -35,3 +39,4 @@ DEPENDENCIES rake rspec (= 1.3.1) shindo (= 0.2.2) + virtualbox (= 0.8.3) diff --git a/fog.gemspec b/fog.gemspec index 960fb32ed..7fede78f0 100644 --- a/fog.gemspec +++ b/fog.gemspec @@ -56,6 +56,7 @@ Gem::Specification.new do |s| s.add_development_dependency('rake') s.add_development_dependency('rspec', '1.3.1') s.add_development_dependency('shindo', '0.2.2') + s.add_development_dependency('virtualbox', '0.8.3') s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {spec,tests}/*`.split("\n") diff --git a/lib/fog/bin.rb b/lib/fog/bin.rb index 7bea038e3..fae657dd5 100644 --- a/lib/fog/bin.rb +++ b/lib/fog/bin.rb @@ -56,6 +56,7 @@ end require 'fog/bin/aws' require 'fog/bin/bluebox' require 'fog/bin/brightbox' +require 'fog/bin/dnsimple' require 'fog/bin/ecloud' require 'fog/bin/go_grid' require 'fog/bin/google' @@ -65,6 +66,6 @@ require 'fog/bin/new_servers' require 'fog/bin/rackspace' require 'fog/bin/slicehost' require 'fog/bin/terremark' +require 'fog/bin/virtual_box' require 'fog/bin/voxel' require 'fog/bin/zerigo' -require 'fog/bin/dnsimple' diff --git a/lib/fog/bin/virtual_box.rb b/lib/fog/bin/virtual_box.rb new file mode 100644 index 000000000..37247b92d --- /dev/null +++ b/lib/fog/bin/virtual_box.rb @@ -0,0 +1,52 @@ +module VirtualBox # deviates from other bin stuff to accomodate gem + class << self + + def class_for(key) + case key + when :compute + Fog::VirtualBox::Compute + else + raise ArgumentError, "Unrecognized service: #{key}" + end + end + + def [](service) + @@connections ||= Hash.new do |hash, key| + hash[key] = case key + when :compute + Fog::Compute.new(:provider => 'VirtualBox') + else + raise ArgumentError, "Unrecognized service: #{key.inspect}" + end + end + @@connections[service] + end + + def available? + availability = !Gem.source_index.find_name('virtualbox').empty? + if availability + for service in services + for collection in self.class_for(service).collections + unless self.respond_to?(collection) + self.class_eval <<-EOS, __FILE__, __LINE__ + def self.#{collection} + self[:#{service}].#{collection} + end + EOS + end + end + end + end + availability + end + + def collections + services.map {|service| self[service].collections}.flatten.sort_by {|service| service.to_s} + end + + def services + Fog::VirtualBox.services + end + + end +end diff --git a/lib/fog/compute.rb b/lib/fog/compute.rb index bc5ee3c56..150845036 100644 --- a/lib/fog/compute.rb +++ b/lib/fog/compute.rb @@ -28,12 +28,15 @@ module Fog when 'Rackspace' require 'fog/compute/rackspace' Fog::Rackspace::Compute.new(attributes) - when 'Voxel' - require 'fog/compute/voxel' - Fog::Voxel::Compute.new(attributes) when 'Slicehost' require 'fog/compute/slicehost' Fog::Slicehost::Compute.new(attributes) + when 'VirtualBox' + require 'fog/compute/virtual_box' + Fog::VirtualBox::Compute.new(attributes) + when 'Voxel' + require 'fog/compute/voxel' + Fog::Voxel::Compute.new(attributes) else raise ArgumentError.new("#{provider} is not a recognized compute provider") end diff --git a/lib/fog/compute/aws.rb b/lib/fog/compute/aws.rb index 7dd80ac67..5965d6513 100644 --- a/lib/fog/compute/aws.rb +++ b/lib/fog/compute/aws.rb @@ -122,12 +122,6 @@ module Fog end end - def self.reset_data(keys=data.keys) - for key in [*keys] - data.delete(key) - end - end - def initialize(options={}) unless options.delete(:provider) location = caller.first diff --git a/lib/fog/compute/models/virtual_box/medium.rb b/lib/fog/compute/models/virtual_box/medium.rb new file mode 100644 index 000000000..16518c077 --- /dev/null +++ b/lib/fog/compute/models/virtual_box/medium.rb @@ -0,0 +1,87 @@ +require 'fog/core/model' +require 'fog/compute/models/virtual_box/medium_format' + +module Fog + module VirtualBox + class Compute + + class Medium < Fog::Model + + identity :id + + attribute :auto_reset + attribute :base + attribute :children + attribute :description + attribute :device_type + attribute :format + attribute :host_drive + attribute :id + attribute :last_access_error + attribute :location + attribute :logical_size + attribute :machine_ids + attribute :medium_format + attribute :name + attribute :parent + attribute :read_only + attribute :size + attribute :state + attribute :type + attribute :variant + + def destroy + requires :raw + raw.close + true + end + + undef_method :medium_format + def medium_format + Fog::VirtualBox::Compute::MediumFormat.new( + :connection => connection, + :raw => raw.medium_format + ) + end + + def save + requires :device_type, :location, :read_only + + if File.exists?(location) + + access_mode = if read_only + :access_mode_read_only + else + :access_mode_read_write + end + + self.raw = connection.open_medium(location, device_type, access_mode) + + else + + raise Fog::Errors::Error.new('Creating a new medium is not yet implemented. Contributions welcome!') + + end + end + + private + + def raw + @raw + end + + def raw=(new_raw) + @raw = new_raw + raw_attributes = {} + for key in [:auto_reset, :base, :children, :description, :device_type, :format, :host_drive, :id, :last_access_error, :location, :logical_size, :machine_ids, :medium_format, :name, :parent, :read_only, :size, :state, :type, :variant] + raw_attributes[key] = @raw.send(key) + end + merge_attributes(raw_attributes) + end + + end + + end + end + +end diff --git a/lib/fog/compute/models/virtual_box/medium_format.rb b/lib/fog/compute/models/virtual_box/medium_format.rb new file mode 100644 index 000000000..358b14d82 --- /dev/null +++ b/lib/fog/compute/models/virtual_box/medium_format.rb @@ -0,0 +1,34 @@ +require 'fog/core/model' + +module Fog + module VirtualBox + class Compute + + class MediumFormat < Fog::Model + + identity :id + + # attribute :capabilities + attribute :name + + private + + def raw + @raw + end + + def raw=(new_raw) + @raw = new_raw + raw_attributes = {} + for key in [:id, :name] + raw_attributes[key] = @raw.send(key) + end + merge_attributes(raw_attributes) + end + + end + + end + end + +end diff --git a/lib/fog/compute/models/virtual_box/mediums.rb b/lib/fog/compute/models/virtual_box/mediums.rb new file mode 100644 index 000000000..fd8671e0f --- /dev/null +++ b/lib/fog/compute/models/virtual_box/mediums.rb @@ -0,0 +1,32 @@ +require 'fog/core/collection' +require 'fog/compute/models/virtual_box/medium' + +module Fog + module VirtualBox + class Compute + + class Mediums < Fog::Collection + + model Fog::VirtualBox::Compute::Medium + + def all + data = [] + data.concat(connection.dvd_images) + data.concat(connection.floppy_images) + data.concat(connection.hard_disks) + data = data.map do |medium| + {:raw => medium} + end + load(data) + end + + def get(medium_identity) + data = connection.find_medium(medium_identity) + new(:raw => data) + end + + end + + end + end +end diff --git a/lib/fog/compute/models/virtual_box/nat_engine.rb b/lib/fog/compute/models/virtual_box/nat_engine.rb new file mode 100644 index 000000000..a2ad067fa --- /dev/null +++ b/lib/fog/compute/models/virtual_box/nat_engine.rb @@ -0,0 +1,65 @@ +require 'fog/core/model' + +module Fog + module VirtualBox + class Compute + + class NATEngine < Fog::Model + + # identity :? + + attribute :alias_mode + attribute :dns_pass_domain + attribute :dns_proxy + attribute :dns_use_host_resolver + attribute :host_ip + attribute :network + attribute :redirects + attribute :tftp_boot_file + attribute :tftp_next_server + attribute :tftp_prefix + + attr_accessor :machine, :network_adapter + + # def save + # unless identity + # requires :identity, :bus, :machine + # with_session do |session| + # self.raw = session.machine.add_storage_controller(identity, bus) + # end + # true + # else + # raise Fog::Errors::Error.new('Updating an existing storage_controller is not yet implemented. Contributions welcome!') + # end + # end + + undef_method :redirects + def redirects + Fog::VirtualBox::Compute::NATRedirects.new( + :connection => connection, + :machine => machine, + :nat_engine => self + ) + end + + private + + def raw + @raw + end + + def raw=(new_raw) + @raw = new_raw + raw_attributes = {} + for key in [:alias_mode, :dns_pass_domain, :dns_proxy, :dns_use_host_resolver, :host_ip, :network, :redirects, :tftp_boot_file, :tftp_next_server, :tftp_prefix] + raw_attributes[key] = @raw.send(key) + end + merge_attributes(raw_attributes) + end + + end + + end + end + +end diff --git a/lib/fog/compute/models/virtual_box/nat_redirect.rb b/lib/fog/compute/models/virtual_box/nat_redirect.rb new file mode 100644 index 000000000..8f8c3edb6 --- /dev/null +++ b/lib/fog/compute/models/virtual_box/nat_redirect.rb @@ -0,0 +1,91 @@ +require 'fog/core/model' + +module Fog + module VirtualBox + class Compute + + class NATRedirect < Fog::Model + + identity :name + + attribute :name + attribute :protocol + attribute :host_ip + attribute :host_port + attribute :guest_ip + attribute :guest_port + + attr_accessor :machine, :nat_engine + + def destroy + requires :nat_engine, :name + with_session do |session| + raw_network_adapter = session.machine.get_network_adapter(nat_engine.network_adapter.slot) + raw_nat_engine = raw_network_adapter.nat_driver + raw_nat_engine.remove_redirect(name) + session.machine.save_settings + end + true + end + + def initialize(attributes = {}) + self.name = '' + self.protocol = :tcp + self.host_ip = '' + self.guest_ip = '' + super + end + + undef_method :protocol= + def protocol=(new_protocol) + attributes[:protocol] = case new_protocol + when '0' + :udp + when '1' + :tcp + else + new_protocol + end + end + + def save + requires :nat_engine, :name, :protocol, :host_ip, :host_port, :guest_ip, :guest_port + with_session do |session| + raw_network_adapter = session.machine.get_network_adapter(nat_engine.network_adapter.slot) + raw_nat_engine = raw_network_adapter.nat_driver + raw_nat_engine.add_redirect(name, protocol, host_ip, host_port, guest_ip, guest_port) + session.machine.save_settings + end + true + end + + private + + def raw + @raw + end + + def raw=(new_raw) + @raw = new_raw + name, protocol, host_ip, host_port, guest_ip, guest_port = new_raw.split(',') + raw_attributes = {:name => name, :protocol => protocol, :host_ip => host_ip, :host_port => host_port, :guest_ip => guest_ip, :guest_port => guest_port} + merge_attributes(raw_attributes) + end + + def session + ::VirtualBox::Lib.lib.session + end + + def with_session + raw_machine = machine.instance_variable_get(:@raw) + raw_machine.lock_machine(session, :write) + yield session + session.unlock_machine + end + + end + + end + end + +end diff --git a/lib/fog/compute/models/virtual_box/nat_redirects.rb b/lib/fog/compute/models/virtual_box/nat_redirects.rb new file mode 100644 index 000000000..adb645998 --- /dev/null +++ b/lib/fog/compute/models/virtual_box/nat_redirects.rb @@ -0,0 +1,41 @@ +require 'fog/core/collection' +require 'fog/compute/models/virtual_box/nat_redirect' + +module Fog + module VirtualBox + class Compute + + class NATRedirects < Fog::Collection + + model Fog::VirtualBox::Compute::NATRedirect + + attr_accessor :machine, :nat_engine + + def all + requires :machine, :nat_engine + data = nat_engine.instance_variable_get(:@raw).redirects.map do |nat_redirect| + { + :machine => machine, + :raw => nat_redirect + } + end + load(data) + end + + def get(nat_redirect_name) + requires :machine, :nat_engine + all.detect do |nat_redirect| + nat_redirect.name == nat_redirect_name + end + end + + def new(attributes = {}) + requires :machine, :nat_engine + super({:machine => machine, :nat_engine => nat_engine}.merge!(attributes)) + end + + end + + end + end +end diff --git a/lib/fog/compute/models/virtual_box/network_adapter.rb b/lib/fog/compute/models/virtual_box/network_adapter.rb new file mode 100644 index 000000000..a98a20dd6 --- /dev/null +++ b/lib/fog/compute/models/virtual_box/network_adapter.rb @@ -0,0 +1,82 @@ +require 'fog/core/model' +require 'fog/compute/models/virtual_box/nat_engine' + +module Fog + module VirtualBox + class Compute + + class NetworkAdapter < Fog::Model + + identity :slot + + attribute :adapter_type + attribute :attachment_type + attribute :bandwidth_limit + attribute :boot_priority + attribute :cable_connected + attribute :enabled + attribute :host_interface + attribute :internal_network + attribute :line_speed + attribute :mac_address + attribute :nat_driver + attribute :nat_network + attribute :trace_enabled + attribute :trace_file + attribute :vde_network + + attr_accessor :machine + + def save + with_session do |session| + session_raw = session.machine.get_network_adapter(slot) + # for attribute in [:adapter_type, :bandwidth_limit, :boot_priority, :cable_connected, :enabled, :host_interface, :internal_network, :line_speed, :mac_address, :nat_network, :trace_enabled, :trace_file] + # session_raw.send("#{attribute}=", attributes[attribute]) + # end + session_raw.mac_address = mac_address + session.machine.save_settings + end + end + + undef_method :nat_driver + def nat_driver + Fog::VirtualBox::Compute::NATEngine.new( + :connection => connection, + :machine => machine, + :network_adapter => self, + :raw => raw.nat_driver + ) + end + + private + + def raw + @raw + end + + def raw=(new_raw) + @raw = new_raw + raw_attributes = {} + for key in [:adapter_type, :attachment_type, :bandwidth_limit, :boot_priority, :cable_connected, :enabled, :host_interface, :internal_network, :line_speed, :mac_address, :nat_driver, :nat_network, :slot, :trace_enabled, :trace_file] + raw_attributes[key] = @raw.send(key) + end + merge_attributes(raw_attributes) + end + + def session + ::VirtualBox::Lib.lib.session + end + + def with_session + raw_machine = machine.instance_variable_get(:@raw) + raw_machine.lock_machine(session, :write) + yield session + session.unlock_machine + end + + end + + end + end + +end diff --git a/lib/fog/compute/models/virtual_box/network_adapters.rb b/lib/fog/compute/models/virtual_box/network_adapters.rb new file mode 100644 index 000000000..f16da7872 --- /dev/null +++ b/lib/fog/compute/models/virtual_box/network_adapters.rb @@ -0,0 +1,42 @@ +require 'fog/core/collection' +require 'fog/compute/models/virtual_box/network_adapter' + +module Fog + module VirtualBox + class Compute + + class NetworkAdapters < Fog::Collection + + model Fog::VirtualBox::Compute::NetworkAdapter + + attr_accessor :machine + + def all + requires :machine + data = [] + raw_machine = machine.instance_variable_get(:@raw) + connection.system_properties.network_adapter_count.times do |index| + data << { + :raw => raw_machine.get_network_adapter(index) + } + end + load(data) + end + + def get(network_adapter_slot) + requires :machine + raw_machine = machine.instance_variable_get(:@raw) + network_adapter = raw_machine.get_network_adapter(network_adapter_slot) + new(:raw => network_adapter) + end + + def new(attributes = {}) + requires :machine + super({ :machine => machine }.merge!(attributes)) + end + + end + + end + end +end diff --git a/lib/fog/compute/models/virtual_box/server.rb b/lib/fog/compute/models/virtual_box/server.rb new file mode 100644 index 000000000..65ca9d5be --- /dev/null +++ b/lib/fog/compute/models/virtual_box/server.rb @@ -0,0 +1,241 @@ +require 'fog/core/model' + +module Fog + module VirtualBox + class Compute + + class Server < Fog::Model + + identity :id + + attribute :description + attribute :memory_size + attribute :name + attribute :os, :aliases => :os_type_id + attribute :rtc_use_utc + attribute :session_state + attribute :status, :aliases => :state + attribute :vram_size + + # property :accelerate_2d_video_enabled, T_BOOL + # property :accelerate_3d_enabled, T_BOOL + # property :access_error, :VirtualBoxErrorInfo, :readonly => true + # property :accessible, T_BOOL, :readonly => true + # property :audio_adapter, :AudioAdapter, :readonly => true + # property :bandwidth_control, :BandwidthControl, :readonly => true + # property :bios_settings, :BIOSSettings, :readonly => true + # property :chipset_type, :ChipsetType + # property :clipboard_mode, :ClipboardMode + # property :cpu_count, T_UINT32 + # property :cpu_execution_cap, T_UINT64 + # property :cpu_hot_plug_enabled, T_BOOL + # property :current_snapshot, :Snapshot, :readonly => true + # property :current_state_modified, T_BOOL, :readonly => true + # property :fault_tolerance_address, WSTRING + # property :fault_tolerance_password, WSTRING + # property :fault_tolerance_port, T_UINT64 + # property :fault_tolerance_state, :FaultToleranceState + # property :fault_tolerance_sync_interval, T_UINT64 + # property :firmware_type, :FirmwareType + # property :guest_property_notification_patterns, WSTRING + # property :hardware_uuid, WSTRING + # property :hardware_version, WSTRING + # property :hpet_enabled, T_BOOL + # property :io_cache_enabled, T_BOOL + # property :io_cache_size, T_UINT32 + # property :keyboard_hid_type, T_UINT32 + # property :last_state_change, T_INT64, :readonly => true + # property :log_folder, WSTRING, :readonly => true + # property :medium_attachments, [:MediumAttachment], :readonly => true + # property :memory_balloon_size, T_UINT64 + # property :monitor_count, T_UINT64 + # property :page_fusion_enabled, T_BOOL + # property :parent, :VirtualBox, :readonly => true + # property :pci_device_assignments, [:PciDeviceAttachment], :readonly => true + # property :pointing_hid_type, T_UINT32 + # property :session_pid, T_UINT64, :readonly => true + # property :session_type, WSTRING, :readonly => true + # property :settings_file_path, WSTRING, :readonly => true + # property :settings_modified, T_BOOL, :readonly => true + # property :shared_folders, [:SharedFolder], :readonly => true + # property :snapshot_count, T_UINT32, :readonly => true + # property :snapshot_folder, WSTRING + # property :state_file_path, WSTRING, :readonly => true + # property :storage_controllers, [:StorageController], :readonly => true + # property :teleporter_address, WSTRING + # property :teleporter_enabled, T_BOOL + # property :teleporter_password, WSTRING + # property :teleporter_port, T_UINT32 + # property :usb_controller, :USBController, :readonly => true + # property :vrde_server, :VRDEServer, :readonly => true + + attr_writer :private_key, :private_key_path, :public_key, :public_key_path, :username + + def initialize(attributes={}) + self.memory_size = 256 + self.rtc_use_utc = true + self.vram_size = 8 + super + end + + def destroy + requires :name, :raw + unless raw.state == :powered_off + stop + wait_for { raw.session_state == :closed } + end + raw.unregister(:full) + config_file = connection.compose_machine_filename(name) + config_directory = config_file.split(File::SEPARATOR)[0...-1].join(File::SEPARATOR) + FileUtils.rm_rf(config_directory) + true + end + + def network_adapters + Fog::VirtualBox::Compute::NetworkAdapters.new( + :connection => connection, + :machine => self + ) + end + + def private_ip_address + nil + end + + def private_key_path + @private_key_path ||= Fog.credentials[:private_key_path] + @private_key_path &&= File.expand_path(@private_key_path) + end + + def private_key + @private_key ||= private_key_path && File.read(private_key_path) + end + + def public_ip_address + nil + end + + def public_key_path + @public_key_path ||= Fog.credentials[:public_key_path] + @public_key_path &&= File.expand_path(@public_key_path) + end + + def public_key + @public_key ||= public_key_path && File.read(public_key_path) + end + + def ready? + status == :running + end + + def reboot + requires :raw + session.console.reset + true + end + + def save + unless identity + requires :name, :os + self.raw = connection.create_machine(nil, name, os) + connection.register_machine(raw) + with_session do |session| + for attribute in [:description, :memory_size, :rtc_use_utc, :vram_size] + session.machine.send(:"#{attribute}=", attributes[attribute]) + end + session.machine.save_settings + end + true + else + raise Fog::Errors::Error.new('Updating an existing server is not yet implemented. Contributions welcome!') + end + end + + def scp(local_path, remote_path) + raise 'Not Implemented' + # requires :addresses, :username + # + # options = {} + # options[:key_data] = [private_key] if private_key + # Fog::SCP.new(addresses['public'].first, username, options).upload(local_path, remote_path) + end + + def setup(credentials = {}) + raise 'Not Implemented' + # requires :addresses, :identity, :public_key, :username + # Fog::SSH.new(addresses['public'].first, username, credentials).run([ + # %{mkdir .ssh}, + # %{echo "#{public_key}" >> ~/.ssh/authorized_keys}, + # %{passwd -l #{username}}, + # %{echo "#{attributes.to_json}" >> ~/attributes.json}, + # %{echo "#{metadata.to_json}" >> ~/metadata.json} + # ]) + # rescue Errno::ECONNREFUSED + # sleep(1) + # retry + end + + def ssh(commands) + raise 'Not Implemented' + # requires :addresses, :identity, :username + # + # options = {} + # options[:key_data] = [private_key] if private_key + # Fog::SSH.new(addresses['public'].first, username, options).run(commands) + end + + def start(type = 'headless') + requires :raw + # session, type in ['gui', 'headless'], key[=value]\n env variables + raw.launch_vm_process(session, type, '').wait + true + end + + def stop + requires :raw + session.console.power_down.wait + true + end + + def storage_controllers + Fog::VirtualBox::Compute::StorageControllers.new( + :connection => connection, + :machine => self + ) + end + + def username + @username ||= 'root' + end + + private + + def raw + @raw + end + + def raw=(new_raw) + @raw = new_raw + raw_attributes = {} + for key in [:id, :description, :memory_size, :name, :os_type_id, :state] + raw_attributes[key] = @raw.send(key) + end + merge_attributes(raw_attributes) + end + + def session + ::VirtualBox::Lib.lib.session + end + + def with_session + raw.lock_machine(session, :write) + yield session + session.unlock_machine + end + + end + + end + end + +end diff --git a/lib/fog/compute/models/virtual_box/servers.rb b/lib/fog/compute/models/virtual_box/servers.rb new file mode 100644 index 000000000..3d81aece7 --- /dev/null +++ b/lib/fog/compute/models/virtual_box/servers.rb @@ -0,0 +1,41 @@ +require 'fog/core/collection' +require 'fog/compute/models/virtual_box/server' + +module Fog + module VirtualBox + class Compute + + class Servers < Fog::Collection + + model Fog::VirtualBox::Compute::Server + + def all + data = connection.machines.map do |machine| + { + :raw => machine + } + end + load(data) + end + + def bootstrap(new_attributes = {}) + raise 'Not Implemented' + # server = create(new_attributes) + # server.start + # server.wait_for { ready? } + # server.setup(:password => server.password) + # server + end + + def get(server_id) + machine = connection.find_machine(server_id) + new(:raw => machine) + rescue ::VirtualBox::Exceptions::ObjectNotFoundException + nil + end + + end + + end + end +end diff --git a/lib/fog/compute/models/virtual_box/storage_controller.rb b/lib/fog/compute/models/virtual_box/storage_controller.rb new file mode 100644 index 000000000..b8e1351e2 --- /dev/null +++ b/lib/fog/compute/models/virtual_box/storage_controller.rb @@ -0,0 +1,83 @@ +require 'fog/core/model' + +module Fog + module VirtualBox + class Compute + + class StorageController < Fog::Model + + identity :name + + attribute :bootable + attribute :bus + attribute :controller_type + attribute :instance + attribute :max_devices_per_port_count + attribute :max_port_count + attribute :min_port_count + attribute :port_count + attribute :use_host_io_cache + + attr_accessor :machine + + def attach(medium, port, device = 0) + requires :identity, :machine + with_session do |session| + session.machine.attach_device(identity, port, device, medium.device_type, medium.instance_variable_get(:@raw)) + session.machine.save_settings + end + true + end + + def destroy + requires :identity, :machine + with_session do |session| + session.machine.remove_storage_controller(identity) + session.machine.save_settings + end + true + end + + def save + requires :bus, :identity, :machine + with_session do |session| + self.raw = session.machine.add_storage_controller(identity, bus) + raw.port_count = 1 + session.machine.save_settings + end + true + end + + private + + def raw + @raw + end + + def raw=(new_raw) + @raw = new_raw + raw_attributes = {} + # TODO: pending my patches being accepted :bootable, + for key in [:bus, :controller_type, :instance, :max_devices_per_port_count, :max_port_count, :min_port_count, :port_count, :use_host_io_cache] + raw_attributes[key] = @raw.send(key) + end + merge_attributes(raw_attributes) + end + + def session + ::VirtualBox::Lib.lib.session + end + + def with_session + raw_machine = machine.instance_variable_get(:@raw) + raw_machine.lock_machine(session, :write) + yield session + session.unlock_machine + end + + end + + end + end + +end diff --git a/lib/fog/compute/models/virtual_box/storage_controllers.rb b/lib/fog/compute/models/virtual_box/storage_controllers.rb new file mode 100644 index 000000000..ce30cde9e --- /dev/null +++ b/lib/fog/compute/models/virtual_box/storage_controllers.rb @@ -0,0 +1,38 @@ +require 'fog/core/collection' +require 'fog/compute/models/virtual_box/storage_controller' + +module Fog + module VirtualBox + class Compute + + class StorageControllers < Fog::Collection + + model Fog::VirtualBox::Compute::StorageController + + attr_accessor :machine + + def all + requires :machine + data = machine.instance_variable_get(:@raw).storage_controllers.map do |storage_controller| + {:raw => storage_controller} + end + load(data) + end + + def get(storage_controller_name) + requires :machine + all.detect do |storage_controller| + storage_controller.name == storage_controller_name + end + end + + def new(attributes = {}) + requires :machine + super({ :machine => machine }.merge!(attributes)) + end + + end + + end + end +end diff --git a/lib/fog/compute/virtual_box.rb b/lib/fog/compute/virtual_box.rb new file mode 100644 index 000000000..90f6cd553 --- /dev/null +++ b/lib/fog/compute/virtual_box.rb @@ -0,0 +1,48 @@ +module Fog + module VirtualBox + class Compute < Fog::Service + + recognizes :provider # remove post deprecation + + model_path 'fog/compute/models/virtual_box' + model :medium + collection :mediums + model :medium_format + model :nat_engine + model :nat_redirect + collection :nat_redirects + model :network_adapter + collection :network_adapters + model :server + collection :servers + model :storage_controller + collection :storage_controllers + + class Mock + + def initialize(options={}) + Fog::Mock.not_implemented + end + + end + + class Real + + def initialize(options={}) + require 'virtualbox' + @connection = ::VirtualBox::Global.global.lib.virtualbox + end + + # hack to provide 'requests' + def method_missing(method_sym, *arguments, &block) + if @connection.respond_to?(method_sym) + @connection.send(method_sym, *arguments) + else + super + end + end + + end + end + end +end diff --git a/lib/fog/core.rb b/lib/fog/core.rb index 0d7561b36..6fed5576b 100644 --- a/lib/fog/core.rb +++ b/lib/fog/core.rb @@ -9,6 +9,7 @@ require 'rubygems' require 'base64' require 'cgi' require 'excon' +require 'fileutils' require 'formatador' require 'time' require 'timeout' diff --git a/lib/fog/core/attributes.rb b/lib/fog/core/attributes.rb index 22f707620..0457fbb20 100644 --- a/lib/fog/core/attributes.rb +++ b/lib/fog/core/attributes.rb @@ -152,7 +152,9 @@ module Fog def requires(*args) missing = [] for arg in [:connection] | args - missing << arg unless send("#{arg}") + unless send("#{arg}") || attributes.has_key?(arg) + missing << arg + end end unless missing.empty? if missing.length == 1 diff --git a/lib/fog/dns.rb b/lib/fog/dns.rb index 37d848a88..1842107c3 100644 --- a/lib/fog/dns.rb +++ b/lib/fog/dns.rb @@ -10,6 +10,9 @@ module Fog when 'Bluebox' require 'fog/dns/bluebox' Fog::Bluebox::DNS.new(attributes) + when 'DNSimple' + require 'fog/dns/dnsimple' + Fog::DNSimple::DNS.new(attributes) when 'Linode' require 'fog/dns/linode' Fog::Linode::DNS.new(attributes) @@ -19,9 +22,6 @@ module Fog when 'Zerigo' require 'fog/dns/zerigo' Fog::Zerigo::DNS.new(attributes) - when 'DNSimple' - require 'fog/dns/dnsimple' - Fog::DNSimple::DNS.new(attributes) else raise ArgumentError.new("#{provider} is not a recognized dns provider") end diff --git a/lib/fog/providers.rb b/lib/fog/providers.rb index 8d5648077..0edd230ba 100644 --- a/lib/fog/providers.rb +++ b/lib/fog/providers.rb @@ -9,6 +9,7 @@ end require 'fog/providers/aws' require 'fog/providers/bluebox' require 'fog/providers/brightbox' +require 'fog/providers/dnsimple' require 'fog/providers/ecloud' require 'fog/providers/go_grid' require 'fog/providers/google' @@ -17,6 +18,6 @@ require 'fog/providers/local' require 'fog/providers/new_servers' require 'fog/providers/rackspace' require 'fog/providers/slicehost' +require 'fog/providers/virtual_box' require 'fog/providers/voxel' require 'fog/providers/zerigo' -require 'fog/providers/dnsimple' diff --git a/lib/fog/providers/virtual_box.rb b/lib/fog/providers/virtual_box.rb new file mode 100644 index 000000000..75683b7f9 --- /dev/null +++ b/lib/fog/providers/virtual_box.rb @@ -0,0 +1,11 @@ +require 'fog/core' + +module Fog + module VirtualBox + + extend Fog::Provider + + service(:compute, 'compute/virtual_box') + + end +end