libvirt_ffi 0.5.6 → 0.8.0

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