libvirt_ffi 0.5.6 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc49a5a9986110313860c3dd0390c7485e598b4407a52d35009381c1255ca9c5
4
- data.tar.gz: 6ebd4be029bba4e8a50dc0efc996d91e357e8d7616b1f64f66dde66503dcfc21
3
+ metadata.gz: 5f84407d986359b92b8ad0eaf854f85d098e93835d218a69a9a346f864176c9d
4
+ data.tar.gz: c339098e1c00e91f229f814eb399e1ba1980673428d1bf78c565a79080d5456e
5
5
  SHA512:
6
- metadata.gz: 0d9716eca3d06aa6d0e3479e50c1bb93142968a9b34ad3df59a35a53dfab5b651f59d49e096a89362275700b2cdfd72f6b9832c6bbd187645fb3d236e6478afe
7
- data.tar.gz: cac12813a17c8ef4a6bd41ebbed45437d3c3908254866435bcb3bdeb17b457e65c6107c72b4fdd9b553699af2ee8608d2a6a56b6d4bc10ac0437d932e1acd15d
6
+ metadata.gz: ef9bf3632b42bc37324dbd9cc382b908f6320cdb7a8c16c91bd05a2b5c4f402d2fb675079c3ab0fce9157ad4557caa4b5bd37044841b1ce558c7d2eaf9901502
7
+ data.tar.gz: 504c1ac8e2c3df785f8754e2abc3bc5643dc7c5c553a8f10793f9e14ea40da9c07961fb510b6a4ae701f2d9df66f689acec0cf09d593a7d23d663e52703b5309
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'ffi'
4
4
  require 'objspace'
5
- require 'libvirt/domain_callback_storage'
5
+ require 'libvirt/host_callback_storage'
6
6
  require 'libvirt/util'
7
7
  require 'libvirt/errors'
8
8
  require 'libvirt/ffi'
@@ -16,6 +16,8 @@ require 'libvirt/domain'
16
16
  require 'libvirt/stream'
17
17
  require 'libvirt/storage_pool'
18
18
  require 'libvirt/storage_volume'
19
+ require 'libvirt/network'
20
+ require 'libvirt/interface'
19
21
  require 'libvirt/version'
20
22
 
21
23
  module Libvirt
@@ -16,6 +16,7 @@ module Libvirt
16
16
  end
17
17
  end
18
18
 
19
+ # @param pointer [FFI::Pointer]
19
20
  def initialize(pointer)
20
21
  raise ArgumentError, "Can't initialize base class #{self.class}" if self.class == BaseInfo
21
22
 
@@ -23,12 +24,19 @@ module Libvirt
23
24
  @struct = self.class._struct_class.new(pointer)
24
25
  end
25
26
 
27
+ # @param attr [Symbol]
28
+ # @return [Object, nil]
26
29
  def [](attr)
27
30
  @struct[attr]
28
31
  end
29
32
 
33
+ # @return [Hash]
30
34
  def to_h
31
35
  @struct.members.map { |attr| [attr, @struct[attr]] }.to_h
32
36
  end
37
+
38
+ def to_ptr
39
+ @struct.to_ptr
40
+ end
33
41
  end
34
42
  end
@@ -3,19 +3,60 @@
3
3
  module Libvirt
4
4
  class Connection
5
5
  DOMAIN_EVENT_IDS = FFI::Domain.enum_type(:event_id).symbols.dup.freeze
6
+ POOL_EVENT_IDS = FFI::Storage.enum_type(:event_id).symbols.dup.freeze
7
+ NETWORK_EVENT_IDS = FFI::Network.enum_type(:event_id).symbols.dup.freeze
6
8
 
7
- STORAGE = DomainCallbackStorage.new
9
+ DOMAIN_STORAGE = HostCallbackStorage.new(:domain_event)
10
+ POOL_STORAGE = HostCallbackStorage.new(:storage_pool_event)
11
+ NETWORK_STORAGE = HostCallbackStorage.new(:network_event)
12
+ CLOSE_STORAGE = HostCallbackStorage.new(:close)
8
13
 
