libvirt_ffi 0.6.1 → 0.8.1

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: 43c4cf7b7fa510b96605a9f05e8f04680280459d48572085740a71f145ce1442
4
- data.tar.gz: a3ca5f72fdeb7de0cc95b440f58c5b894970add2cb746c12e3191d12269dcc42
3
+ metadata.gz: d81d03c71f0077138bdc7369c7468138333eb45ae1de85c857089b263975e8c4
4
+ data.tar.gz: cdae17b6ecb8174ee12247d31d4419a9bf367ba17a460c6f9e3e5cc347d313ca
5
5
  SHA512:
6
- metadata.gz: f1b7448f8ebd67349c59a365d1b30072bf99d5f78ffc1b07c87f99a312365f4d42474e62886c71e797fd0deab4c6f726af6440d6c4bb350fb8a65ee751b68ed5
7
- data.tar.gz: 24056f945020275a102517bd6f4fba560be15c0f4fea7725b9c4b9b6032a1e94695b1520094c4027bf4ea0e34291e00148efefbb60d114640980e6c69e9f6cae
6
+ metadata.gz: 4f2a8d886ed935f536bd5e04fd9e710d953d0f7f78a8e408220018784291ac3ba71f2e342dcaedbe44b3b57c2e1c77cd36784a05f9d6a0b486ddc6b1dfeb1bd3
7
+ data.tar.gz: 3df70b41610251d35c2986ba77fd617ee15cb956dc690f850b4650ac34ef4fee80072987d83b1cefcf806501fd87e6401def2c2d2d120e5d8db1b09136d21742
@@ -0,0 +1,26 @@
1
+ name: Tests
2
+ on:
3
+ pull_request:
4
+ push:
5
+ branches:
6
+ - master
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ ruby: [ '2.6', '2.7', '3.0' ]
14
+ name: Tests with Ruby ${{ matrix.ruby }}
15
+ steps:
16
+ - name: Install libvirt
17
+ run: sudo apt-get install -y libvirt-dev libvirt0
18
+ - uses: actions/checkout@v2
19
+ - uses: actions/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ - name: Run tests
23
+ run: |
24
+ gem install bundler
25
+ bundle install
26
+ bundle exec rake
data/.gitignore CHANGED
@@ -6,5 +6,6 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
-
10
9
  /Gemfile.lock
10
+ .rspec_local
11
+ /spec/last_run.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml CHANGED
@@ -5,7 +5,7 @@ AllCops:
5
5
  - vendor/**/*
6
6
  - tmp/**/*
7
7
  - pkg/*
8
- - test_usage/**/*.rb
8
+ - examples/**/*.rb
9
9
 
10
10
  Layout/LineLength:
11
11
  Max: 180
data/Gemfile CHANGED
@@ -5,14 +5,11 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in libvirt.gemspec
6
6
  gemspec
7
7
 
8
- gem 'minitest', '~> 5.0'
9
- gem 'rake', '~> 12.0'
10
-
8
+ gem 'activesupport'
9
+ gem 'async', '~> 1.24'
10
+ gem 'gc_tracer'
11
+ gem 'get_process_mem'
11
12
  gem 'nokogiri'
12
-
13
- group :development do
14
- gem 'activesupport'
15
- gem 'async', '~> 1.24'
16
- gem 'gc_tracer'
17
- gem 'get_process_mem'
18
- end
13
+ gem 'rake', '~> 12.0'
14
+ gem 'rspec', '~> 3.9'
15
+ gem 'rubocop', '~> 0.80.1'
data/README.md CHANGED
@@ -32,7 +32,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
32
 
33
33
  ## Contributing
34
34
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/libvirt. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/libvirt/blob/master/CODE_OF_CONDUCT.md).
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/senid231/libvirt. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/senid231/libvirt/blob/master/CODE_OF_CONDUCT.md).
36
36
 
37
37
 
38
38
  ## License
@@ -41,4 +41,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
41
41
 
42
42
  ## Code of Conduct
43
43
 
44
- Everyone interacting in the Libvirt project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/libvirt/blob/master/CODE_OF_CONDUCT.md).
44
+ Everyone interacting in the Libvirt project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/senid231/libvirt/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,15 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/gem_tasks'
4
- require 'rake/testtask'
4
+ require 'rspec/core/rake_task'
5
5
  require 'rubocop/rake_task'
6
6
 
