libvirt_ffi 0.2.1 → 0.5.1

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +78 -0
  3. data/Gemfile +7 -2
  4. data/Rakefile +6 -1
  5. data/bin/console +1 -0
  6. data/exe/libvirt +1 -0
  7. data/lib/libvirt.rb +14 -13
  8. data/lib/libvirt/base_info.rb +34 -0
  9. data/lib/libvirt/connection.rb +156 -47
  10. data/lib/libvirt/domain.rb +136 -8
  11. data/lib/libvirt/domain_callback_storage.rb +69 -0
  12. data/lib/libvirt/errors.rb +65 -0
  13. data/lib/libvirt/event.rb +60 -38
  14. data/lib/libvirt/ffi.rb +17 -0
  15. data/lib/libvirt/ffi/common.rb +8 -1
  16. data/lib/libvirt/ffi/domain.rb +796 -69
  17. data/lib/libvirt/ffi/error.rb +243 -0
  18. data/lib/libvirt/ffi/event.rb +30 -36
  19. data/lib/libvirt/ffi/helpers.rb +17 -0
  20. data/lib/libvirt/ffi/host.rb +122 -0
  21. data/lib/libvirt/ffi/storage.rb +149 -0
  22. data/lib/libvirt/ffi/stream.rb +74 -0
  23. data/lib/libvirt/node_info.rb +2 -41
  24. data/lib/libvirt/storage_pool.rb +70 -0
  25. data/lib/libvirt/storage_pool_info.rb +7 -0
  26. data/lib/libvirt/storage_volume.rb +51 -0
  27. data/lib/libvirt/storage_volume_info.rb +7 -0
  28. data/lib/libvirt/stream.rb +124 -0
  29. data/lib/libvirt/util.rb +75 -8
  30. data/lib/libvirt/version.rb +1 -1
  31. data/lib/libvirt/xml.rb +23 -0
  32. data/lib/libvirt/xml/disk.rb +59 -0
  33. data/lib/libvirt/xml/domain.rb +76 -0
  34. data/lib/libvirt/xml/generic.rb +252 -0
  35. data/lib/libvirt/xml/graphics.rb +14 -0
  36. data/lib/libvirt/xml/max_vcpu.rb +12 -0
  37. data/lib/libvirt/xml/memory.rb +14 -0
  38. data/lib/libvirt/xml/storage_pool.rb +24 -0
  39. data/lib/libvirt/xml/storage_volume.rb +32 -0
  40. data/lib/libvirt/xml/vcpu.rb +12 -0
  41. data/lib/libvirt_ffi.rb +2 -0
  42. data/libvirt.gemspec +5 -1
  43. data/test_usage/support/libvirt_async.rb +33 -31
  44. data/test_usage/support/log_formatter.rb +5 -10
  45. data/test_usage/test_domain.rb +43 -0
  46. data/test_usage/test_event_loop.rb +134 -33
  47. data/test_usage/test_libvirtd_restart.rb +63 -0
  48. data/test_usage/test_metadata.rb +104 -0
  49. data/test_usage/test_screenshot.rb +197 -0
  50. data/test_usage/test_storage.rb +52 -0
  51. metadata +46 -6
  52. data/lib/libvirt/error.rb +0 -6
  53. data/lib/libvirt/ffi/connection.rb +0 -84
  54. data/lib/libvirt/ffi/libvirt.rb +0 -17
  55. data/lib/libvirt/ffi/node_info.rb +0 -37
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ module FFI
5
+ module Storage
6
+ # https://libvirt.org/html/libvirt-libvirt-storage.html
7
+
8
+ extend ::FFI::Library
9
+ extend Helpers
10
+ ffi_lib Util.library_path
11
+
12
+ # enum virStoragePoolState
13
+ enum :pool_state, [
14
+ :INACTIVE, 0x0, # Not running
15
+ :BUILDING, 0x1, # Initializing pool, not available
16
+ :RUNNING, 0x2, # Running normally
17
+ :DEGRADED, 0x3, # Running degraded
18
+ :INACCESSIBLE, 0x4 # Running, but not accessible
19
+ ]
20
+
21
+ # enum virConnectListAllStoragePoolsFlags
22
+ enum :list_all_pools_flags, [
23
+ :INACTIVE, 0x1,
24
+ :ACTIVE, 0x2,
25
+ :PERSISTENT, 0x4,
26
+ :TRANSIENT, 0x8,
27
+ :AUTOSTART, 0x10,
28
+ :NO_AUTOSTART, 0x20, # List pools by type
29
+ :DIR, 0x40,
30
+ :FS, 0x80,
31
+ :NETFS, 0x100,
32
+ :LOGICAL, 0x200,
33
+ :DISK, 0x400,
34
+ :ISCSI, 0x800,
35
+ :SCSI, 0x1000,
36
+ :MPATH, 0x2000,
37
+ :RBD, 0x4000,
38
+ :SHEEPDOG, 0x8000,
39
+ :GLUSTER, 0x10000,
40
+ :ZFS, 0x20000,
41
+ :VSTORAGE, 0x40000,
42
+ :ISCSI_DIRECT, 0x80000
43
+ ]
44
+
45
+ # enum virStorageVolInfoFlags
46
+ enum :volume_info_flags, [
47
+ :USE_ALLOCATION, 0x0, # Return the physical size in allocation
48
+ :GET_PHYSICAL, 0x1
49
+ ]
50
+
51
+ # enum virStorageVolType
52
+ enum :volume_type, [
53
+ :FILE, 0x0, # Regular file based volumes
54
+ :BLOCK, 0x1, # Block based volumes
55
+ :DIR, 0x2, # Directory-passthrough based volume
56
+ :NETWORK, 0x3, # Network volumes like RBD (RADOS Block Device)
57
+ :NETDIR, 0x4, # Network accessible directory that can contain other network volumes
58
+ :PLOOP, 0x5 # Ploop based volumes
59
+ ]
60
+
61
+ # enum virStorageXMLFlags
62
+ enum :xml_flags, [
63
+ :INACTIVE, 0x1 # dump inactive pool/volume information
64
+ ]
65
+
66
+ # struct virStoragePoolInfo {
67
+ # int state # virStoragePoolState flags
68
+ # unsigned long long capacity # Logical size bytes
69
+ # unsigned long long allocation # Current allocation bytes
70
+ # unsigned long long available # Remaining free space bytes
71
+ # }
72
+ class PoolInfoStruct < ::FFI::Struct
73
+ layout :state, FFI::Storage.enum_type(:pool_state),
74
+ :capacity, :ulong_long,
75
+ :allocation, :ulong_long,
76
+ :available, :ulong_long
77
+ end
78
+
79
+ # struct virStorageVolInfo {
80
+ # int type # virStorageVolType flags
81
+ # unsigned long long capacity # Logical size bytes
82
+ # unsigned long long allocation # Current allocation bytes
83
+ # }
84
+ class VolumeInfoStruct < ::FFI::Struct
85
+ layout :type, FFI::Storage.enum_type(:volume_type),
86
+ :capacity, :ulong_long,
87
+ :allocation, :ulong_long
88
+ end
89
+
90
+ # int virConnectListAllStoragePools (
91
+ # virConnectPtr conn,
92
+ # virStoragePoolPtr ** pools,
93
+ # unsigned int flags
94
+ # )
95
+ attach_function :virConnectListAllStoragePools, [:pointer, :pointer, :uint], :int
96
+
97
+ # int virStoragePoolGetInfo (
98
+ # virStoragePoolPtr pool,
99
+ # virStoragePoolInfoPtr info
100
+ # )
101
+ attach_function :virStoragePoolGetInfo, [:pointer, :pointer], :int
102
+
103
+ # char * virStoragePoolGetXMLDesc (
104
+ # virStoragePoolPtr pool,
105
+ # unsigned int flags
106
+ # )
107
+ attach_function :virStoragePoolGetXMLDesc, [:pointer, :xml_flags], :string
108
+
109
+ # int virStoragePoolRef (
110
+ # virStoragePoolPtr pool
111
+ # )
112
+ attach_function :virStoragePoolRef, [:pointer], :int
113
+
114
+ # int virStoragePoolFree (
115
+ # virStoragePoolPtr pool
116
+ # )
117
+ attach_function :virStoragePoolFree, [:pointer], :int
118
+
119
+ # int virStoragePoolListAllVolumes (
120
+ # virStoragePoolPtr pool,
121
+ # virStorageVolPtr ** vols,
122
+ # unsigned int flags
123
+ # )
124
+ attach_function :virStoragePoolListAllVolumes, [:pointer, :pointer, :uint], :int
125
+
126
+ # int virStorageVolRef (
127
+ # virStorageVolPtr vol
128
+ # )
129
+ attach_function :virStorageVolRef, [:pointer], :int
130
+
131
+ # int virStorageVolFree (
132
+ # virStorageVolPtr vol
133
+ # )
134
+ attach_function :virStorageVolFree, [:pointer], :int
135
+
136
+ # int virStorageVolGetInfo (
137
+ # virStorageVolPtr vol,
138
+ # virStorageVolInfoPtr info
139
+ # )
140
+ attach_function :virStorageVolGetInfo, [:pointer, :pointer], :int
141
+
142
+ # char * virStorageVolGetXMLDesc (
143
+ # virStorageVolPtr vol,
144
+ # unsigned int flags
145
+ # )
146
+ attach_function :virStorageVolGetXMLDesc, [:pointer, :xml_flags], :string
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ module FFI
5
+ module Stream
6
+ # https://libvirt.org/html/libvirt-libvirt-stream.html
7
+
8
+ extend ::FFI::Library
9
+ extend Helpers
10
+ ffi_lib Util.library_path
11
+
12
+ # virStreamPtr virStreamNew (
13
+ # virConnectPtr conn,
14
+ # unsigned int flags
15
+ # )
16
+ attach_function :virStreamNew, [:pointer, :uint], :pointer
17
+
18
+ # typedef void (*virStreamEventCallback) (
19
+ # virStreamPtr stream,
20
+ # int events,
21
+ # void * opaque
22
+ # )
23
+ callback :virStreamEventCallback, [:pointer, :int, :pointer], :void
24
+
25
+ # int virStreamEventAddCallback (
26
+ # virStreamPtr stream,
27
+ # int events,
28
+ # virStreamEventCallback cb,
29
+ # void * opaque,
30
+ # virFreeCallback ff
31
+ # )
32
+ attach_function :virStreamEventAddCallback, [
33
+ :pointer,
34
+ :int,
35
+ :virStreamEventCallback,
36
+ :pointer,
37
+ FFI::Common::FREE_CALLBACK
38
+ ], :int
39
+
40
+ # int virStreamEventRemoveCallback (
41
+ # virStreamPtr stream
42
+ # )
43
+ attach_function :virStreamEventRemoveCallback, [:pointer], :int
44
+
45
+ # int virStreamEventUpdateCallback (
46
+ # virStreamPtr stream,
47
+ # int events
48
+ # )
49
+ attach_function :virStreamEventUpdateCallback, [:pointer, :int], :int
50
+
51
+ # int virStreamFinish (
52
+ # virStreamPtr stream
53
+ # )
54
+ attach_function :virStreamFinish, [:pointer], :int
55
+
56
+ # int virStreamFree (
57
+ # virStreamPtr stream
58
+ # )
59
+ attach_function :virStreamFree, [:pointer], :int
60
+
61
+ # int virStreamAbort (
62
+ # virStreamPtr stream
63
+ # )
64
+ attach_function :virStreamAbort, [:pointer], :int
65
+
66
+ # int virStreamRecv (
67
+ # virStreamPtr stream,
68
+ # char *data,
69
+ # size_t nbytes
70
+ # )
71
+ attach_function :virStreamRecv, [:pointer, :pointer, :size_t], :int
72
+ end
73
+ end
74
+ end
@@ -1,46 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Libvirt
4
- class NodeInfo
5
- def initialize(node_info_ptr)
6
- @node_info_ptr = node_info_ptr
7
- @node_info_struct = FFI::NodeInfo::Struct.new(node_info_ptr)
8
- end
9
-
10
- def [](attr)
11
- @node_info_struct[attr]
12
- end
13
-
14
- def model
15
- @node_info_struct[:model].to_s
16
- end
17
-
18
- def cpus
19
- @node_info_struct[:cpus]
20
- end
21
-
22
- def mhz
23
- @node_info_struct[:mhz]
24
- end
25
-
26
- def nodes
27
- @node_info_struct[:nodes]
28
- end
29
-
30
- def sockets
31
- @node_info_struct[:sockets]
32
- end
33
-
34
- def cores
35
- @node_info_struct[:cores]
36
- end
37
-
38
- def threads
39
- @node_info_struct[:threads]
40
- end
41
-
42
- def memory
43
- @node_info_struct[:memory]
44
- end
4
+ class NodeInfo < BaseInfo
5
+ struct_class FFI::Host::NodeInfoStruct
45
6
  end