9
14
  DOMAIN_EVENT_CALLBACKS = DOMAIN_EVENT_IDS.map do |event_id_sym|
10
15
  func = FFI::Domain.event_callback_for(event_id_sym) do |conn_ptr, dom_ptr, *args, op_ptr|
16
+ Util.log(:debug, "DOMAIN_EVENT_CALLBACKS[#{event_id_sym}]") do
17
+ "inside callback conn_ptr=#{conn_ptr}, pool_ptr=#{dom_ptr}, args=#{args}, op_ptr=#{op_ptr}"
18
+ end
11
19
  connection = Connection.load_ref(conn_ptr)
12
20
  domain = Domain.load_ref(dom_ptr)
13
- block, opaque = STORAGE.retrieve_from_pointer(op_ptr)
21
+ block, opaque = DOMAIN_STORAGE.retrieve_from_pointer(op_ptr)
14
22
  block.call(connection, domain, *args, opaque)
15
23
  end
16
24
  [event_id_sym, func]
17
25
  end.to_h.freeze
18
26
 
27
+ POOL_EVENT_CALLBACKS = POOL_EVENT_IDS.map do |event_id_sym|
28
+ func = FFI::Storage.event_callback_for(event_id_sym) do |conn_ptr, pool_ptr, *args, op_ptr|
29
+ Util.log(:debug, "POOL_EVENT_CALLBACKS[#{event_id_sym}]") do
30
+ "inside callback conn_ptr=#{conn_ptr}, pool_ptr=#{pool_ptr}, args=#{args}, op_ptr=#{op_ptr}"
31
+ end
32
+ connection = Connection.load_ref(conn_ptr)
33
+ pool = StoragePool.load_ref(pool_ptr)
34
+ block, opaque = POOL_STORAGE.retrieve_from_pointer(op_ptr)
35
+ block.call(connection, pool, *args, opaque)
36
+ end
37
+ [event_id_sym, func]
38
+ end.to_h.freeze
39
+
40
+ NETWORK_EVENT_CALLBACKS = NETWORK_EVENT_IDS.map do |event_id_sym|
41
+ func = FFI::Network.event_callback_for(event_id_sym) do |conn_ptr, pool_ptr, *args, op_ptr|
42
+ Util.log(:debug, "NETWORK_EVENT_CALLBACKS[#{event_id_sym}]") do
43
+ "inside callback conn_ptr=#{conn_ptr}, pool_ptr=#{pool_ptr}, args=#{args}, op_ptr=#{op_ptr}"
44
+ end
45
+ connection = Connection.load_ref(conn_ptr)
46
+ pool = Network.load_ref(pool_ptr)
47
+ block, opaque = NETWORK_STORAGE.retrieve_from_pointer(op_ptr)
48
+ block.call(connection, pool, *args, opaque)
49
+ end
50
+ [event_id_sym, func]
51
+ end.to_h.freeze
52
+
53
+ CLOSE_CALLBACK = FFI::Host.callback_function(:virConnectCloseFunc) do |conn_ptr, reason, op_ptr|
54
+ Util.log(:debug, 'CLOSE_CALLBACK') { "inside callback conn_ptr=#{conn_ptr}, reason=#{reason}, op_ptr=#{op_ptr}" }
55
+ connection = Connection.load_ref(conn_ptr)
56
+ block, opaque = CLOSE_STORAGE.retrieve_from_pointer(op_ptr)
57
+ block.call(connection, reason, opaque)
58
+ end
59
+
19
60
  def self.load_ref(conn_ptr)
20
61
  ref_result = FFI::Host.virConnectRef(conn_ptr)
21
62
  raise Errors::LibError, "Couldn't retrieve connection reference" if ref_result.negative?