7
- Rake::TestTask.new(:test) do |t|
8
- t.libs << 'test'
9
- t.libs << 'lib'
10
- t.test_files = FileList['test/**/*_test.rb']
11
- end
12
-
7
+ RSpec::Core::RakeTask.new(:spec)
13
8
  RuboCop::RakeTask.new(:rubocop)
14
9
 
15
- task default: [:rubocop, :test]
10
+ task default: [:rubocop, :spec]
@@ -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
@@ -2,11 +2,15 @@
2
2
 
3
3
  module Libvirt
4
4
  class Connection
5
+ include Loggable
6
+
5
7
  DOMAIN_EVENT_IDS = FFI::Domain.enum_type(:event_id).symbols.dup.freeze
6
8
  POOL_EVENT_IDS = FFI::Storage.enum_type(:event_id).symbols.dup.freeze
9
+ NETWORK_EVENT_IDS = FFI::Network.enum_type(:event_id).symbols.dup.freeze
7
10
 
8
11
  DOMAIN_STORAGE = HostCallbackStorage.new(:domain_event)
9
12
  POOL_STORAGE = HostCallbackStorage.new(:storage_pool_event)
13
+ NETWORK_STORAGE = HostCallbackStorage.new(:network_event)
10
14
  CLOSE_STORAGE = HostCallbackStorage.new(:close)
11
15
 
12
16
  DOMAIN_EVENT_CALLBACKS = DOMAIN_EVENT_IDS.map do |event_id_sym|
@@ -35,6 +39,19 @@ module Libvirt
35
39
  [event_id_sym, func]
36
40
  end.to_h.freeze
37
41
 
42
+ NETWORK_EVENT_CALLBACKS = NETWORK_EVENT_IDS.map do |event_id_sym|
43
+ func = FFI::Network.event_callback_for(event_id_sym) do |conn_ptr, pool_ptr, *args, op_ptr|
44
+ Util.log(:debug, "NETWORK_EVENT_CALLBACKS[#{event_id_sym}]") do
45
+ "inside callback conn_ptr=#{conn_ptr}, pool_ptr=#{pool_ptr}, args=#{args}, op_ptr=#{op_ptr}"
46
+ end
47
+ connection = Connection.load_ref(conn_ptr)
48
+ pool = Network.load_ref(pool_ptr)
49
+ block, opaque = NETWORK_STORAGE.retrieve_from_pointer(op_ptr)
50
+ block.call(connection, pool, *args, opaque)
51
+ end
52
+ [event_id_sym, func]
53
+ end.to_h.freeze
54
+
38
55
  CLOSE_CALLBACK = FFI::Host.callback_function(:virConnectCloseFunc) do |conn_ptr, reason, op_ptr|
39
56
  Util.log(:debug, 'CLOSE_CALLBACK') { "inside callback conn_ptr=#{conn_ptr}, reason=#{reason}, op_ptr=#{op_ptr}" }
40
57
  connection = Connection.load_ref(conn_ptr)
@@ -42,56 +59,68 @@ module Libvirt
42
59
  block.call(connection, reason, opaque)
43
60
  end
44
61
 
45
- def self.load_ref(conn_ptr)
46
- ref_result = FFI::Host.virConnectRef(conn_ptr)
47
- raise Errors::LibError, "Couldn't retrieve connection reference" if ref_result.negative?
62
+ def self.load_ref(ptr)
63
+ result = FFI::Host.virConnectRef(ptr)
64
+ raise Errors::LibError, "Couldn't retrieve connection reference" if result.negative?
48
65
 
49
- new(nil).tap { |r| r.send(:set_connection, conn_ptr) }
66
+ uri = FFI::Host.virConnectGetURI(ptr)
67
+ new(uri).tap { |c| c.instance_variable_set(:@ptr, ptr) }
50
68
  end
51
69
 
70
+ attr_reader :uri
71
+
52
72
  def initialize(uri)
53
73
  @uri = uri
54
- @conn_ptr = ::FFI::Pointer.new(0)
74
+ @ptr = ::FFI::Pointer.new(0)
55
75
  @close_data = nil
56
76
 
57
- free = ->(obj_id) do
58
- Util.log(:debug) { "Finalize Libvirt::Connection 0x#{obj_id.to_s(16)} @conn_ptr=#{@conn_ptr}," }
59
- return if @conn_ptr.null?
77
+ Util.define_finalizer(self) { |pointer| FFI::Host.virConnectClose(pointer) }
78
+ end
60
79
 
