libvirt 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/.gitignore +10 -0
  2. data/.yardopts +3 -0
  3. data/CHANGELOG.md +3 -0
  4. data/Gemfile +12 -0
  5. data/Gemfile.lock +36 -0
  6. data/README.md +83 -0
  7. data/Rakefile +20 -0
  8. data/docs/user_guide.md +259 -0
  9. data/examples/README.md +10 -0
  10. data/examples/create_domain.rb +46 -0
  11. data/examples/print_domain_info.rb +46 -0
  12. data/examples/print_hypervisor_info.rb +40 -0
  13. data/lib/ffi/libvirt/domain_info.rb +12 -0
  14. data/lib/ffi/libvirt/error.rb +25 -0
  15. data/lib/ffi/libvirt/error_functions.rb +21 -0
  16. data/lib/ffi/libvirt/error_types.rb +125 -0
  17. data/lib/ffi/libvirt/functions.rb +363 -0
  18. data/lib/ffi/libvirt/node_info.rb +27 -0
  19. data/lib/ffi/libvirt/storage_pool_info.rb +11 -0
  20. data/lib/ffi/libvirt/storage_volume_info.rb +14 -0
  21. data/lib/ffi/libvirt/types.rb +61 -0
  22. data/lib/ffi/libvirt/util.rb +19 -0
  23. data/lib/ffi/libvirt/version.rb +46 -0
  24. data/lib/ffi/libvirt.rb +29 -0
  25. data/lib/libvirt/collection/abstract_collection.rb +49 -0
  26. data/lib/libvirt/collection/domain_collection.rb +98 -0
  27. data/lib/libvirt/collection/interface_collection.rb +16 -0
  28. data/lib/libvirt/collection/network_collection.rb +58 -0
  29. data/lib/libvirt/collection/node_device_collection.rb +29 -0
  30. data/lib/libvirt/collection/nwfilter_collection.rb +15 -0
  31. data/lib/libvirt/collection/storage_pool_collection.rb +58 -0
  32. data/lib/libvirt/collection/storage_volume_collection.rb +57 -0
  33. data/lib/libvirt/collection.rb +12 -0
  34. data/lib/libvirt/connection.rb +225 -0
  35. data/lib/libvirt/domain.rb +241 -0
  36. data/lib/libvirt/error.rb +91 -0
  37. data/lib/libvirt/exception.rb +19 -0
  38. data/lib/libvirt/network.rb +118 -0
  39. data/lib/libvirt/node.rb +118 -0
  40. data/lib/libvirt/node_device.rb +75 -0
  41. data/lib/libvirt/spec/device/disk.rb +58 -0
  42. data/lib/libvirt/spec/device/emulator.rb +23 -0
  43. data/lib/libvirt/spec/device.rb +8 -0
  44. data/lib/libvirt/spec/domain/os_booting.rb +69 -0
  45. data/lib/libvirt/spec/domain.rb +71 -0
  46. data/lib/libvirt/spec.rb +12 -0
  47. data/lib/libvirt/storage_pool.rb +164 -0
  48. data/lib/libvirt/storage_volume.rb +109 -0
  49. data/lib/libvirt/version.rb +3 -0
  50. data/lib/libvirt.rb +53 -0
  51. data/libvirt.gemspec +27 -0
  52. data/test/libvirt/collection/abstract_collection_test.rb +14 -0
  53. data/test/libvirt/collection/domain_collection_test.rb +122 -0
  54. data/test/libvirt/collection/interface_collection_test.rb +9 -0
  55. data/test/libvirt/collection/network_collection_test.rb +41 -0
  56. data/test/libvirt/collection/node_device_collection_test.rb +24 -0
  57. data/test/libvirt/collection/nwfilter_collection_test.rb +7 -0
  58. data/test/libvirt/collection/storage_pool_collection_test.rb +41 -0
  59. data/test/libvirt/collection/storage_volume_collection_test.rb +86 -0
  60. data/test/libvirt/connection_test.rb +133 -0
  61. data/test/libvirt/domain_test.rb +221 -0
  62. data/test/libvirt/error_test.rb +93 -0
  63. data/test/libvirt/libvirt_test.rb +16 -0
  64. data/test/libvirt/network_test.rb +76 -0
  65. data/test/libvirt/node_device_test.rb +16 -0
  66. data/test/libvirt/node_test.rb +24 -0
  67. data/test/libvirt/spec/devices/disk_test.rb +107 -0
  68. data/test/libvirt/spec/devices/emulator_test.rb +20 -0
  69. data/test/libvirt/spec/domain_test.rb +17 -0
  70. data/test/libvirt/storage_pool_test.rb +133 -0
  71. data/test/libvirt/storage_volume_test.rb +63 -0
  72. data/test/support/xml_assertions.rb +29 -0
  73. data/test/test_helper.rb +23 -0
  74. metadata +219 -0