@@ -134,25 +175,95 @@ module Libvirt
134
175
  ptr.get_array_of_pointer(0, size).map { |stp_ptr| StoragePool.new(stp_ptr) }
135
176
  end
136
177
 
178
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
179
+ # @return [Integer]
180
+ # @raise [Libvirt::Errors::LibError]
181
+ def list_all_networks_qty(options_or_flags = nil)
182
+ flags = Util.parse_flags options_or_flags, FFI::Network.enum_type(:list_all_flags)
183
+ result = FFI::Network.virConnectListAllNetworks(@conn_ptr, nil, flags)
184
+ raise Errors::LibError, "Couldn't retrieve networks qty with flags #{flags.to_s(16)}" if result.negative?
185
+
186
+ result
187
+ end
188
+
189
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
190
+ # @return [Array<Libvirt::Network>, Array]
191
+ # @raise [Libvirt::Errors::LibError]
192
+ def list_all_networks(options_or_flags = nil)
193
+ flags = Util.parse_flags options_or_flags, FFI::Network.enum_type(:list_all_flags)
194
+ size = list_all_networks_qty(flags)
195
+ return [] if size.zero?
196
+
197
+ networks_ptr = ::FFI::MemoryPointer.new(:pointer, size)
198
+ result = FFI::Network.virConnectListAllNetworks(@conn_ptr, networks_ptr, 0)
199
+ raise Errors::LibError, "Couldn't retrieve networks list" if result.negative?
200
+
201
+ ptr = networks_ptr.read_pointer
202
+ ptr.get_array_of_pointer(0, size).map { |n_ptr| Network.new(n_ptr) }
203
+ end
204
+
205
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
206
+ # @return [Integer]
207
+ # @raise [Libvirt::Errors::LibError]
208
+ def list_all_interfaces_qty(options_or_flags = nil)
209
+ flags = Util.parse_flags options_or_flags, FFI::Interface.enum_type(:list_all_flags)
210
+ result = FFI::Interface.virConnectListAllInterfaces(@conn_ptr, nil, flags)
211
+ raise Errors::LibError, "Couldn't retrieve interfaces qty with flags #{flags.to_s(16)}" if result.negative?
212
+
213
+ result
214
+ end
215
+
216
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
217
+ # @return [Array<Libvirt::Interface>, Array]
218
+ # @raise [Libvirt::Errors::LibError]
219
+ def list_all_interfaces(options_or_flags = nil)
220
+ flags = Util.parse_flags options_or_flags, FFI::Interface.enum_type(:list_all_flags)
221
+ size = list_all_interfaces_qty(flags)
222
+ return [] if size.zero?
223
+
224
+ interfaces_ptr = ::FFI::MemoryPointer.new(:pointer, size)
225
+ result = FFI::Interface.virConnectListAllInterfaces(@conn_ptr, interfaces_ptr, 0)
226
+ raise Errors::LibError, "Couldn't retrieve interfaces list" if result.negative?
227
+
228
+ ptr = interfaces_ptr.read_pointer
229
+ ptr.get_array_of_pointer(0, size).map { |i_ptr| Interface.new(i_ptr) }
230
+ end
231
+
137
232
  def register_close_callback(opaque = nil, &block)
138
233
  dbg { "#register_close_callback opaque=#{opaque}" }
139
- raise ArgumentError, 'close function already registered' if @close_data
140
-
141
- @close_data = { opaque: opaque, block: block }
142
- @close_cb = FFI::Host.callback_function(:virConnectCloseFunc) do |_conn, reason, _op|
143
- dbg { "CONNECTION CLOSED @conn_ptr=#{@conn_ptr} reason=#{reason}" }
144
- block = @close_data[:block]
145
- opaque = @close_data[:opaque]
146
- # we clear @closed_data here, because connection can be opened again and
147
- # add new close callback inside `block`.
148
- @close_data = nil
149
- block.call(self, reason, opaque)
150
- end
151
- @close_free_func = FFI::Common.free_function do
152
- dbg { "CONNECTION CLOSED FREE FUNC @conn_ptr=#{@conn_ptr}" }
153
- @close_cb = @close_free_func = @close_data = nil
234
+
235
+ cb_data, cb_data_free_func = CLOSE_STORAGE.allocate_struct
236
+ result = FFI::Host.virConnectRegisterCloseCallback(
237
+ @conn_ptr,
238
+ CLOSE_CALLBACK,
239
+ cb_data.pointer,
240
+ cb_data_free_func
241
+ )
242
+ if result.negative?
243
+ cb_data.pointer.free
244
+ raise Errors::LibError, "Couldn't register connection close callback"
154
245
  end