61
- cl_result = FFI::Host.virConnectClose(@conn_ptr)
62
- warn "Couldn't close Libvirt::Connection (0x#{obj_id.to_s(16)}) pointer #{@conn_ptr.address}" if cl_result.negative?
63
- end
64
- ObjectSpace.define_finalizer(self, free)
80
+ def to_s
81
+ "#<#{self.class}:0x#{object_id.to_s(16)} @uri=#{@uri.inspect} @ptr=0x#{@ptr.address.to_s(16)}>"
82
+ end
83
+
84
+ def inspect
85
+ to_s
86
+ end
87
+
88
+ def to_ptr
89
+ @ptr
65
90
  end
66
91
 
67
92
  def open
68
- @conn_ptr = FFI::Host.virConnectOpen(@uri)
69
- raise Errors::LibError, "Couldn't open connection to #{@uri.inspect}" if @conn_ptr.null?
93
+ @ptr = FFI::Host.virConnectOpen(@uri)
94
+ raise Errors::LibError, "Couldn't open connection to #{@uri.inspect}" if @ptr.null?
95
+
96
+ dbg { 'opened' }
70
97
 
71
98
  true
72
99
  end
73
100
 
74
101
  def close
75
- result = FFI::Host.virConnectClose(@conn_ptr)
102
+ result = FFI::Host.virConnectClose(@ptr)
76
103
  raise Errors::LibError, "Couldn't close connection to #{@uri.inspect}" if result.negative?
77
104
 
78
- @conn_ptr = ::FFI::Pointer.new(0)
105
+ dbg { 'closed' }
106
+
107
+ @ptr = ::FFI::Pointer.new(0)
79
108
  true
80
109
  end
81
110
 
82
111
  def opened?
83
- !@conn_ptr.null?
112
+ !@ptr.null?
84
113
  end
85
114
 
86
- def to_ptr
87
- @conn_ptr
115
+ def closed?
116
+ !opened?
88
117
  end
89
118
 
90
119
  def version
91
120
  check_open!
92
121
 
93
122
  version_ptr = ::FFI::MemoryPointer.new(:ulong)
94
- result = FFI::Host.virConnectGetVersion(@conn_ptr, version_ptr)
123
+ result = FFI::Host.virConnectGetVersion(@ptr, version_ptr)
95
124
  raise Errors::LibError, "Couldn't retrieve connection version" if result.negative?
96
125
 
97
126
  version_number = version_ptr.get_ulong(0)
@@ -99,29 +128,21 @@ module Libvirt
99
128
  end
100
129
 
101
130
  def set_keep_alive(interval, count)
102
- result = FFI::Host.virConnectSetKeepAlive(@conn_ptr, interval, count)
131
+ result = FFI::Host.virConnectSetKeepAlive(@ptr, interval, count)
103
132
  raise Errors::LibError, "Couldn't set connection keep_alive" if result.negative?
104
133
 
105
134
  result.zero?
106
135
  end
107
136
 
108
137
  def free_memory
109
- result = FFI::Host.virNodeGetFreeMemory(@conn_ptr)
138
+ result = FFI::Host.virNodeGetFreeMemory(@ptr)
110
139
  raise Errors::LibError, "Couldn't set connection keep_alive" if result.negative?
111
140
 
112
141
  result
113
142
  end
114
143
 
115
- def to_s
116
- "#<#{self.class}:0x#{object_id.to_s(16)} @uri=#{@uri.inspect} @conn_ptr=0x#{@conn_ptr.address.to_s(16)}>"
117
- end
118
-
119
- def inspect
120
- to_s
121
- end
122
-
123
144
  def list_all_domains_qty(flags = 0)
124
- result = FFI::Domain.virConnectListAllDomains(@conn_ptr, nil, flags)
145
+ result = FFI::Domain.virConnectListAllDomains(@ptr, nil, flags)
125
146
  raise Errors::LibError, "Couldn't retrieve domains qty with flags #{flags.to_s(16)}" if result.negative?
126
147
 
127
148
  result
@@ -132,7 +153,7 @@ module Libvirt
132
153
  return [] if size.zero?
133
154
 
134
155
  domains_ptr = ::FFI::MemoryPointer.new(:pointer, size)