46
7
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ class StoragePool
5
+ def self.load_ref(pointer)
6
+ result = FFI::Storage.virStoragePoolRef(pointer)
7
+ raise Errors::LibError, "Couldn't retrieve storage pool reference" if result.negative?
8
+
9
+ new(pointer)
10
+ end
11
+
12
+ def initialize(pointer)
13
+ @ptr = pointer
14
+
15
+ free = ->(obj_id) do
16
+ Util.log(:debug) { "Finalize Libvirt::StoragePool 0x#{obj_id.to_s(16)} @ptr=#{@ptr}," }
17
+ return unless @ptr
18
+
19
+ fr_result = FFI::Storage.virStoragePoolFree(@ptr)
20
+ warn "Couldn't free Libvirt::StoragePool (0x#{obj_id.to_s(16)}) pointer #{@ptr.address}" if fr_result.negative?
21
+ end
22
+ ObjectSpace.define_finalizer(self, free)
23
+ end
24
+
25
+ def to_ptr
26
+ @ptr
27
+ end
28
+
29
+ def info
30
+ info_ptr = ::FFI::MemoryPointer.new(FFI::Storage::PoolInfoStruct.by_value)
31
+ result = FFI::Storage.virStoragePoolGetInfo(@ptr, info_ptr)
32
+ raise Errors::LibError, "Couldn't get storage pool info" if result.negative?
33
+
34
+ StoragePoolInfo.new(info_ptr)
35
+ end
36
+
37
+ def xml_desc(options_or_flags = nil)
38
+ flags = Util.parse_flags options_or_flags, FFI::Storage.enum_type(:xml_flags)
39
+ result = FFI::Storage.virStoragePoolGetXMLDesc(@ptr, flags)
40
+ raise Errors::LibError, "Couldn't get storage pool xml desc" if result.nil?
41
+
42
+ result
43
+ end
44
+
45
+ def list_all_volumes_qty
46
+ result = FFI::Storage.virStoragePoolListAllVolumes(@ptr, nil, 0)
47
+ raise Errors::LibError, "Couldn't retrieve volumes qty" if result.negative?
48
+
49
+ result
50
+ end
51
+
52
+ def list_all_volumes
53
+ size = list_all_volumes_qty
54
+ return [] if size.zero?
55
+
56
+ storage_volumes_ptr = ::FFI::MemoryPointer.new(:pointer, size)
57
+ result = FFI::Storage.virStoragePoolListAllVolumes(@ptr, storage_volumes_ptr, 0)
58
+ raise Errors::LibError, "Couldn't retrieve volumes list" if result.negative?
59
+
60
+ ptr = storage_volumes_ptr.read_pointer
61
+ ptr.get_array_of_pointer(0, size).map { |stv_ptr| StorageVolume.new(stv_ptr) }
62
+ end
63
+
64
+ private
65
+
66
+ def dbg(&block)
67
+ Util.log(:debug, 'Libvirt::Domain', &block)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ class StoragePoolInfo < BaseInfo
5
+ struct_class FFI::Storage::PoolInfoStruct
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ class StorageVolume
5
+ def self.load_ref(pointer)
6
+ result = FFI::Storage.virStorageVolRef(pointer)
7
+ raise Errors::LibError, "Couldn't retrieve storage volume reference" if result.negative?
8
+
9
+ new(pointer)
10
+ end
11
+
12
+ def initialize(pointer)
13
+ @ptr = pointer
14
+
15
+ free = ->(obj_id) do
16
+ Util.log(:debug) { "Finalize Libvirt::StorageVolume 0x#{obj_id.to_s(16)} @ptr=#{@ptr}," }
17
+ return unless @ptr
18
+
19
+ fr_result = FFI::Storage.virStorageVolFree(@ptr)
20
+ warn "Couldn't free Libvirt::StorageVolume (0x#{obj_id.to_s(16)}) pointer #{@ptr.address}" if fr_result.negative?
21
+ end
22
+ ObjectSpace.define_finalizer(self, free)
23
+ end
24
+
25
+ def to_ptr
26
+ @ptr
27
+ end
28
+
29
+ def info
30
+ info_ptr = ::FFI::MemoryPointer.new(FFI::Storage::VolumeInfoStruct.by_value)
31
+ result = FFI::Storage.virStorageVolGetInfo(@ptr, info_ptr)
32
+ raise Errors::LibError, "Couldn't get storage volume info" if result.negative?
33
+
34
+ StorageVolumeInfo.new(info_ptr)
35
+ end
36
+
37
+ def xml_desc(options_or_flags = nil)
38
+ flags = Util.parse_flags options_or_flags, FFI::Storage.enum_type(:xml_flags)
39
+ result = FFI::Storage.virStorageVolGetXMLDesc(@ptr, flags)
40
+ raise Errors::LibError, "Couldn't get storage volume xml desc" if result.nil?
41
+
42
+ result
43
+ end
44
+
45
+ private
46
+
47
+ def dbg(&block)
48
+ Util.log(:debug, 'Libvirt::Domain', &block)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ class StorageVolumeInfo < BaseInfo
5
+ struct_class FFI::Storage::VolumeInfoStruct
6
+ end
7
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ class Stream
5
+ NONBLOCK = 0x1
6
+ EVENT_READABLE = 0x1
7
+ EVENT_WRITABLE = 0x2
8
+
9
+ def initialize(stream_ptr)
10
+ @stream_ptr = stream_ptr
11
+ @cb = nil
12
+ @opaque = nil
13
+
14
+ free = ->(obj_id) do
15
+ Util.log(:debug) { "Finalize Libvirt::Stream 0x#{obj_id.to_s(16)} @stream_ptr=#{@stream_ptr}, @cb=#{@cb}, @opaque=#{@opaque}," }
16
+ return unless @stream_ptr
17
+
18
+ if @cb
19
+ rcb_result = FFI::Stream.virStreamEventRemoveCallback(@stream_ptr)
20
+ warn("Couldn't remove callback Libvirt::Stream (0x#{obj_id.to_s(16)}) pointer #{@stream_ptr.address}") if rcb_result.negative?
21
+ ab_result = FFI::Stream.virStreamAbort(@stream_ptr)
22
+ warn("Couldn't abort Libvirt::Stream (0x#{obj_id.to_s(16)}) pointer #{@stream_ptr.address}") if ab_result.negative?
23
+ end
24
+ fr_result = FFI::Stream.virStreamFree(@stream_ptr)
25
+ warn("Couldn't free Libvirt::Stream (0x#{obj_id.to_s(16)}) pointer #{@stream_ptr.address}") if fr_result.negative?
26
+ end
27
+ ObjectSpace.define_finalizer(self, free)
28
+ end
29
+
30
+ def to_ptr
31
+ @stream_ptr
32
+ end
33
+
34
+ # @param events [Integer] bit OR of EVENT_READABLE, EVENT_READABLE
35
+ # @param opaque [Object]
36
+ # @yield [Stream]
37
+ def event_add_callback(events, opaque, &block)
38
+ dbg { "#event_add_callback events=#{events}, opaque=#{opaque}" }
39
+
40
+ raise Errors::LibError, 'callback already added' unless @cb.nil?
41
+
42
+ @opaque = opaque
43
+ @cb = FFI::Stream.callback_function(:virStreamEventCallback) do |_stream_ptr, evs, _op|
44
+ # stream = Stream.new(stream_ptr)
45
+ block.call(self, evs, @opaque)
46
+ end
47
+
48
+ result = FFI::Stream.virStreamEventAddCallback(@stream_ptr, events, @cb, nil, nil)
49
+ raise Errors::LibError, "Couldn't add stream event callback" if result.negative?
50
+
51
+ true
52
+ end
53
+
54
+ # @param events [Integer] bit OR of EVENT_READABLE, EVENT_READABLE
55
+ def event_update_callback(events)
56
+ dbg { "#event_update_callback events=#{events}" }
57
+
58
+ result = FFI::Stream.virStreamEventUpdateCallback(@stream_ptr, events)
59
+ raise Errors::LibError, "Couldn't remove stream event callback" if result.negative?
60
+
61
+ true
62
+ end
63
+
64
+ def event_remove_callback
65
+ dbg { '#event_remove_callback' }
66
+
67
+ result = FFI::Stream.virStreamEventRemoveCallback(@stream_ptr)
68
+ raise Errors::LibError, "Couldn't remove stream event callback" if result.negative?
69
+
70
+ opaque = @opaque
71
+ @cb = nil
72
+ @opaque = nil
73
+ opaque
74
+ end
75
+
76
+ def finish
77
+ result = FFI::Stream.virStreamFinish(@stream_ptr)
78
+ raise Errors::LibError, "Couldn't remove stream event callback" if result.negative?
79
+
80
+ @cb = nil
81
+ @opaque = nil
82
+ end
83
+
84
+ def abort_stream
85
+ result = FFI::Stream.virStreamAbort(@stream_ptr)
86
+ raise Errors::LibError, "Couldn't remove stream event callback" if result.negative?
87
+
88
+ @cb = nil
89
+ @opaque = nil
90
+ end
91
+
92
+ def free_stream
93
+ result = FFI::Stream.virStreamFree(@stream_ptr)
94
+ raise Errors::LibError, "Couldn't free stream event callback" if result.negative?
95
+
96
+ @cb = nil
97
+ @opaque = nil
98
+ @stream_ptr = nil
99
+ end
100
+
101
+ def recv(bytes)
102
+ buffer = ::FFI::MemoryPointer.new(:char, bytes)
103
+ result = FFI::Stream.virStreamRecv(@stream_ptr, buffer, bytes)
104
+ if result == -1
105
+ abort_stream
106
+ [-1, nil]
107
+ elsif result.zero?
108
+ [0, nil]
109
+ elsif result == -2
110
+ [-2, nil]
111
+ elsif result.positive?
112
+ [result, buffer.read_bytes(result)]
113
+ else
114
+ raise Errors::LibError, "Invalid response from virStreamRecv #{result.inspect}"
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ def dbg(&block)
121
+ Util.log(:debug, 'Libvirt::Stream', &block)
122
+ end
123
+ end
124
+ end