155
- FFI::Host.virConnectRegisterCloseCallback(@conn_ptr, @close_cb, nil, @close_free_func)
246
+
247
+ CLOSE_STORAGE.store_struct(
248
+ cb_data,
249
+ connection_pointer: @conn_ptr,
250
+ callback_id: result,
251
+ cb: block,
252
+ opaque: opaque,
253
+ free_func: cb_data_free_func
254
+ )
255
+ result
256
+ end
257
+
258
+ def deregister_close_callback
259
+ dbg { '#deregister_close_callback' }
260
+
261
+ result = FFI::Host.virConnectUnregisterCloseCallback(@conn_ptr, CLOSE_CALLBACK)
262
+ raise Errors::LibError, "Couldn't deregister close callback" if result.negative?
263
+
264
+ # virConnectUnregisterCloseCallback will call free func
265
+ # So we don't need to remove object from CLOSE_STORAGE here.
266
+ true
156
267
  end
157
268
 
158
269
  # @yield conn, dom, *args
@@ -163,7 +274,7 @@ module Libvirt
163
274
  event_id, event_id_sym = Util.parse_enum(enum, event_id)
164
275
  cb = DOMAIN_EVENT_CALLBACKS.fetch(event_id_sym)
165
276
 
166
- cb_data, cb_data_free_func = STORAGE.allocate_struct
277
+ cb_data, cb_data_free_func = DOMAIN_STORAGE.allocate_struct
167
278
 
