libvirt_ffi 0.2.1 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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