135
- result = FFI::Domain.virConnectListAllDomains(@conn_ptr, domains_ptr, flags)
156
+ result = FFI::Domain.virConnectListAllDomains(@ptr, domains_ptr, flags)
136
157
  raise Errors::LibError, "Couldn't retrieve domains list with flags #{flags.to_s(16)}" if result.negative?
137
158
 
138
159
  ptr = domains_ptr.read_pointer
@@ -141,7 +162,7 @@ module Libvirt
141
162
 
142
163
  def list_all_storage_pools_qty(options_or_flags = nil)
143
164
  flags = Util.parse_flags options_or_flags, FFI::Storage.enum_type(:list_all_pools_flags)
144
- result = FFI::Storage.virConnectListAllStoragePools(@conn_ptr, nil, flags)
165
+ result = FFI::Storage.virConnectListAllStoragePools(@ptr, nil, flags)
145
166
  raise Errors::LibError, "Couldn't retrieve storage pools qty with flags #{flags.to_s(16)}" if result.negative?
146
167
 
147
168
  result
@@ -153,19 +174,73 @@ module Libvirt
153
174
  return [] if size.zero?
154
175
 
155
176
  storage_pools_ptr = ::FFI::MemoryPointer.new(:pointer, size)
156
- result = FFI::Storage.virConnectListAllStoragePools(@conn_ptr, storage_pools_ptr, flags)
177
+ result = FFI::Storage.virConnectListAllStoragePools(@ptr, storage_pools_ptr, flags)
157
178
  raise Errors::LibError, "Couldn't retrieve storage pools list with flags #{flags.to_s(16)}" if result.negative?
158
179
 
159
180
  ptr = storage_pools_ptr.read_pointer
160
181
  ptr.get_array_of_pointer(0, size).map { |stp_ptr| StoragePool.new(stp_ptr) }
161
182
  end
162
183
 
184
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
185
+ # @return [Integer]
186
+ # @raise [Libvirt::Errors::LibError]
187
+ def list_all_networks_qty(options_or_flags = nil)
188
+ flags = Util.parse_flags options_or_flags, FFI::Network.enum_type(:list_all_flags)
189
+ result = FFI::Network.virConnectListAllNetworks(@ptr, nil, flags)
190
+ raise Errors::LibError, "Couldn't retrieve networks qty with flags #{flags.to_s(16)}" if result.negative?
191
+
192
+ result
193
+ end
194
+
195
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
196
+ # @return [Array<Libvirt::Network>, Array]
197
+ # @raise [Libvirt::Errors::LibError]
198
+ def list_all_networks(options_or_flags = nil)
199
+ flags = Util.parse_flags options_or_flags, FFI::Network.enum_type(:list_all_flags)
200
+ size = list_all_networks_qty(flags)
201
+ return [] if size.zero?
202
+
203
+ networks_ptr = ::FFI::MemoryPointer.new(:pointer, size)
204
+ result = FFI::Network.virConnectListAllNetworks(@ptr, networks_ptr, 0)
205
+ raise Errors::LibError, "Couldn't retrieve networks list" if result.negative?
206
+
207
+ ptr = networks_ptr.read_pointer
208
+ ptr.get_array_of_pointer(0, size).map { |n_ptr| Network.new(n_ptr) }
209
+ end
210
+
211
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
212
+ # @return [Integer]
213
+ # @raise [Libvirt::Errors::LibError]
214
+ def list_all_interfaces_qty(options_or_flags = nil)
215
+ flags = Util.parse_flags options_or_flags, FFI::Interface.enum_type(:list_all_flags)
216
+ result = FFI::Interface.virConnectListAllInterfaces(@ptr, nil, flags)
217
+ raise Errors::LibError, "Couldn't retrieve interfaces qty with flags #{flags.to_s(16)}" if result.negative?
218
+
219
+ result
220
+ end
221
+
222
+ # @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
223
+ # @return [Array<Libvirt::Interface>, Array]
224
+ # @raise [Libvirt::Errors::LibError]
225
+ def list_all_interfaces(options_or_flags = nil)
226
+ flags = Util.parse_flags options_or_flags, FFI::Interface.enum_type(:list_all_flags)
227
+ size = list_all_interfaces_qty(flags)
228
+ return [] if size.zero?
229
+
230
+ interfaces_ptr = ::FFI::MemoryPointer.new(:pointer, size)
231
+ result = FFI::Interface.virConnectListAllInterfaces(@ptr, interfaces_ptr, 0)
232
+ raise Errors::LibError, "Couldn't retrieve interfaces list" if result.negative?
233
+
234
+ ptr = interfaces_ptr.read_pointer
235
+ ptr.get_array_of_pointer(0, size).map { |i_ptr| Interface.new(i_ptr) }
236
+ end
237
+
163
238
  def register_close_callback(opaque = nil, &block)