168
279
  result = FFI::Domain.virConnectDomainEventRegisterAny(
169
280
  @conn_ptr,
@@ -178,12 +289,13 @@ module Libvirt
178
289
  raise Errors::LibError, "Couldn't register domain event callback"
179
290
  end
180
291
 
181
- STORAGE.store_struct(
292
+ DOMAIN_STORAGE.store_struct(
182
293
  cb_data,
183
294
  connection_pointer: @conn_ptr,
184
295
  callback_id: result,
185
296
  cb: block,
186
- opaque: opaque
297
+ opaque: opaque,
298
+ free_func: cb_data_free_func
187
299
  )
188
300
  result
189
301
  end
@@ -195,7 +307,95 @@ module Libvirt
195
307
  raise Errors::LibError, "Couldn't deregister domain event callback" if result.negative?
196
308
 
197
309
  # virConnectDomainEventDeregisterAny will call free func
198
- # So we don't need to remove object from STORAGE here.
310
+ # So we don't need to remove object from DOMAIN_STORAGE here.
311
+ true
312
+ end
313
+
314
+ def register_storage_pool_event_callback(event_id, storage_pool = nil, opaque = nil, &block)
315
+ dbg { "#register_storage_pool_event_callback event_id=#{event_id}" }
316
+
317
+ enum = FFI::Storage.enum_type(:event_id)
318
+ event_id, event_id_sym = Util.parse_enum(enum, event_id)
319
+ cb = POOL_EVENT_CALLBACKS.fetch(event_id_sym)
320
+
321
+ cb_data, cb_data_free_func = POOL_STORAGE.allocate_struct
322
+
323
+ result = FFI::Storage.virConnectStoragePoolEventRegisterAny(
324
+ @conn_ptr,
325
+ storage_pool&.to_ptr,
326
+ event_id,
327
+ cb,
328
+ cb_data.pointer,
329
+ cb_data_free_func
330
+ )
331
+ if result.negative?
332
+ cb_data.pointer.free
333
+ raise Errors::LibError, "Couldn't register storage pool event callback"
334
+ end
335
+
336
+ POOL_STORAGE.store_struct(
337
+ cb_data,
338
+ connection_pointer: @conn_ptr,
339
+ callback_id: result,
340
+ cb: block,
341
+ opaque: opaque,
342
+ free_func: cb_data_free_func
343
+ )
344
+ result
345
+ end
346
+
347
+ def deregister_storage_pool_event_callback(callback_id)
348
+ dbg { "#deregister_storage_pool_event_callback callback_id=#{callback_id}" }
349
+
350
+ result = FFI::Storage.virConnectStoragePoolEventDeregisterAny(@conn_ptr, callback_id)
351
+ raise Errors::LibError, "Couldn't deregister storage pool event callback" if result.negative?
352
+
353
+ # virConnectStoragePoolEventDeregisterAny will call free func
354
+ # So we don't need to remove object from POOL_STORAGE here.
355
+ true
356
+ end
357
+
358
+ def register_network_event_callback(event_id, network = nil, opaque = nil, &block)
359
+ dbg { "#register_network_event_callback event_id=#{event_id}" }
360
+
361
+ enum = FFI::Network.enum_type(:event_id)
362
+ event_id, event_id_sym = Util.parse_enum(enum, event_id)
363
+ cb = NETWORK_EVENT_CALLBACKS.fetch(event_id_sym)
364
+
365
+ cb_data, cb_data_free_func = NETWORK_STORAGE.allocate_struct
366
+
367
+ result = FFI::Network.virConnectNetworkEventRegisterAny(
368
+ @conn_ptr,
369
+ network&.to_ptr,
370
+ event_id,
371
+ cb,
372
+ cb_data.pointer,
373
+ cb_data_free_func
374
+ )
375
+ if result.negative?
376
+ cb_data.pointer.free
377
+ raise Errors::LibError, "Couldn't register network event callback"
378
+ end
379
+
380
+ NETWORK_STORAGE.store_struct(
381
+ cb_data,
382
+ connection_pointer: @conn_ptr,
383
+ callback_id: result,
384
+ cb: block,
385
+ opaque: opaque,
386
+ free_func: cb_data_free_func
387
+ )
388
+ result
389
+ end
390
+
391
+ def deregister_network_event_callback(callback_id)
392
+ dbg { "#deregister_network_event_callback callback_id=#{callback_id}" }
393
+
394
+ result = FFI::Network.virConnectNetworkEventDeregisterAny(@conn_ptr, callback_id)
395
+ raise Errors::LibError, "Couldn't deregister network event callback" if result.negative?
396
+
397
+ # virConnectNetworkEventDeregisterAny will call free func
398
+ # So we don't need to remove object from NETWORK_STORAGE here.
199
399
  true
200
400
  end
201
401
 
@@ -244,6 +444,51 @@ module Libvirt
244
444
  Domain.new(pointer)
245
445
  end
246
446
 
447
+ # @param xml [String]
448
+ # @raise [Libvirt::Errors::LibError]
449
+ def create_network(xml)
450
+ pointer = FFI::Network.virNetworkCreateXML(@ptr, xml)
451
+ raise Errors::LibError, "Couldn't create network with xml" if pointer.null?
452
+
453
+ Network.new(pointer)
454
+ end
455
+
456
+ # @param xml [String]
457
+ # @raise [Libvirt::Errors::LibError]
458
+ def define_network(xml)
459
+ pointer = FFI::Network.virNetworkDefineXML(@ptr, xml)
460
+ raise Errors::LibError, "Couldn't define network with xml" if pointer.null?
461
+
462
+ Network.new(pointer)
463
+ end
464
+
465
+ # @param xml [String]
466
+ # @raise [Libvirt::Errors::LibError]
467
+ def define_interface(xml)
468
+ pointer = FFI::Interface.virInterfaceDefineXML(@conn_ptr, xml, 0)
469
+ raise Errors::LibError, "Couldn't define interface with xml" if pointer.null?
470
+
471
+ Interface.new(pointer)
472
+ end
473
+
474
+ # @raise [Libvirt::Errors::LibError]
475
+ def begin_interface_change
476
+ result = FFI::Interface.virInterfaceChangeBegin(@conn_ptr, 0)
477
+ raise Errors::LibError, "Couldn't begin interface change" if result.negative?
478
+ end
479
+
480
+ # @raise [Libvirt::Errors::LibError]
481
+ def commit_interface_change
482
+ result = FFI::Interface.virInterfaceChangeCommit(@conn_ptr, 0)
483
+ raise Errors::LibError, "Couldn't commit interface change" if result.negative?
484
+ end
485
+
486
+ # @raise [Libvirt::Errors::LibError]
487
+ def rollback_interface_change
488
+ result = FFI::Interface.virInterfaceChangeRollback(@conn_ptr, 0)
489
+ raise Errors::LibError, "Couldn't rollback interface change" if result.negative?
490
+ end
491
+
247
492
  private
248
493
 
249
494
  def set_connection(conn_ptr)
@@ -38,7 +38,7 @@ module Libvirt
38
38
  end
39
39
 
40
40
  def uuid
41
- buff = ::FFI::MemoryPointer.new(:char, FFI::Domain::UUID_STRING_BUFLEN)
41
+ buff = ::FFI::MemoryPointer.new(:char, Util::UUID_STRING_BUFLEN)
42
42
  result = FFI::Domain.virDomainGetUUIDString(@dom_ptr, buff)
43
43
  raise Errors::LibError, "Couldn't get domain uuid" if result.negative?
44
44
 
@@ -46,13 +46,34 @@ module Libvirt
46
46
  end
47
47
 
48
48
  def name
49
- FFI::Domain.virDomainGetName(@dom_ptr)
49
+ result = FFI::Domain.virDomainGetName(@dom_ptr)
50
+ raise Errors::LibError, "Couldn't retrieve storage pool name" if result.nil?
51
+
52
+ result
50
53
  end
51
54
 
52
55
  def max_vcpus
53
56
  FFI::Domain.virDomainGetMaxVcpus(@dom_ptr)
54
57
  end
55
58
 
59
+ # @return [Boolean]
60
+ # @raise [Libvirt::Errors::LibError]
61
+ def auto_start
62
+ value = ::FFI::MemoryPointer.new(:int)
63
+ result = FFI::Domain.virDomainGetAutostart(@dom_ptr, value)
64
+ raise Errors::LibError, "Couldn't get domain auto_start" if result.negative?
65
+
66
+ value.read_int == 1
67
+ end
68
+
69
+ # @param value [Boolean]
70
+ # @raise [Libvirt::Errors::LibError]
71
+ def set_auto_start(value)
72
+ value = value ? 1 : 0
73
+ result = FFI::Domain.virDomainSetAutostart(@dom_ptr, value)
74
+ raise Errors::LibError, "Couldn't set domain auto_start" if result.negative?
75
+ end
76
+
56
77
  # def vcpus
57
78
  # # https://github.com/libvirt/ruby-libvirt/blob/9f71ff5add1f57ffef7cf513b72638d92d9fd84f/ext/libvirt/domain.c#L787
58
79
  # # dominfo = virDomainGetInfo
@@ -13,5 +13,7 @@ module Libvirt
13
13
  require 'libvirt/ffi/event'
14
14
  require 'libvirt/ffi/stream'
15
15
  require 'libvirt/ffi/storage'
16
+ require 'libvirt/ffi/network'
17
+ require 'libvirt/ffi/interface'
16
18
  end
17
19
  end