libvirt_ffi 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/lib/libvirt.rb +1 -2
- data/lib/libvirt/connection.rb +59 -24
- data/lib/libvirt/domain.rb +16 -1
- data/lib/libvirt/domain_callback_storage.rb +65 -0
- data/lib/libvirt/ffi/connection.rb +10 -0
- data/lib/libvirt/ffi/domain.rb +422 -37
- data/lib/libvirt/stream.rb +16 -8
- data/lib/libvirt/util.rb +14 -0
- data/lib/libvirt/version.rb +1 -1
- data/test_usage/test_event_loop.rb +39 -14
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79ea563057bb675ad519b6dfafca175b69afe8f9b0dc9b3ab76c32175372eab1
|
4
|
+
data.tar.gz: 86420a7e48c60ff3a4cf3bbd5377d8070facd1e453494b16225a78c7c3e4c898
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5c81de1008c0a2c55bcacbbd0a50611d492eba8ee7232fb007f861e011f71053e75434563374c60037a89330b10da5f2873b5fd7359a8ba7bd9a88c011da01d
|
7
|
+
data.tar.gz: b803fae7ff7a85fa744784c89e6566acd43bad33f3229af2f97404e852021005084ca7513afea67f28c9e6e0bc9d2309731f25899bb5b9b5fcb2d8568c46c7d3
|
data/Gemfile
CHANGED
data/lib/libvirt.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'ffi'
|
4
4
|
require 'objspace'
|
5
|
+
require 'libvirt/domain_callback_storage'
|
5
6
|
require 'libvirt/util'
|
6
7
|
require 'libvirt/error'
|
7
8
|
require 'libvirt/ffi/common'
|
@@ -24,8 +25,6 @@ module Libvirt
|
|
24
25
|
EVENT_HANDLE_ERROR = 4
|
25
26
|
EVENT_HANDLE_HANGUP = 8
|
26
27
|
|
27
|
-
DOMAIN_EVENT_ID_LIFECYCLE = 0
|
28
|
-
|
29
28
|
class << self
|
30
29
|
def lib_version
|
31
30
|
version_ptr = ::FFI::MemoryPointer.new(:ulong)
|
data/lib/libvirt/connection.rb
CHANGED
@@ -2,20 +2,48 @@
|
|
2
2
|
|
3
3
|
module Libvirt
|
4
4
|
class Connection
|
5
|
+
DOMAIN_EVENT_IDS = FFI::Domain.enum_type(:event_id).symbols.dup.freeze
|
6
|
+
|
7
|
+
STORAGE = DomainCallbackStorage.new
|
8
|
+
|
9
|
+
DOMAIN_EVENT_CALLBACKS = FFI::Domain.enum_type(:event_id).symbol_map.map do |name, event_id|
|
10
|
+
func = FFI::Domain.event_callback(event_id) do |conn_ptr, dom_ptr, *args, op_ptr|
|
11
|
+
connection = Connection.load_ref(conn_ptr)
|
12
|
+
domain = Domain.load_ref(dom_ptr)
|
13
|
+
block, opaque = STORAGE.retrieve_from_pointer(op_ptr)
|
14
|
+
block.call(connection, domain, *args, opaque)
|
15
|
+
end
|
16
|
+
[name, func]
|
17
|
+
end.to_h
|
18
|
+
|
19
|
+
def self.load_ref(conn_ptr)
|
20
|
+
ref_result = FFI::Connection.virConnectRef(conn_ptr)
|
21
|
+
raise Error, "Couldn't retrieve connection reference" if ref_result < 0
|
22
|
+
new(nil).send(:set_connection, conn_ptr)
|
23
|
+
end
|
24
|
+
|
5
25
|
def initialize(uri)
|
6
26
|
@uri = uri
|
7
27
|
@conn_ptr = ::FFI::Pointer.new(0)
|
8
|
-
@cb_data = {}
|
9
28
|
|
10
29
|
free = ->(obj_id) do
|
11
|
-
|
30
|
+
return if @conn_ptr.null?
|
31
|
+
cl_result = FFI::Connection.virConnectClose(@conn_ptr)
|
32
|
+
STDERR.puts "Couldn't close Libvirt::Connection (0x#{obj_id.to_s(16)}) pointer #{@conn_ptr.address}" if cl_result < 0
|
12
33
|
end
|
13
34
|
ObjectSpace.define_finalizer(self, free)
|
14
35
|
end
|
15
36
|
|
16
37
|
def open
|
17
38
|
@conn_ptr = FFI::Connection.virConnectOpen(@uri)
|
18
|
-
raise Error, "Couldn't
|
39
|
+
raise Error, "Couldn't open connection to #{@uri.inspect}" if @conn_ptr.null?
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
def close
|
44
|
+
result = FFI::Connection.virConnectClose(@conn_ptr)
|
45
|
+
raise Error, "Couldn't close connection to #{@uri.inspect}" if result < 0
|
46
|
+
@conn_ptr = ::FFI::Pointer.new(0)
|
19
47
|
true
|
20
48
|
end
|
21
49
|
|
@@ -66,42 +94,46 @@ module Libvirt
|
|
66
94
|
ptr.get_array_of_pointer(0, size).map { |dom_ptr| Libvirt::Domain.new(dom_ptr) }
|
67
95
|
end
|
68
96
|
|
69
|
-
# @yield conn, dom
|
97
|
+
# @yield conn, dom, *args
|
70
98
|
def register_domain_event_callback(event_id, domain = nil, opaque = nil, &block)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
99
|
+
Util.logger.debug { "Libvirt::Connection#register_domain_event_callback event_id=#{event_id}" }
|
100
|
+
|
101
|
+
enum = FFI::Domain.enum_type(:event_id)
|
102
|
+
event_id, event_id_sym = Util.parse_enum(enum, event_id)
|
103
|
+
cb = DOMAIN_EVENT_CALLBACKS.fetch(event_id_sym)
|
104
|
+
|
105
|
+
cb_data, cb_data_free_func = STORAGE.allocate_struct
|
76
106
|
|
77
107
|
result = FFI::Domain.virConnectDomainEventRegisterAny(
|
78
108
|
@conn_ptr,
|
79
109
|
domain&.to_ptr,
|
80
110
|
event_id,
|
81
111
|
cb,
|
82
|
-
|
83
|
-
|
112
|
+
cb_data.pointer,
|
113
|
+
cb_data_free_func
|
84
114
|
)
|
85
|
-
|
115
|
+
if result < 0
|
116
|
+
cb_data.pointer.free
|
117
|
+
raise Error, "Couldn't register domain event callback"
|
118
|
+
end
|
86
119
|
|
87
|
-
|
120
|
+
STORAGE.store_struct(
|
121
|
+
cb_data,
|
122
|
+
connection_pointer: @conn_ptr,
|
123
|
+
callback_id: result,
|
124
|
+
cb: block,
|
125
|
+
opaque: opaque
|
126
|
+
)
|
88
127
|
result
|
89
128
|
end
|
90
129
|
|
91
130
|
def deregister_domain_event_callback(callback_id)
|
92
|
-
|
131
|
+
Util.logger.debug { "Libvirt::Connection#deregister_domain_event_callback callback_id=#{callback_id}" }
|
132
|
+
|
93
133
|
result = FFI::Domain.virConnectDomainEventDeregisterAny(@conn_ptr, callback_id)
|
94
134
|
raise Error, "Couldn't deregister domain event callback" if result < 0
|
95
|
-
true
|
96
|
-
end
|
97
135
|
|
98
|
-
|
99
|
-
version_ptr = ::FFI::MemoryPointer.new(:ulong)
|
100
|
-
result = FFI::Connection.virConnectGetVersion(@conn_ptr, version_ptr)
|
101
|
-
raise Error, "Couldn't get connection version" if result < 0
|
102
|
-
version_number = version_ptr.get_ulong(0)
|
103
|
-
# version_number = FFI::Connection.virConnectGetVersion(@conn_ptr)
|
104
|
-
Libvirt::Util.parse_version(version_number)
|
136
|
+
STORAGE.remove_struct(connection_pointer: @conn_ptr, callback_id: callback_id)
|
105
137
|
end
|
106
138
|
|
107
139
|
def lib_version
|
@@ -109,7 +141,6 @@ module Libvirt
|
|
109
141
|
result = FFI::Connection.virConnectGetLibVersion(@conn_ptr, version_ptr)
|
110
142
|
raise Error, "Couldn't get connection lib version" if result < 0
|
111
143
|
version_number = version_ptr.get_ulong(0)
|
112
|
-
# version_number = FFI::Connection.virConnectGetLibVersion(@conn_ptr)
|
113
144
|
Libvirt::Util.parse_version(version_number)
|
114
145
|
end
|
115
146
|
|
@@ -141,6 +172,10 @@ module Libvirt
|
|
141
172
|
|
142
173
|
private
|
143
174
|
|
175
|
+
def set_connection(conn_ptr)
|
176
|
+
@conn_ptr = conn_ptr
|
177
|
+
end
|
178
|
+
|
144
179
|
def check_open!
|
145
180
|
raise Error, "Connection to #{@uri.inspect} is not open" if @conn_ptr.null?
|
146
181
|
end
|
data/lib/libvirt/domain.rb
CHANGED
@@ -2,11 +2,20 @@
|
|
2
2
|
|
3
3
|
module Libvirt
|
4
4
|
class Domain
|
5
|
+
|
6
|
+
def self.load_ref(dom_ptr)
|
7
|
+
ref_result = FFI::Domain.virDomainRef(dom_ptr)
|
8
|
+
raise Error, "Couldn't retrieve domain reference" if ref_result < 0
|
9
|
+
new(dom_ptr)
|
10
|
+
end
|
11
|
+
|
5
12
|
def initialize(dom_ptr)
|
6
13
|
@dom_ptr = dom_ptr
|
7
14
|
|
8
15
|
free = ->(obj_id) do
|
9
|
-
|
16
|
+
return unless @dom_ptr
|
17
|
+
fr_result = FFI::Domain.virDomainFree(@dom_ptr)
|
18
|
+
STDERR.puts "Couldn't free Libvirt::Domain (0x#{obj_id.to_s(16)}) pointer #{@dom_ptr.address}" if fr_result < 0
|
10
19
|
end
|
11
20
|
ObjectSpace.define_finalizer(self, free)
|
12
21
|
end
|
@@ -64,5 +73,11 @@ module Libvirt
|
|
64
73
|
# free pointer required
|
65
74
|
mime_type
|
66
75
|
end
|
76
|
+
|
77
|
+
def free_domain
|
78
|
+
result = FFI::Domain.virDomainFree(@dom_ptr)
|
79
|
+
raise Error, "Couldn't free domain" if result < 0
|
80
|
+
@dom_ptr = nil
|
81
|
+
end
|
67
82
|
end
|
68
83
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Libvirt
|
2
|
+
class DomainCallbackStorage
|
3
|
+
|
4
|
+
class CallbackDataStruct < ::FFI::Struct
|
5
|
+
layout :connection_pointer, :pointer,
|
6
|
+
:callback_id, :int
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@inner_storage = Hash.new { |h, key| h[key] = {} }
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Array<2>]
|
14
|
+
# cb_data [Libvirt::DomainCallbackStorage::CallbackDataStruct],
|
15
|
+
# cb_data_free_func [FFI::Function]
|
16
|
+
def allocate_struct
|
17
|
+
Util.logger.debug { "Libvirt::DomainCallbackStorage#allocate_struct" }
|
18
|
+
|
19
|
+
cb_data_ptr = ::FFI::MemoryPointer.new(:char, CallbackDataStruct.size, false)
|
20
|
+
cb_data = CallbackDataStruct.new(cb_data_ptr)
|
21
|
+
cb_data_free_func = ::FFI::Function.new(:void, [:pointer]) do |pointer|
|
22
|
+
Util.logger.debug { "Libvirt::DomainCallbackStorage cb_data_free_func triggered" }
|
23
|
+
remove_struct(pointer: pointer)
|
24
|
+
end
|
25
|
+
[cb_data, cb_data_free_func]
|
26
|
+
end
|
27
|
+
|
28
|
+
def store_struct(cb_data, connection_pointer:, callback_id:, cb:, opaque:)
|
29
|
+
Util.logger.debug { "Libvirt::DomainCallbackStorage#store_struct" }
|
30
|
+
|
31
|
+
cb_data[:connection_pointer] = connection_pointer
|
32
|
+
cb_data[:callback_id] = callback_id
|
33
|
+
@inner_storage[connection_pointer.address][callback_id] = { cb: cb, opaque: opaque, pointer: cb_data.pointer }
|
34
|
+
end
|
35
|
+
|
36
|
+
def remove_struct(pointer: nil, connection_pointer: nil, callback_id: nil)
|
37
|
+
Util.logger.debug { "Libvirt::DomainCallbackStorage#remove_struct pointer=#{pointer}, connection_pointer=#{connection_pointer}, callback_id=#{callback_id}," }
|
38
|
+
|
39
|
+
if pointer
|
40
|
+
cb_data_struct = CallbackDataStruct.new(pointer)
|
41
|
+
connection_pointer = cb_data_struct[:connection_pointer]
|
42
|
+
callback_id = cb_data_struct[:callback_id]
|
43
|
+
end
|
44
|
+
|
45
|
+
cb_data = @inner_storage[connection_pointer.address].delete(callback_id)
|
46
|
+
pointer ||= cb_data[:pointer]
|
47
|
+
@inner_storage.delete(connection_pointer.address) if @inner_storage[connection_pointer.address].empty?
|
48
|
+
|
49
|
+
#pointer.free
|
50
|
+
cb_data[:opaque]
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param [::FFI::Pointer]
|
54
|
+
# @return [Array<2>] cb [Proc], opaque [Object]
|
55
|
+
def retrieve_from_pointer(pointer)
|
56
|
+
Util.logger.debug { "Libvirt::DomainCallbackStorage#retrieve_from_pointer pointer=#{pointer}," }
|
57
|
+
|
58
|
+
cb_data_struct = CallbackDataStruct.new(pointer)
|
59
|
+
connection_pointer = cb_data_struct[:connection_pointer]
|
60
|
+
callback_id = cb_data_struct[:callback_id]
|
61
|
+
cb_data = @inner_storage[connection_pointer.address][callback_id]
|
62
|
+
[cb_data[:cb], cb_data[:opaque]]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -79,6 +79,16 @@ module Libvirt
|
|
79
79
|
# virConnectPtr conn
|
80
80
|
# )
|
81
81
|
attach_function :virConnectGetCapabilities, [:pointer], :string # strptr ?
|
82
|
+
|
83
|
+
# int virConnectClose (
|
84
|
+
# virConnectPtr conn
|
85
|
+
# )
|
86
|
+
attach_function :virConnectClose, [:pointer], :int
|
87
|
+
|
88
|
+
# int virConnectRef (
|
89
|
+
# virConnectPtr conn
|
90
|
+
# )
|
91
|
+
attach_function :virConnectRef, [:pointer], :int
|
82
92
|
end
|
83
93
|
end
|
84
94
|
end
|
data/lib/libvirt/ffi/domain.rb
CHANGED
@@ -8,6 +8,85 @@ module Libvirt
|
|
8
8
|
|
9
9
|
UUID_STRING_BUFLEN = 0x80 # RFC4122
|
10
10
|
|
11
|
+
# enum virDomainEventID
|
12
|
+
enum :event_id, [
|
13
|
+
:LIFECYCLE, 0, # (0x0) virConnectDomainEventCallback
|
14
|
+
:REBOOT, 1, # (0x1) virConnectDomainEventGenericCallback
|
15
|
+
:RTC_CHANGE, 2, # (0x2) virConnectDomainEventRTCChangeCallback
|
16
|
+
:WATCHDOG, 3, # (0x3) virConnectDomainEventWatchdogCallback
|
17
|
+
:IO_ERROR, 4, # (0x4) virConnectDomainEventIOErrorCallback
|
18
|
+
:GRAPHICS, 5, # (0x5) virConnectDomainEventGraphicsCallback
|
19
|
+
:IO_ERROR_REASON, 6, # (0x6) virConnectDomainEventIOErrorReasonCallback
|
20
|
+
:CONTROL_ERROR, 7, # (0x7) virConnectDomainEventGenericCallback
|
21
|
+
:BLOCK_JOB, 8, # (0x8) virConnectDomainEventBlockJobCallback
|
22
|
+
:DISK_CHANGE, 9, # (0x9) virConnectDomainEventDiskChangeCallback
|
23
|
+
:TRAY_CHANGE, 10, # (0xa) virConnectDomainEventTrayChangeCallback
|
24
|
+
:PMWAKEUP, 11, # (0xb) virConnectDomainEventPMWakeupCallback
|
25
|
+
:PMSUSPEND, 12, # (0xc) virConnectDomainEventPMSuspendCallback
|
26
|
+
:BALLOON_CHANGE, 13, # (0xd) virConnectDomainEventBalloonChangeCallback
|
27
|
+
:PMSUSPEND_DISK, 14, # (0xe) virConnectDomainEventPMSuspendDiskCallback
|
28
|
+
:DEVICE_REMOVED, 15, # (0xf) virConnectDomainEventDeviceRemovedCallback
|
29
|
+
:BLOCK_JOB_2, 16, # (0x10) virConnectDomainEventBlockJobCallback
|
30
|
+
:TUNABLE, 17, # (0x11) virConnectDomainEventTunableCallback
|
31
|
+
:AGENT_LIFECYCLE, 18, # (0x12) virConnectDomainEventAgentLifecycleCallback
|
32
|
+
:DEVICE_ADDED, 19, # (0x13) virConnectDomainEventDeviceAddedCallback
|
33
|
+
:MIGRATION_ITERATION, 20, # (0x14) virConnectDomainEventMigrationIterationCallback
|
34
|
+
:JOB_COMPLETED, 21, # (0x15) virConnectDomainEventJobCompletedCallback
|
35
|
+
:DEVICE_REMOVAL_FAILED, 22, # (0x16) virConnectDomainEventDeviceRemovalFailedCallback
|
36
|
+
:METADATA_CHANGE, 23, # (0x17) virConnectDomainEventMetadataChangeCallback
|
37
|
+
:BLOCK_THRESHOLD, 24 # (0x18) virConnectDomainEventBlockThresholdCallback
|
38
|
+
]
|
39
|
+
|
40
|
+
EVENT_ID_TO_CALLBACK = {
|
41
|
+
LIFECYCLE: :virConnectDomainEventCallback,
|
42
|
+
REBOOT: :virConnectDomainEventGenericCallback,
|
43
|
+
RTC_CHANGE: :virConnectDomainEventRTCChangeCallback,
|
44
|
+
WATCHDOG: :virConnectDomainEventWatchdogCallback,
|
45
|
+
IO_ERROR: :virConnectDomainEventIOErrorCallback,
|
46
|
+
GRAPHICS: :virConnectDomainEventGraphicsCallback,
|
47
|
+
IO_ERROR_REASON: :virConnectDomainEventIOErrorReasonCallback,
|
48
|
+
CONTROL_ERROR: :virConnectDomainEventGenericCallback,
|
49
|
+
BLOCK_JOB: :virConnectDomainEventBlockJobCallback,
|
50
|
+
DISK_CHANGE: :virConnectDomainEventDiskChangeCallback,
|
51
|
+
TRAY_CHANGE: :virConnectDomainEventTrayChangeCallback,
|
52
|
+
PMWAKEUP: :virConnectDomainEventPMWakeupCallback,
|
53
|
+
PMSUSPEND: :virConnectDomainEventPMSuspendCallback,
|
54
|
+
BALLOON_CHANGE: :virConnectDomainEventBalloonChangeCallback,
|
55
|
+
PMSUSPEND_DISK: :virConnectDomainEventPMSuspendDiskCallback,
|
56
|
+
DEVICE_REMOVED: :virConnectDomainEventDeviceRemovedCallback,
|
57
|
+
BLOCK_JOB_2: :virConnectDomainEventBlockJobCallback,
|
58
|
+
TUNABLE: :virConnectDomainEventTunableCallback,
|
59
|
+
AGENT_LIFECYCLE: :virConnectDomainEventAgentLifecycleCallback,
|
60
|
+
DEVICE_ADDED: :virConnectDomainEventDeviceAddedCallback,
|
61
|
+
MIGRATION_ITERATION: :virConnectDomainEventMigrationIterationCallback,
|
62
|
+
JOB_COMPLETED: :virConnectDomainEventJobCompletedCallback,
|
63
|
+
DEVICE_REMOVAL_FAILED: :virConnectDomainEventDeviceRemovalFailedCallback,
|
64
|
+
METADATA_CHANGE: :virConnectDomainEventMetadataChangeCallback,
|
65
|
+
BLOCK_THRESHOLD: :virConnectDomainEventBlockThresholdCallback
|
66
|
+
}
|
67
|
+
|
68
|
+
# enum virDomainState
|
69
|
+
enum :state, [
|
70
|
+
:NOSTATE, 0x0, # no state
|
71
|
+
:RUNNING, 0x1, # the domain is running
|
72
|
+
:BLOCKED, 0x2, # the domain is blocked on resource
|
73
|
+
:PAUSED, 0x3, # the domain is paused by user
|
74
|
+
:SHUTDOWN, 0x4, # the domain is being shut down
|
75
|
+
:SHUTOFF, 0x5, # the domain is shut off
|
76
|
+
:CRASHED, 0x6, # the domain is crashed
|
77
|
+
:PMSUSPENDED, 0x7 # the domain is suspended by guest power management
|
78
|
+
]
|
79
|
+
|
80
|
+
# int virDomainFree (
|
81
|
+
# virDomainPtr domain
|
82
|
+
# )
|
83
|
+
attach_function :virDomainFree, [:pointer], :int
|
84
|
+
|
85
|
+
# int virDomainRef (
|
86
|
+
# virDomainPtr domain
|
87
|
+
# )
|
88
|
+
attach_function :virDomainRef, [:pointer], :int
|
89
|
+
|
11
90
|
# int virConnectDomainEventRegisterAny(
|
12
91
|
# virConnectPtr conn,
|
13
92
|
# virDomainPtr dom,
|
@@ -25,6 +104,12 @@ module Libvirt
|
|
25
104
|
:pointer
|
26
105
|
], :int
|
27
106
|
|
107
|
+
# int virConnectDomainEventDeregisterAny (
|
108
|
+
# virConnectPtr conn,
|
109
|
+
# int callbackID
|
110
|
+
# )
|
111
|
+
attach_function :virConnectDomainEventDeregisterAny, [:pointer, :int], :int
|
112
|
+
|
28
113
|
# int virConnectListAllDomains (
|
29
114
|
# virConnectPtr conn,
|
30
115
|
# virDomainPtr **domains,
|
@@ -32,39 +117,6 @@ module Libvirt
|
|
32
117
|
# )
|
33
118
|
attach_function :virConnectListAllDomains, [:pointer, :pointer, :uint], :int
|
34
119
|
|
35
|
-
# enum virDomainState {
|
36
|
-
# VIR_DOMAIN_NOSTATE = 0 (0x0)
|
37
|
-
# no state
|
38
|
-
# VIR_DOMAIN_RUNNING = 1 (0x1)
|
39
|
-
# the domain is running
|
40
|
-
# VIR_DOMAIN_BLOCKED = 2 (0x2)
|
41
|
-
# the domain is blocked on resource
|
42
|
-
# VIR_DOMAIN_PAUSED = 3 (0x3)
|
43
|
-
# the domain is paused by user
|
44
|
-
# VIR_DOMAIN_SHUTDOWN = 4 (0x4)
|
45
|
-
# the domain is being shut down
|
46
|
-
# VIR_DOMAIN_SHUTOFF = 5 (0x5)
|
47
|
-
# the domain is shut off
|
48
|
-
# VIR_DOMAIN_CRASHED = 6 (0x6)
|
49
|
-
# the domain is crashed
|
50
|
-
# VIR_DOMAIN_PMSUSPENDED = 7 (0x7)
|
51
|
-
# the domain is suspended by guest power management
|
52
|
-
# VIR_DOMAIN_LAST = 8 (0x8)
|
53
|
-
# NB: this enum value will increase over time as new events are added to the libvirt API.
|
54
|
-
# It reflects the last state supported by this version of the libvirt API.
|
55
|
-
# }
|
56
|
-
enum :states, [
|
57
|
-
:no_state, 0x0,
|
58
|
-
:running, 0x1,
|
59
|
-
:blocked, 0x2,
|
60
|
-
:paused, 0x3,
|
61
|
-
:shutdown, 0x4,
|
62
|
-
:shutoff, 0x5,
|
63
|
-
:crashed, 0x6,
|
64
|
-
:pm_suspended, 0x7,
|
65
|
-
:last, 0x8
|
66
|
-
]
|
67
|
-
|
68
120
|
# int virDomainGetState (
|
69
121
|
# virDomainPtr domain,
|
70
122
|
# int *state,
|
@@ -124,10 +176,343 @@ module Libvirt
|
|
124
176
|
# int detail,
|
125
177
|
# void * opaque
|
126
178
|
# )
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
179
|
+
callback :virConnectDomainEventCallback, [:pointer, :pointer, :int, :int, :pointer], :int
|
180
|
+
|
181
|
+
# typedef void (*virConnectDomainEventGenericCallback) (
|
182
|
+
# virConnectPtr conn,
|
183
|
+
# virDomainPtr dom,
|
184
|
+
# void * opaque
|
185
|
+
# )
|
186
|
+
callback :virConnectDomainEventGenericCallback, [:pointer, :pointer, :pointer], :void
|
187
|
+
|
188
|
+
# typedef void (*virConnectDomainEventRTCChangeCallback) (
|
189
|
+
# virConnectPtr conn,
|
190
|
+
# virDomainPtr dom,
|
191
|
+
# long long utcoffset,
|
192
|
+
# void * opaque
|
193
|
+
# )
|
194
|
+
callback :virConnectDomainEventRTCChangeCallback, [
|
195
|
+
:pointer,
|
196
|
+
:pointer,
|
197
|
+
:long_long,
|
198
|
+
:pointer
|
199
|
+
], :void
|
200
|
+
|
201
|
+
# typedef void (*virConnectDomainEventWatchdogCallback) (
|
202
|
+
# virConnectPtr conn,
|
203
|
+
# virDomainPtr dom,
|
204
|
+
# int action,
|
205
|
+
# void * opaque
|
206
|
+
# )
|
207
|
+
callback :virConnectDomainEventWatchdogCallback, [
|
208
|
+
:pointer,
|
209
|
+
:pointer,
|
210
|
+
:int,
|
211
|
+
:pointer
|
212
|
+
], :void
|
213
|
+
|
214
|
+
# typedef void (*virConnectDomainEventIOErrorCallback) (
|
215
|
+
# virConnectPtr conn,
|
216
|
+
# virDomainPtr dom,
|
217
|
+
# const char * srcPath,
|
218
|
+
# const char * devAlias,
|
219
|
+
# int action,
|
220
|
+
# void * opaque
|
221
|
+
# )
|
222
|
+
callback :virConnectDomainEventIOErrorCallback, [
|
223
|
+
:pointer,
|
224
|
+
:pointer,
|
225
|
+
:string,
|
226
|
+
:string,
|
227
|
+
:int,
|
228
|
+
:pointer
|
229
|
+
], :void
|
230
|
+
|
231
|
+
# typedef void (*virConnectDomainEventGraphicsCallback) (
|
232
|
+
# virConnectPtr conn,
|
233
|
+
# virDomainPtr dom,
|
234
|
+
# int phase,
|
235
|
+
# const virDomainEventGraphicsAddress * local,
|
236
|
+
# const virDomainEventGraphicsAddress * remote,
|
237
|
+
# const char * authScheme,
|
238
|
+
# const virDomainEventGraphicsSubject * subject,
|
239
|
+
# void * opaque
|
240
|
+
# )
|
241
|
+
callback :virConnectDomainEventGraphicsCallback, [
|
242
|
+
:pointer,
|
243
|
+
:pointer,
|
244
|
+
:int,
|
245
|
+
# virDomainEventGraphicsAddress
|
246
|
+
# virDomainEventGraphicsAddress
|
247
|
+
:string,
|
248
|
+
# virDomainEventGraphicsSubject
|
249
|
+
:pointer
|
250
|
+
], :void
|
251
|
+
|
252
|
+
# typedef void (*virConnectDomainEventIOErrorReasonCallback) (
|
253
|
+
# virConnectPtr conn,
|
254
|
+
# virDomainPtr dom,
|
255
|
+
# const char * srcPath,
|
256
|
+
# const char * devAlias,
|
257
|
+
# int action,
|
258
|
+
# const char * reason,
|
259
|
+
# void * opaque
|
260
|
+
# )
|
261
|
+
callback :virConnectDomainEventIOErrorReasonCallback, [
|
262
|
+
:pointer,
|
263
|
+
:pointer,
|
264
|
+
:string,
|
265
|
+
:string,
|
266
|
+
:int,
|
267
|
+
:string,
|
268
|
+
:pointer
|
269
|
+
], :void
|
270
|
+
|
271
|
+
# typedef void (*virConnectDomainEventBlockJobCallback) (
|
272
|
+
# virConnectPtr conn,
|
273
|
+
# virDomainPtr dom,
|
274
|
+
# const char * disk,
|
275
|
+
# int type,
|
276
|
+
# int status,
|
277
|
+
# void * opaque
|
278
|
+
# )
|
279
|
+
callback :virConnectDomainEventBlockJobCallback, [
|
280
|
+
:pointer,
|
281
|
+
:pointer,
|
282
|
+
:string,
|
283
|
+
:int,
|
284
|
+
:int,
|
285
|
+
:pointer
|
286
|
+
], :void
|
287
|
+
|
288
|
+
# typedef void (*virConnectDomainEventDiskChangeCallback) (
|
289
|
+
# virConnectPtr conn,
|
290
|
+
# virDomainPtr dom,
|
291
|
+
# const char * oldSrcPath,
|
292
|
+
# const char * newSrcPath,
|
293
|
+
# const char * devAlias,
|
294
|
+
# int reason,
|
295
|
+
# void * opaque
|
296
|
+
# )
|
297
|
+
callback :virConnectDomainEventDiskChangeCallback, [
|
298
|
+
:pointer,
|
299
|
+
:pointer,
|
300
|
+
:string,
|
301
|
+
:string,
|
302
|
+
:string,
|
303
|
+
:int,
|
304
|
+
:pointer
|
305
|
+
], :void
|
306
|
+
|
307
|
+
# typedef void (*virConnectDomainEventTrayChangeCallback) (
|
308
|
+
# virConnectPtr conn,
|
309
|
+
# virDomainPtr dom,
|
310
|
+
# const char * devAlias,
|
311
|
+
# int reason,
|
312
|
+
# void * opaque
|
313
|
+
# )
|
314
|
+
callback :virConnectDomainEventTrayChangeCallback, [
|
315
|
+
:pointer,
|
316
|
+
:pointer,
|
317
|
+
:string,
|
318
|
+
:int,
|
319
|
+
:pointer
|
320
|
+
], :void
|
321
|
+
|
322
|
+
# typedef void (*virConnectDomainEventPMWakeupCallback) (
|
323
|
+
# virConnectPtr conn,
|
324
|
+
# virDomainPtr dom,
|
325
|
+
# int reason,
|
326
|
+
# void * opaque
|
327
|
+
# )
|
328
|
+
callback :virConnectDomainEventPMWakeupCallback, [
|
329
|
+
:pointer,
|
330
|
+
:pointer,
|
331
|
+
:int,
|
332
|
+
:pointer
|
333
|
+
], :void
|
334
|
+
|
335
|
+
# typedef void (*virConnectDomainEventPMSuspendCallback) (
|
336
|
+
# virConnectPtr conn,
|
337
|
+
# virDomainPtr dom,
|
338
|
+
# int reason,
|
339
|
+
# void * opaque
|
340
|
+
# )
|
341
|
+
callback :virConnectDomainEventPMSuspendCallback, [
|
342
|
+
:pointer,
|
343
|
+
:pointer,
|
344
|
+
:int,
|
345
|
+
:pointer
|
346
|
+
], :void
|
347
|
+
|
348
|
+
# typedef void (*virConnectDomainEventBalloonChangeCallback) (
|
349
|
+
# virConnectPtr conn,
|
350
|
+
# virDomainPtr dom,
|
351
|
+
# unsigned long long actual,
|
352
|
+
# void * opaque
|
353
|
+
# )
|
354
|
+
callback :virConnectDomainEventBalloonChangeCallback, [
|
355
|
+
:pointer,
|
356
|
+
:pointer,
|
357
|
+
:ulong_long,
|
358
|
+
:pointer
|
359
|
+
], :void
|
360
|
+
|
361
|
+
# typedef void (*virConnectDomainEventPMSuspendDiskCallback) (
|
362
|
+
# virConnectPtr conn,
|
363
|
+
# virDomainPtr dom,
|
364
|
+
# int reason,
|
365
|
+
# void * opaque
|
366
|
+
# )
|
367
|
+
callback :virConnectDomainEventPMSuspendDiskCallback, [
|
368
|
+
:pointer,
|
369
|
+
:pointer,
|
370
|
+
:int,
|
371
|
+
:pointer
|
372
|
+
], :void
|
373
|
+
|
374
|
+
# typedef void (*virConnectDomainEventDeviceRemovedCallback) (
|
375
|
+
# virConnectPtr conn,
|
376
|
+
# virDomainPtr dom,
|
377
|
+
# const char * devAlias,
|
378
|
+
# void * opaque
|
379
|
+
# )
|
380
|
+
callback :virConnectDomainEventDeviceRemovedCallback, [
|
381
|
+
:pointer,
|
382
|
+
:pointer,
|
383
|
+
:string,
|
384
|
+
:pointer
|
385
|
+
], :void
|
386
|
+
|
387
|
+
# typedef void (*virConnectDomainEventTunableCallback) (
|
388
|
+
# virConnectPtr conn,
|
389
|
+
# virDomainPtr dom,
|
390
|
+
# virTypedParameterPtr params,
|
391
|
+
# int nparams,
|
392
|
+
# void * opaque
|
393
|
+
# )
|
394
|
+
callback :virConnectDomainEventTunableCallback, [
|
395
|
+
:pointer,
|
396
|
+
:pointer,
|
397
|
+
# virTypedParameterPtr
|
398
|
+
:int,
|
399
|
+
:pointer
|
400
|
+
], :void
|
401
|
+
|
402
|
+
# typedef void (*virConnectDomainEventAgentLifecycleCallback) (
|
403
|
+
# virConnectPtr conn,
|
404
|
+
# virDomainPtr dom,
|
405
|
+
# int state,
|
406
|
+
# int reason,
|
407
|
+
# void * opaque
|
408
|
+
# )
|
409
|
+
callback :virConnectDomainEventAgentLifecycleCallback, [
|
410
|
+
:pointer,
|
411
|
+
:pointer,
|
412
|
+
:int,
|
413
|
+
:int,
|
414
|
+
:pointer
|
415
|
+
], :void
|
416
|
+
|
417
|
+
# typedef void (*virConnectDomainEventDeviceAddedCallback) (
|
418
|
+
# virConnectPtr conn,
|
419
|
+
# virDomainPtr dom,
|
420
|
+
# const char * devAlias,
|
421
|
+
# void * opaque
|
422
|
+
# )
|
423
|
+
callback :virConnectDomainEventDeviceAddedCallback, [
|
424
|
+
:pointer,
|
425
|
+
:pointer,
|
426
|
+
:string,
|
427
|
+
:pointer
|
428
|
+
], :void
|
429
|
+
|
430
|
+
# typedef void (*virConnectDomainEventMigrationIterationCallback) (
|
431
|
+
# virConnectPtr conn,
|
432
|
+
# virDomainPtr dom,
|
433
|
+
# int iteration,
|
434
|
+
# void * opaque
|
435
|
+
# )
|
436
|
+
callback :virConnectDomainEventMigrationIterationCallback, [
|
437
|
+
:pointer,
|
438
|
+
:pointer,
|
439
|
+
:int,
|
440
|
+
:pointer
|
441
|
+
], :void
|
442
|
+
|
443
|
+
# typedef void (*virConnectDomainEventJobCompletedCallback) (
|
444
|
+
# virConnectPtr conn,
|
445
|
+
# virDomainPtr dom,
|
446
|
+
# virTypedParameterPtr params,
|
447
|
+
# int nparams,
|
448
|
+
# void * opaque
|
449
|
+
# )
|
450
|
+
callback :virConnectDomainEventJobCompletedCallback, [
|
451
|
+
:pointer,
|
452
|
+
:pointer,
|
453
|
+
# virTypedParameterPtr
|
454
|
+
:int,
|
455
|
+
:pointer
|
456
|
+
], :void
|
457
|
+
|
458
|
+
# typedef void (*virConnectDomainEventDeviceRemovalFailedCallback) (
|
459
|
+
# virConnectPtr conn,
|
460
|
+
# virDomainPtr dom,
|
461
|
+
# const char * devAlias,
|
462
|
+
# void * opaque
|
463
|
+
# )
|
464
|
+
callback :virConnectDomainEventDeviceRemovalFailedCallback, [
|
465
|
+
:pointer,
|
466
|
+
:pointer,
|
467
|
+
:string,
|
468
|
+
:pointer
|
469
|
+
], :void
|
470
|
+
|
471
|
+
# typedef void (*virConnectDomainEventMetadataChangeCallback) (
|
472
|
+
# virConnectPtr conn,
|
473
|
+
# virDomainPtr dom,
|
474
|
+
# int type,
|
475
|
+
# const char * nsuri,
|
476
|
+
# void * opaque
|
477
|
+
# )
|
478
|
+
callback :virConnectDomainEventMetadataChangeCallback, [
|
479
|
+
:pointer,
|
480
|
+
:pointer,
|
481
|
+
:string,
|
482
|
+
:pointer
|
483
|
+
], :void
|
484
|
+
|
485
|
+
# typedef void (*virConnectDomainEventBlockThresholdCallback) (
|
486
|
+
# virConnectPtr conn,
|
487
|
+
# virDomainPtr dom,
|
488
|
+
# const char * dev,
|
489
|
+
# const char * path,
|
490
|
+
# unsigned long long threshold,
|
491
|
+
# unsigned long long excess,
|
492
|
+
# void * opaque
|
493
|
+
# )
|
494
|
+
callback :virConnectDomainEventBlockThresholdCallback, [
|
495
|
+
:pointer,
|
496
|
+
:pointer,
|
497
|
+
:string,
|
498
|
+
:string,
|
499
|
+
:ulong_long,
|
500
|
+
:ulong_long,
|
501
|
+
:pointer
|
502
|
+
], :void
|
503
|
+
|
504
|
+
# @param event_id [Integer]
|
505
|
+
# @yield connect_ptr, domain_ptr, *args, opaque_ptr
|
506
|
+
def self.event_callback(event_id, &block)
|
507
|
+
event_id_sym = enum_type(:event_id)[event_id]
|
508
|
+
callback_name = EVENT_ID_TO_CALLBACK.fetch(event_id_sym)
|
509
|
+
callback_info = find_type(callback_name)
|
510
|
+
::FFI::Function.new(callback_info.result_type, callback_info.param_types) do |*args|
|
511
|
+
Util.log(:debug) { "Libvirt::Domain #{event_id_sym} CALLBACK #{args.map(&:to_s).join(', ')}," }
|
512
|
+
block.call(*args)
|
513
|
+
# Only callback for lifecycle must return 0.
|
514
|
+
# Return value of other callbacks are ignored.
|
515
|
+
# So we just pass zero everywhere.
|
131
516
|
0
|
132
517
|
end
|
133
518
|
end
|
data/lib/libvirt/stream.rb
CHANGED
@@ -12,15 +12,15 @@ module Libvirt
|
|
12
12
|
@opaque = nil
|
13
13
|
|
14
14
|
free = ->(obj_id) do
|
15
|
-
|
16
|
-
if @
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
return unless @stream_ptr
|
16
|
+
if @cb
|
17
|
+
rcb_result = FFI::Stream.virStreamEventRemoveCallback(@stream_ptr)
|
18
|
+
STDERR.puts("Couldn't remove callback Libvirt::Stream (0x#{obj_id.to_s(16)}) pointer #{@stream_ptr.address}") if rcb_result < 0
|
19
|
+
ab_result = FFI::Stream.virStreamAbort(@stream_ptr)
|
20
|
+
STDERR.puts("Couldn't abort Libvirt::Stream (0x#{obj_id.to_s(16)}) pointer #{@stream_ptr.address}") if ab_result < 0
|
21
21
|
end
|
22
|
-
|
23
|
-
|
22
|
+
fr_result = FFI::Stream.virStreamFree(@stream_ptr)
|
23
|
+
STDERR.puts("Couldn't free Libvirt::Stream (0x#{obj_id.to_s(16)}) pointer #{@stream_ptr.address}") if fr_result < 0
|
24
24
|
end
|
25
25
|
ObjectSpace.define_finalizer(self, free)
|
26
26
|
end
|
@@ -77,6 +77,14 @@ module Libvirt
|
|
77
77
|
@opaque = nil
|
78
78
|
end
|
79
79
|
|
80
|
+
def free_stream
|
81
|
+
result = FFI::Stream.virStreamFree(@stream_ptr)
|
82
|
+
raise Error, "Couldn't free stream event callback" if result < 0
|
83
|
+
@cb = nil
|
84
|
+
@opaque = nil
|
85
|
+
@stream_ptr = nil
|
86
|
+
end
|
87
|
+
|
80
88
|
def recv(bytes)
|
81
89
|
buffer = ::FFI::MemoryPointer.new(:char, bytes)
|
82
90
|
result = FFI::Stream.virStreamRecv(@stream_ptr, buffer, bytes)
|
data/lib/libvirt/util.rb
CHANGED
@@ -29,6 +29,20 @@ module Libvirt
|
|
29
29
|
"#{major}.#{minor}.#{release}"
|
30
30
|
end
|
31
31
|
|
32
|
+
# @param enum [FFI::Enum]
|
33
|
+
# @param value [Symbol, Integer]
|
34
|
+
# @return [Array] event_id, event_id_sym
|
35
|
+
# @raise ArgumentError
|
36
|
+
def parse_enum(enum, value)
|
37
|
+
if value.is_a?(Symbol)
|
38
|
+
raise ArgumentError, 'invalid enum value' unless enum.symbols.include?(value)
|
39
|
+
return [enum.find(value), value]
|
40
|
+
end
|
41
|
+
|
42
|
+
raise ArgumentError, 'invalid enum value' unless enum.symbol_map.values.include?(value)
|
43
|
+
[value, enum.symbol_map[value]]
|
44
|
+
end
|
45
|
+
|
32
46
|
end
|
33
47
|
end
|
34
48
|
end
|
data/lib/libvirt/version.rb
CHANGED
@@ -6,16 +6,26 @@ require 'logger'
|
|
6
6
|
require 'active_support/all'
|
7
7
|
require 'async'
|
8
8
|
require 'get_process_mem'
|
9
|
+
require 'gc_tracer'
|
9
10
|
|
10
11
|
require_relative 'support/libvirt_async'
|
11
12
|
require_relative 'support/log_formatter'
|
12
13
|
|
14
|
+
GC::Tracer.start_logging(
|
15
|
+
nil,
|
16
|
+
gc_stat: false,
|
17
|
+
gc_latest_gc_info: false,
|
18
|
+
rusage: false,
|
19
|
+
events: %i[end_mark end_sweep]
|
20
|
+
)
|
21
|
+
|
13
22
|
Libvirt.logger = Logger.new(STDOUT, formatter: LogFormatter.new)
|
14
23
|
Libvirt.logger.level = ENV['DEBUG'] ? :debug : :info
|
15
24
|
|
16
25
|
IMPL = LibvirtAsync::Implementations.new
|
17
26
|
CONNS = []
|
18
27
|
DOMS = []
|
28
|
+
CB_IDS = []
|
19
29
|
|
20
30
|
Async do
|
21
31
|
ASYNC_REACTOR = Async::Task.current.reactor
|
@@ -47,9 +57,13 @@ Async do
|
|
47
57
|
puts "NodeInfo threads #{node_info.threads.inspect}"
|
48
58
|
puts "NodeInfo memory #{node_info.memory.inspect}"
|
49
59
|
|
50
|
-
|
51
|
-
|
60
|
+
cb_ids = Libvirt::Connection::DOMAIN_EVENT_IDS.map do |event_id|
|
61
|
+
op = OpenStruct.new(a: 'b', event_id: event_id)
|
62
|
+
c.register_domain_event_callback(event_id, nil, op) do |conn, dom, *args, opaque|
|
63
|
+
Libvirt.logger.info { "DOMAIN EVENT #{event_id} conn=#{conn}, dom=#{dom}, args=#{args}, opaque=#{opaque}" }
|
64
|
+
end
|
52
65
|
end
|
66
|
+
CB_IDS.concat(cb_ids)
|
53
67
|
|
54
68
|
puts "domains qty #{c.list_all_domains_qty}"
|
55
69
|
|
@@ -57,12 +71,6 @@ Async do
|
|
57
71
|
DOMS.concat(domains)
|
58
72
|
puts "Domains (#{domains.size}): #{domains}"
|
59
73
|
|
60
|
-
domains.each_with_index do |domain, index|
|
61
|
-
c.register_domain_event_callback(Libvirt::DOMAIN_EVENT_ID_LIFECYCLE, domain) do |dom, event, detail, opaque|
|
62
|
-
Libvirt.logger.info { "DOMAIN_EVENT_CALLBACK LIFECYCLE user##{index} dom=#{dom}, event=#{event}, detail=#{detail}, opaque=#{opaque}" }
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
74
|
d = domains.first
|
67
75
|
puts "Domain uuid #{d.uuid.inspect}"
|
68
76
|
puts "Domain name #{d.name.inspect}"
|
@@ -75,10 +83,27 @@ Async do
|
|
75
83
|
# LibvirtAsync::Util.create_task(nil, ASYNC_REACTOR) { IMPL.print_debug_info }.run
|
76
84
|
# end
|
77
85
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
86
|
+
ASYNC_REACTOR.every(5) do
|
87
|
+
Libvirt.logger.info { "MEM USAGE: #{GetProcessMem.new.mb} MB" }
|
88
|
+
# Libvirt.logger.info { "GC.start" }
|
89
|
+
# GC.start
|
90
|
+
# Libvirt.logger.info { "MEM USAGE: #{GetProcessMem.new.mb} MB" }
|
91
|
+
end
|
92
|
+
|
93
|
+
ASYNC_REACTOR.after(20) do
|
94
|
+
LibvirtAsync::Util.create_task(nil, ASYNC_REACTOR) do
|
95
|
+
|
96
|
+
c = CONNS.first
|
97
|
+
CB_IDS.each do |callback_id|
|
98
|
+
opaque = c.deregister_domain_event_callback(callback_id)
|
99
|
+
puts "Retrieved opaque #{opaque}"
|
100
|
+
end
|
101
|
+
Libvirt.logger.info { 'Cleaning up!' }
|
102
|
+
CONNS = []
|
103
|
+
DOMS = []
|
104
|
+
CB_IDS = []
|
105
|
+
GC.start
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
84
109
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: libvirt_ffi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Talakevich
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -45,6 +45,7 @@ files:
|
|
45
45
|
- lib/libvirt.rb
|
46
46
|
- lib/libvirt/connection.rb
|
47
47
|
- lib/libvirt/domain.rb
|
48
|
+
- lib/libvirt/domain_callback_storage.rb
|
48
49
|
- lib/libvirt/error.rb
|
49
50
|
- lib/libvirt/event.rb
|
50
51
|
- lib/libvirt/ffi/common.rb
|