164
- dbg { "#register_close_callback opaque=#{opaque}" }
239
+ dbg { "opaque=#{opaque}" }
165
240
 
166
241
  cb_data, cb_data_free_func = CLOSE_STORAGE.allocate_struct
167
242
  result = FFI::Host.virConnectRegisterCloseCallback(
168
- @conn_ptr,
243
+ @ptr,
169
244
  CLOSE_CALLBACK,
170
245
  cb_data.pointer,
171
246
  cb_data_free_func
@@ -177,17 +252,29 @@ module Libvirt
177
252
 
178
253
  CLOSE_STORAGE.store_struct(
179
254
  cb_data,
180
- connection_pointer: @conn_ptr,
255
+ connection_pointer: @ptr,
181
256
  callback_id: result,
182
257
  cb: block,
183
- opaque: opaque
258
+ opaque: opaque,
259
+ free_func: cb_data_free_func
184
260
  )
185
261
  result
186
262
  end
187
263
 
264
+ def deregister_close_callback
265
+ dbg { 'deregister' }
266
+
267
+ result = FFI::Host.virConnectUnregisterCloseCallback(@ptr, CLOSE_CALLBACK)
268
+ raise Errors::LibError, "Couldn't deregister close callback" if result.negative?
269
+
270
+ # virConnectUnregisterCloseCallback will call free func
271
+ # So we don't need to remove object from CLOSE_STORAGE here.
272
+ true
273
+ end
274
+
188
275
  # @yield conn, dom, *args
189
276
  def register_domain_event_callback(event_id, domain = nil, opaque = nil, &block)
190
- dbg { "#register_domain_event_callback event_id=#{event_id}" }
277
+ dbg { "event_id=#{event_id}" }
191
278
 
192
279
  enum = FFI::Domain.enum_type(:event_id)
193
280
  event_id, event_id_sym = Util.parse_enum(enum, event_id)
@@ -196,7 +283,7 @@ module Libvirt
196
283
  cb_data, cb_data_free_func = DOMAIN_STORAGE.allocate_struct
197
284
 
198
285
  result = FFI::Domain.virConnectDomainEventRegisterAny(
199
- @conn_ptr,
286
+ @ptr,
200
287
  domain&.to_ptr,
201
288
  event_id,
202
289
  cb,
@@ -213,15 +300,16 @@ module Libvirt
213
300
  connection_pointer: @conn_ptr,
214
301
  callback_id: result,
215
302
  cb: block,
216
- opaque: opaque
303
+ opaque: opaque,
304
+ free_func: cb_data_free_func
217
305
  )
218
306
  result
219
307
  end
220
308
 
221
309
  def deregister_domain_event_callback(callback_id)
222
- dbg { "#deregister_domain_event_callback callback_id=#{callback_id}" }
310
+ dbg { "callback_id=#{callback_id}" }
223
311
 
224
- result = FFI::Domain.virConnectDomainEventDeregisterAny(@conn_ptr, callback_id)
312
+ result = FFI::Domain.virConnectDomainEventDeregisterAny(@ptr, callback_id)
225
313
  raise Errors::LibError, "Couldn't deregister domain event callback" if result.negative?
226
314
 
227
315
  # virConnectDomainEventDeregisterAny will call free func
@@ -230,7 +318,7 @@ module Libvirt
230
318
  end
231
319
 
232
320
  def register_storage_pool_event_callback(event_id, storage_pool = nil, opaque = nil, &block)
233
- dbg { "#register_storage_pool_event_callback event_id=#{event_id}" }
321
+ dbg { "event_id=#{event_id}" }
234
322
 
235
323
  enum = FFI::Storage.enum_type(:event_id)
236
324
  event_id, event_id_sym = Util.parse_enum(enum, event_id)
@@ -239,7 +327,7 @@ module Libvirt
239
327
  cb_data, cb_data_free_func = POOL_STORAGE.allocate_struct
240
328
 
241
329
  result = FFI::Storage.virConnectStoragePoolEventRegisterAny(
242
- @conn_ptr,
330
+ @ptr,
243
331
  storage_pool&.to_ptr,
244
332
  event_id,
245
333
  cb,
@@ -253,18 +341,19 @@ module Libvirt
253
341
 
254
342
  POOL_STORAGE.store_struct(
255
343
  cb_data,
256
- connection_pointer: @conn_ptr,
344
+ connection_pointer: @ptr,
257
345
  callback_id: result,
258
346
  cb: block,
259
- opaque: opaque
347
+ opaque: opaque,
348
+ free_func: cb_data_free_func
260
349
  )
261
350
  result
262
351
  end
263
352
 
264
353
  def deregister_storage_pool_event_callback(callback_id)
265
- dbg { "#deregister_storage_pool_event_callback callback_id=#{callback_id}" }
354
+ dbg { "callback_id=#{callback_id}" }
266
355
 
267
- result = FFI::Storage.virConnectStoragePoolEventDeregisterAny(@conn_ptr, callback_id)
356
+ result = FFI::Storage.virConnectStoragePoolEventDeregisterAny(@ptr, callback_id)
268
357
  raise Errors::LibError, "Couldn't deregister storage pool event callback" if result.negative?
269
358
 
270
359
  # virConnectStoragePoolEventDeregisterAny will call free func
@@ -272,20 +361,53 @@ module Libvirt
272
361
  true
273
362
  end
274
363
 
275
- def deregister_close_callback
276
- dbg { '#deregister_close_callback' }
364
+ def register_network_event_callback(event_id, network = nil, opaque = nil, &block)
365
+ dbg { "event_id=#{event_id}" }
277
366
 
278
- result = FFI::Host.virConnectUnregisterCloseCallback(@conn_ptr, CLOSE_CALLBACK)
279
- raise Errors::LibError, "Couldn't deregister close callback" if result.negative?
367
+ enum = FFI::Network.enum_type(:event_id)
368
+ event_id, event_id_sym = Util.parse_enum(enum, event_id)
369
+ cb = NETWORK_EVENT_CALLBACKS.fetch(event_id_sym)
280
370
 
281
- # virConnectUnregisterCloseCallback will call free func
282
- # So we don't need to remove object from CLOSE_STORAGE here.
371
+ cb_data, cb_data_free_func = NETWORK_STORAGE.allocate_struct
372
+
373
+ result = FFI::Network.virConnectNetworkEventRegisterAny(
374
+ @ptr,
375
+ network&.to_ptr,
376
+ event_id,
377
+ cb,
378
+ cb_data.pointer,
379
+ cb_data_free_func
380
+ )
381
+ if result.negative?
382
+ cb_data.pointer.free
383
+ raise Errors::LibError, "Couldn't register network event callback"
384
+ end
385
+
386
+ NETWORK_STORAGE.store_struct(
387
+ cb_data,
388
+ connection_pointer: @ptr,
389
+ callback_id: result,
390
+ cb: block,
391
+ opaque: opaque,
392
+ free_func: cb_data_free_func
393
+ )
394
+ result
395
+ end
396
+
397
+ def deregister_network_event_callback(callback_id)
398
+ dbg { "callback_id=#{callback_id}" }
399
+
400
+ result = FFI::Network.virConnectNetworkEventDeregisterAny(@ptr, callback_id)
401
+ raise Errors::LibError, "Couldn't deregister network event callback" if result.negative?
402
+
403
+ # virConnectNetworkEventDeregisterAny will call free func
404
+ # So we don't need to remove object from NETWORK_STORAGE here.
283
405
  true
284
406
  end
285
407
 
286
408
  def lib_version
287
409
  version_ptr = ::FFI::MemoryPointer.new(:ulong)
288
- result = FFI::Host.virConnectGetLibVersion(@conn_ptr, version_ptr)
410
+ result = FFI::Host.virConnectGetLibVersion(@ptr, version_ptr)
289
411
  raise Errors::LibError, "Couldn't get connection lib version" if result.negative?
290
412
 
291
413
  version_number = version_ptr.get_ulong(0)
@@ -293,28 +415,28 @@ module Libvirt
293
415
  end
294
416
 
295
417
  def hostname
296
- FFI::Host.virConnectGetHostname(@conn_ptr)
418
+ FFI::Host.virConnectGetHostname(@ptr)
297
419
  end
298
420
 
299
421
  # @param type [String,NilClass]
300
422
  def max_vcpus(type = nil)
301
- FFI::Host.virConnectGetMaxVcpus(@conn_ptr, type)
423
+ FFI::Host.virConnectGetMaxVcpus(@ptr, type)
302
424
  end
303
425
 
304
426
  def capabilities
305
- FFI::Host.virConnectGetCapabilities(@conn_ptr)
427
+ FFI::Host.virConnectGetCapabilities(@ptr)
306
428
  end
307
429
 
308
430
  def node_info
309
431
  node_info_ptr = ::FFI::MemoryPointer.new(FFI::Host::NodeInfoStruct.by_value)
310
- result = FFI::Host.virNodeGetInfo(@conn_ptr, node_info_ptr)
432
+ result = FFI::Host.virNodeGetInfo(@ptr, node_info_ptr)
311
433
  raise Errors::LibError, "Couldn't get connection node info" if result.negative?
312
434
 
313
435
  NodeInfo.new(node_info_ptr)
314
436
  end
315
437
 
316
438
  def stream(flags = 0)
317
- pointer = FFI::Stream.virStreamNew(@conn_ptr, flags)
439
+ pointer = FFI::Stream.virStreamNew(@ptr, flags)
318
440
  raise Errors::LibError, "Couldn't create stream" if pointer.null?
319
441
 
320
442
  Stream.new(pointer)
@@ -322,24 +444,61 @@ module Libvirt
322
444
 
323
445
  def define_domain(xml, options_or_flags = nil)
324
446
  flags = Util.parse_flags options_or_flags, FFI::Domain.enum_type(:define_flags)
325
- pointer = FFI::Domain.virDomainDefineXMLFlags(@conn_ptr, xml, flags)
447
+ pointer = FFI::Domain.virDomainDefineXMLFlags(@ptr, xml, flags)
326
448
  raise Errors::LibError, "Couldn't define domain" if pointer.null?
327
449
 
328
450
  Domain.new(pointer)
329
451
  end
330
452
 
331
- private
453
+ # @param xml [String]
454
+ # @raise [Libvirt::Errors::LibError]
455
+ def create_network(xml)
456
+ pointer = FFI::Network.virNetworkCreateXML(@ptr, xml)
457
+ raise Errors::LibError, "Couldn't create network with xml" if pointer.null?
332
458
 
333
- def set_connection(conn_ptr)
334
- @conn_ptr = conn_ptr
459
+ Network.new(pointer)
335
460
  end
336
461
 
337
- def check_open!
338
- raise Errors::LibError, "Connection to #{@uri.inspect} is not open" if @conn_ptr.null?
462
+ # @param xml [String]
463
+ # @raise [Libvirt::Errors::LibError]
464
+ def define_network(xml)
465
+ pointer = FFI::Network.virNetworkDefineXML(@ptr, xml)
466
+ raise Errors::LibError, "Couldn't define network with xml" if pointer.null?
467
+
468
+ Network.new(pointer)
339
469
  end
340
470
 
341
- def dbg(&block)
342
- Util.log(:debug, 'Libvirt::Connection', &block)
471
+ # @param xml [String]
472
+ # @raise [Libvirt::Errors::LibError]
473
+ def define_interface(xml)
474
+ pointer = FFI::Interface.virInterfaceDefineXML(@ptr, xml, 0)
475
+ raise Errors::LibError, "Couldn't define interface with xml" if pointer.null?
476
+
477
+ Interface.new(pointer)
478
+ end
479
+
480
+ # @raise [Libvirt::Errors::LibError]
481
+ def begin_interface_change
482
+ result = FFI::Interface.virInterfaceChangeBegin(@ptr, 0)
483
+ raise Errors::LibError, "Couldn't begin interface change" if result.negative?
484
+ end
485
+
486
+ # @raise [Libvirt::Errors::LibError]
487
+ def commit_interface_change
488
+ result = FFI::Interface.virInterfaceChangeCommit(@ptr, 0)
489
+ raise Errors::LibError, "Couldn't commit interface change" if result.negative?
490
+ end
491
+
492
+ # @raise [Libvirt::Errors::LibError]
493
+ def rollback_interface_change
494
+ result = FFI::Interface.virInterfaceChangeRollback(@ptr, 0)
495
+ raise Errors::LibError, "Couldn't rollback interface change" if result.negative?
496
+ end
497
+
498
+ private
499
+
500
+ def check_open!
501
+ raise Errors::LibError, "Connection to #{@uri.inspect} is not open" if @ptr.null?
343
502
  end
344
503
  end
345
504
  end