@@ -0,0 +1,58 @@
1
+ module Libvirt
2
+ module Spec
3
+ module Device
4
+ # Any device that looks like a disk, be it a floppy, harddisk,
5
+ # cdrom, or paravirtualized driver is specified via the disk
6
+ # element.
7
+ class Disk
8
+ attr_accessor :type
9
+ attr_accessor :source
10
+ attr_accessor :target_dev
11
+ attr_accessor :target_bus
12
+ attr_accessor :driver
13
+ attr_accessor :driver_type
14
+ attr_accessor :driver_cache
15
+ attr_accessor :shareable
16
+ attr_accessor :serial
17
+
18
+ # Initialize a new disk element with the given type. Examples
19
+ # of valid `type`s are "disk," "floppy," and "cdrom."
20
+ def initialize(type)
21
+ @type = type
22
+ @shareable = false
23
+ end
24
+
25
+ # Returns the XML representation of this device.
26
+ def to_xml(xml=Nokogiri::XML::Builder.new)
27
+ xml.disk(:type => type) do |d|
28
+ if source
29
+ # Source tag, the attribute depends on the type.
30
+ attribute = type == :block ? :dev : :file
31
+ d.source(attribute => source)
32
+ end
33
+
34
+ if target_dev
35
+ # Target tag has optional "bus" parameter
36
+ options = { :dev => target_dev }
37
+ options[:bus] = target_bus if target_bus
38
+ d.target(options)
39
+ end
40
+
41
+ if driver
42
+ # Driver tag has a couple optional parameters
43
+ options = { :name => driver }
44
+ options[:type] = driver_type if driver_type
45
+ options[:cache] = driver_cache if driver_cache
46
+ d.driver(options)
47
+ end
48
+
49
+ d.shareable if shareable
50
+ d.serial serial if serial
51
+ end
52
+
53
+ xml.to_xml
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,23 @@
1
+ module Libvirt
2
+ module Spec
3
+ module Device
4
+ class Emulator
5
+ attr_accessor :path
6
+
7
+ # Initialize an emulator device with the given path. The capabilities
8
+ # XML from {Connection} describes what emulators are available.
9
+ def initialize(path)
10
+ @path = path
11
+ end
12
+
13
+ # Returns the XML for this device.
14
+ #
15
+ # @return [String]
16
+ def to_xml(xml=Nokogiri::XML::Builder.new)
17
+ xml.emulator path
18
+ xml.to_xml
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ module Libvirt
2
+ module Spec
3
+ module Device
4
+ autoload :Disk, 'libvirt/spec/device/disk'
5
+ autoload :Emulator, 'libvirt/spec/device/emulator'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,69 @@
1
+ module Libvirt
2
+ module Spec
3
+ class Domain
4
+ # The OS booting section of a domain specification indicates to libvirt
5
+ # how to configure the virtual machine to boot. There are three main ways
6
+ # to configure booting. Each hypervisor supports one or more of the following:
7
+ #
8
+ # 1. BIOS bootloader
9
+ # 2. Host bootloader
10
+ # 3. Direct kernel boot
11
+ #
12
+ # TODO: Host bootloader and direct kernel bootloader options.
13
+ class OSBooting
14
+ attr_accessor :type
15
+ attr_accessor :arch
16
+ attr_accessor :loader # Part of the BIOS bootloader
17
+ attr_accessor :boot
18
+ attr_accessor :bootmenu_enabled
19
+
20
+ # Host bootloader configuration options
21
+ attr_accessor :bootloader
22
+ attr_accessor :bootloader_args
23
+
24
+ # Direct kernel boot
25
+ attr_accessor :kernel
26
+ attr_accessor :initrd
27
+ attr_accessor :cmdline
28
+
29
+ def initialize
30
+ @boot = []
31
+ end
32
+
33
+ # Enables or disables the interactive boot menu prompt on guest startup.
34
+ def bootmenu_enabled=(value)
35
+ # Force a boolean value
36
+ @bootmenu_enabled = !!value
37
+ end
38
+
39
+ # Convert just the OS booting section to its XML representation.
40
+ def to_xml(parent=Nokogiri::XML::Builder.new)
41
+ parent.os do |os|
42
+ # Build the arguments for the OS booting type
43
+ type_args = [type]
44
+ type_args << { :arch => arch } if arch
45
+
46
+ # Setup the specification
47
+ os.type_ *type_args
48
+ os.loader loader if loader
49
+ os.bootmenu(:enable => bootmenu_enabled ? 'yes' : 'no') if !bootmenu_enabled.nil?
50
+
51
+ # Boot order for BIOS booting
52
+ boot.each { |dev| os.boot :dev => dev } if boot.is_a?(Array)
53
+
54
+ # Host bootloader configuration options
55
+ os.bootloader bootloader if bootloader
56
+ os.bootloader_args bootloader_args if bootloader_args
57
+
58
+ # Direct kernel boot options
59
+ os.kernel kernel if kernel
60
+ os.initrd initrd if initrd
61
+ os.cmdline cmdline if cmdline
62
+ end
63
+
64
+ parent.to_xml
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,71 @@
1
+ require 'libvirt/spec/domain/os_booting'
2
+
3
+ module Libvirt
4
+ module Spec
5
+ # A specification of a domain. This translates directly down to XML
6
+ # which can be used to define and launch domains on a node by libvirt.
7
+ #
8
+ # **Note:** This class may only be temporary, and the functionality
9
+ # may be merged back into {Domain}. Also, the interface will likely
10
+ # change.
11
+ class Domain
12
+ attr_accessor :hypervisor
13
+ attr_accessor :name
14
+ attr_accessor :uuid
15
+ attr_accessor :description
16
+ attr_accessor :os
17
+ attr_accessor :memory
18
+ attr_accessor :current_memory
19
+ attr_accessor :vcpu
20
+
21
+ attr_accessor :on_poweroff
22
+ attr_accessor :on_reboot
23
+ attr_accessor :on_crash
24
+
25
+ attr_accessor :devices
26
+
27
+ def initialize
28
+ @os = OSBooting.new
29
+ @devices = []
30
+ end
31
+
32
+ # Returns the XML for this specification. This XML may be passed
33
+ # into libvirt to create a domain. This is actually the method which
34
+ # should be used for validation of this XML, since libvirt has
35
+ # great validation built in. If you define a domain and an error occurs,
36
+ # then it will notify you what is missing or wrong with the specification.
37
+ #
38
+ # @return [String]
39
+ def to_xml
40
+ Nokogiri::XML::Builder.new do |xml|
41
+ xml.domain(:type => hypervisor) do
42
+ # Name and description
43
+ xml.name name if name
44
+ xml.uuid uuid if uuid
45
+ xml.description description if description
46
+
47
+ # Operating system boot information
48
+ os.to_xml(xml)
49
+
50
+ # Basic resources
51
+ xml.memory memory if memory
52
+ xml.currentMemory current_memory if current_memory
53
+ xml.vcpu vcpu if vcpu
54
+
55
+ # Lifecycle control
56
+ xml.on_poweroff on_poweroff if on_poweroff
57
+ xml.on_reboot on_reboot if on_reboot
58
+ xml.on_crash on_crash if on_crash
59
+
60
+ # Devices
61
+ if !devices.empty?
62
+ xml.devices do
63
+ devices.map { |d| d.to_xml(xml) }
64
+ end
65
+ end
66
+ end
67
+ end.to_xml
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,12 @@
1
+ module Libvirt
2
+ # This is the namespace which contains all the classes which define
3
+ # specifications for domains, networks, storage pools, etc. These
4
+ # specifications are used to define and launch them via libvirt.
5
+ # The specifications are converted down to XML for consumption by
6
+ # libvirt. Please view the example files for examples on how to use
7
+ # the specs.
8
+ module Spec
9
+ autoload :Device, 'libvirt/spec/device'
10
+ autoload :Domain, 'libvirt/spec/domain'
11
+ end
12
+ end
@@ -0,0 +1,164 @@
1
+ module Libvirt
2
+ # Represents a single storage pool.
3
+ class StoragePool
4
+ # Initializes a new {StoragePool} object given a `virStoragePoolPtr`.
5
+ # Do not call this directly. Instead, use the {Connection#storage_pools}
6
+ # object to retrieve a specific {StoragePool}.
7
+ def initialize(pointer)
8
+ @pointer = pointer
9
+ ObjectSpace.define_finalizer(self, method(:finalize))
10
+ end
11
+
12
+ # Returns the connection of this storage pool.
13
+ #
14
+ # @return [Connection]
15
+ def connection
16
+ Connection.new(FFI::Libvirt.virStoragePoolGetConnect(self))
17
+ end
18
+
19
+ # Returns the name of the network as a string.
20
+ #
21
+ # @return [String]
22
+ def name
23
+ FFI::Libvirt.virStoragePoolGetName(self)
24
+ end
25
+
26
+ # Returns the UUID of the storage pool as a string.
27
+ #
28
+ # @return [String]
29
+ def uuid
30
+ output_ptr = FFI::MemoryPointer.new(:char, 36)
31
+ FFI::Libvirt.virStoragePoolGetUUIDString(self, output_ptr)
32
+ output_ptr.read_string
33
+ end
34
+
35
+ # Returns the XML description of this storage pool.
36
+ #
37
+ # @return [String]
38
+ def xml
39
+ FFI::Libvirt.virStoragePoolGetXMLDesc(self, 0)
40
+ end
41
+
42
+ # Deterine if the storage pool is active or not.
43
+ #
44
+ # @return [Boolean]
45
+ def active?
46
+ FFI::Libvirt.virStoragePoolIsActive(self) == 1
47
+ end
48
+
49
+ # Determine if the storage pool is persistent or not.
50
+ #
51
+ # @return [Boolean]
52
+ def persistent?
53
+ FFI::Libvirt.virStoragePoolIsPersistent(self) == 1
54
+ end
55
+
56
+ # Build the underlying storage pool.
57
+ #
58
+ # @return [Boolean]
59
+ def build
60
+ FFI::Libvirt.virStoragePoolBuild(self, 0) == 0
61
+ end
62
+
63
+ # Starts an inactive storage pool.
64
+ #
65
+ # @return [Boolean]
66
+ def create
67
+ return true if active?
68
+ FFI::Libvirt.virStoragePoolCreate(self, 0) == 0
69
+ end
70
+ alias :start :create
71
+
72
+ # Delete the underlying pool resources. This is a non-recoverable
73
+ # operation. This won't undefine the pool.
74
+ #
75
+ # @return [Boolean]
76
+ def delete(type=nil)
77
+ type ||= :normal
78
+ FFI::Libvirt.virStoragePoolDelete(self, type) == 0
79
+ end
80
+
81
+ # Stops an active storage pool.
82
+ #
83
+ # @return [Boolean]
84
+ def destroy
85
+ FFI::Libvirt.virStoragePoolDestroy(self) == 0
86
+ end
87
+ alias :stop :destroy
88
+
89
+ # Undefines the storage pool. This requires that the storage pool be
90
+ # inactive. This won't delete the underlying resources of the storage pool,
91
+ # however. Run {#delete} for that.
92
+ #
93
+ # @return [Boolean]
94
+ def undefine
95
+ FFI::Libvirt.virStoragePoolUndefine(self) == 0
96
+ end
97
+
98
+ # Returns the state of the storage pool as a symbol.
99
+ #
100
+ # @return [Symbol]
101
+ def state
102
+ info[:state]
103
+ end
104
+
105
+ # Returns the capacity in bytes.
106
+ #
107
+ # @return [Fixnum]
108
+ def capacity
109
+ info[:capacity]
110
+ end
111
+
112
+ # Returns the current allocation in bytes.
113
+ #
114
+ # @return [Fixnum]
115
+ def allocation
116
+ info[:allocation]
117
+ end
118
+
119
+ # Returns the available free space in bytes.
120
+ #
121
+ # @return [Fixnum]
122
+ def available
123
+ info[:available]
124
+ end
125
+
126
+ # Returns the volumes associated with this storage pool.
127
+ #
128
+ # @return [Collection::StorageVolumeCollection]
129
+ def volumes
130
+ Collection::StorageVolumeCollection.new(self)
131
+ end
132
+
133
+ # Provide a meaningful equality check for two storage pools by comparing
134
+ # UUID.
135
+ #
136
+ # @return [Boolean]
137
+ def ==(other)
138
+ other.is_a?(StoragePool) && other.uuid == uuid
139
+ end
140
+
141
+ # Returns the actual `virStoragePoolPtr` underlying this structure.
142
+ #
143
+ # @return [FFI::Pointer]
144
+ def to_ptr
145
+ @pointer
146
+ end
147
+
148
+ protected
149
+
150
+ # Gets the virStoragePoolInfo structure for this storage pool.
151
+ #
152
+ # @return [Hash]
153
+ def info
154
+ result = FFI::Libvirt::StoragePoolInfo.new
155
+ FFI::Libvirt.virStoragePoolGetInfo(self, result.to_ptr)
156
+ result
157
+ end
158
+
159
+ # Frees the underlying memory associated with this object.
160
+ def finalize(*args)
161
+ FFI::Libvirt.virStoragePoolFree(self)
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,109 @@
1
+ module Libvirt
2
+ # Represents a single storage volume.
3
+ class StorageVolume
4
+ # Initializes a new {StorageVolume} object given a `virStorageVolPtr`.
5
+ # Do not call this directly. Instead, use the {StoragePool#volumes} collection
6
+ # object to retrieve a specific {StorageVolume}.
7
+ def initialize(pointer)
8
+ @pointer = pointer
9
+ ObjectSpace.define_finalizer(self, method(:finalize))
10
+ end
11
+
12
+ # Returns a key for this storage volume. The key is a unique identifier.
13
+ #
14
+ # @return [String]
15
+ def key
16
+ FFI::Libvirt.virStorageVolGetKey(self)
17
+ end
18
+ alias :uuid :key
19
+
20
+ # Returns the name of this storage volume.
21
+ #
22
+ # @return [String]
23
+ def name
24
+ FFI::Libvirt.virStorageVolGetName(self)
25
+ end
26
+
27
+ # Returns the path of this storage volume.
28
+ #
29
+ # @return [String]
30
+ def path
31
+ FFI::Libvirt.virStorageVolGetPath(self)
32
+ end
33
+
34
+ # Returns the type of this storage volume.
35
+ #
36
+ # @return [Symbol]
37
+ def type
38
+ info[:type]
39
+ end
40
+
41
+ # Returns the capacity of this volume in bytes.
42
+ #
43
+ # @return [Integer]
44
+ def capacity
45
+ info[:capacity]
46
+ end
47
+
48
+ # Returns the currently allocated number of bytes.
49
+ #
50
+ # @return [Integer]
51
+ def allocation
52
+ info[:allocation]
53
+ end
54
+
55
+ # Wipe the contents of a volume so it is not readable in the future.
56
+ #
57
+ # @return [Boolean]
58
+ def wipe
59
+ FFI::Libvirt.virStorageVolWipe(self, 0) == 0
60
+ end
61
+
62
+ # Delete the storage volume rom the pool.
63
+ #
64
+ # @return [Boolean]
65
+ def delete
66
+ FFI::Libvirt.virStorageVolDelete(self, 0) == 0
67
+ end
68
+
69
+ # Returns the XML description of this storage volume.
70
+ #
71
+ # @return [String]
72
+ def xml
73
+ FFI::Libvirt.virStorageVolGetXMLDesc(self, 0)
74
+ end
75
+
76
+ # Returns the actual `virStorageVolPtr` underlying this structure.
77
+ #
78
+ # @return [FFI::Pointer]
79
+ def to_ptr
80
+ @pointer
81
+ end
82
+
83
+ # Provide a meaningful equality check so that two storage volumes
84
+ # can eaisly be checked for equality.
85
+ #
86
+ # @return [Boolean]
87
+ def ==(other)
88
+ other.is_a?(StorageVolume) && other.uuid == uuid
89
+ end
90
+
91
+ protected
92
+
93
+ # Returns the {FFI::Libvirt::StorageVolumeInfo} object for this volume.
94
+ # The various fields of the info struct are accessible via other getters.
95
+ #
96
+ # @return [FFI::Libvirt::StorageVolumeInfo]
97
+ def info
98
+ result = FFI::Libvirt::StorageVolumeInfo.new
99
+ FFI::Libvirt.virStorageVolGetInfo(self, result.to_ptr)
100
+ result
101
+ end
102
+
103
+ # Release the resources underlying this storage volume. This is called
104
+ # automatically when this volume is garbage collected.
105
+ def finalize(*args)
106
+ FFI::Libvirt.virStorageVolFree(self)
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,3 @@
1
+ module Libvirt
2
+ VERSION = "0.1.0"
3
+ end
data/lib/libvirt.rb ADDED
@@ -0,0 +1,53 @@
1
+ require 'nokogiri'
2
+ require 'ffi/libvirt'
3
+
4
+ # This module is the namespace for the higher level library on top of
5
+ # libvirt, in typicaly Ruby library style. In contrast with {FFI::Libvirt}
6
+ # which is a direct layer on top of FFI, this namespace abstracts much of
7
+ # the manual work away (especially pointer handling) and exposes aspects
8
+ # of the API through nice Ruby objects.
9
+ #
10
+ # Due to the nature of this side of the project, there may be certain features
11
+ # not readily available which are supported by the API. If this is the case,
12
+ # you can use the {FFI::Libvirt} library alongside this side.
13
+ module Libvirt
14
+ autoload :Collection, 'libvirt/collection'
15
+ autoload :Connection, 'libvirt/connection'
16
+ autoload :Domain, 'libvirt/domain'
17
+ autoload :Error, 'libvirt/error'
18
+ autoload :Exception, 'libvirt/exception'
19
+ autoload :Network, 'libvirt/network'
20
+ autoload :Node, 'libvirt/node'
21
+ autoload :NodeDevice, 'libvirt/node_device'
22
+ autoload :Spec, 'libvirt/spec'
23
+ autoload :StoragePool, 'libvirt/storage_pool'
24
+ autoload :StorageVolume, 'libvirt/storage_volume'
25
+
26
+ # Initializes the library by calling `virInitialize`. Most methods
27
+ # in libvirt actually call this themselves, so its not strictly
28
+ # necessary. However, it is good practice and is **highly** recommended
29
+ # that this is called at a same place in a multi-threaded environment.
30
+ def self.initialize!
31
+ FFI::Libvirt.virInitialize == 0
32
+ end
33
+
34
+ # Returns the version of `libvirt` on the client machine. **This is
35
+ # not the version of the `libvirt` ruby library.** The result is
36
+ # return as an array of `[major, minor, patch]`.
37
+ #
38
+ # @return [Array]
39
+ def self.version
40
+ FFI::Libvirt.version
41
+ end
42
+
43
+ # Connect to a hypervisor using libvirt. This is a shortcut to
44
+ # instantiating a {Connection} object, therefore for documentation on
45
+ # the arguments and return value for this method, please consult
46
+ # {Connection#initialize}.
47
+ def self.connect(*args)
48
+ Connection.new(*args)
49
+ end
50
+ end
51
+
52
+ # Disable the stderr output which libvirt defaults to.
53
+ Libvirt::Error.on_error
data/libvirt.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "libvirt/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "libvirt"
7
+ s.version = Libvirt::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Mitchell Hashimoto"]
10
+ s.email = ["mitchell.hashimoto@gmail.com"]
11
+ s.homepage = "http://rubygems.org/gems/libvirt"
12
+ s.summary = "A ruby client library providing the raw interface to libvirt via FFI."
13
+ s.description = "A ruby client library providing the raw interface to libvirt via FFI."
14
+
15
+ s.rubyforge_project = "libvirt"
16
+
17
+ s.add_dependency "ffi", "~> 0.6.3"
18
+ s.add_dependency "nokogiri", "~> 1.4.3"
19
+
20
+ s.add_development_dependency "protest", "~> 0.4.0"
21
+ s.add_development_dependency "mocha", "~> 0.9.8"
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
@@ -0,0 +1,14 @@
1
+ require "test_helper"
2
+
3
+ Protest.describe("abstract collection") do
4
+ setup do
5
+ @klass = Libvirt::Collection::AbstractCollection
6
+
7
+ @connection = mock("connection")
8
+ @instance = @klass.new(@connection)
9
+ end
10
+
11
+ should "have interface be available as an attribute" do
12
+ assert_equal @connection, @instance.interface
13
+ end
14
+ end