libvirt_ffi 0.2.1 → 0.5.1

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +78 -0
  3. data/Gemfile +7 -2
  4. data/Rakefile +6 -1
  5. data/bin/console +1 -0
  6. data/exe/libvirt +1 -0
  7. data/lib/libvirt.rb +14 -13
  8. data/lib/libvirt/base_info.rb +34 -0
  9. data/lib/libvirt/connection.rb +156 -47
  10. data/lib/libvirt/domain.rb +136 -8
  11. data/lib/libvirt/domain_callback_storage.rb +69 -0
  12. data/lib/libvirt/errors.rb +65 -0
  13. data/lib/libvirt/event.rb +60 -38
  14. data/lib/libvirt/ffi.rb +17 -0
  15. data/lib/libvirt/ffi/common.rb +8 -1
  16. data/lib/libvirt/ffi/domain.rb +796 -69
  17. data/lib/libvirt/ffi/error.rb +243 -0
  18. data/lib/libvirt/ffi/event.rb +30 -36
  19. data/lib/libvirt/ffi/helpers.rb +17 -0
  20. data/lib/libvirt/ffi/host.rb +122 -0
  21. data/lib/libvirt/ffi/storage.rb +149 -0
  22. data/lib/libvirt/ffi/stream.rb +74 -0
  23. data/lib/libvirt/node_info.rb +2 -41
  24. data/lib/libvirt/storage_pool.rb +70 -0
  25. data/lib/libvirt/storage_pool_info.rb +7 -0
  26. data/lib/libvirt/storage_volume.rb +51 -0
  27. data/lib/libvirt/storage_volume_info.rb +7 -0
  28. data/lib/libvirt/stream.rb +124 -0
  29. data/lib/libvirt/util.rb +75 -8
  30. data/lib/libvirt/version.rb +1 -1
  31. data/lib/libvirt/xml.rb +23 -0
  32. data/lib/libvirt/xml/disk.rb +59 -0
  33. data/lib/libvirt/xml/domain.rb +76 -0
  34. data/lib/libvirt/xml/generic.rb +252 -0
  35. data/lib/libvirt/xml/graphics.rb +14 -0
  36. data/lib/libvirt/xml/max_vcpu.rb +12 -0
  37. data/lib/libvirt/xml/memory.rb +14 -0
  38. data/lib/libvirt/xml/storage_pool.rb +24 -0
  39. data/lib/libvirt/xml/storage_volume.rb +32 -0
  40. data/lib/libvirt/xml/vcpu.rb +12 -0
  41. data/lib/libvirt_ffi.rb +2 -0
  42. data/libvirt.gemspec +5 -1
  43. data/test_usage/support/libvirt_async.rb +33 -31
  44. data/test_usage/support/log_formatter.rb +5 -10
  45. data/test_usage/test_domain.rb +43 -0
  46. data/test_usage/test_event_loop.rb +134 -33
  47. data/test_usage/test_libvirtd_restart.rb +63 -0
  48. data/test_usage/test_metadata.rb +104 -0
  49. data/test_usage/test_screenshot.rb +197 -0
  50. data/test_usage/test_storage.rb +52 -0
  51. metadata +46 -6
  52. data/lib/libvirt/error.rb +0 -6
  53. data/lib/libvirt/ffi/connection.rb +0 -84
  54. data/lib/libvirt/ffi/libvirt.rb +0 -17
  55. data/lib/libvirt/ffi/node_info.rb +0 -37
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 556422a513288d81aa723c2751129033da2118eb1d8a6a03c01e60efa57017fd
4
- data.tar.gz: 309fd55853169a8b25669736be80d1b0eebc7f66bb4e082f00714d4e751c9ff7
3
+ metadata.gz: 2685f9b26b91cc3365a0552374160ab1448e96b122a65f2e2350bf11811230d7
4
+ data.tar.gz: b89251ca7af3dac7275384f59bd2b93ce93bd7473c1c15ab3302ddad2a021212
5
5
  SHA512:
6
- metadata.gz: '039e73eb32c5354f99e3c31ca9fab1e81e23b0249bfd20f7ed78c10a9b21da5f2f5b73e124df4c2765b18c8e965e55ee5422135d73f56b84b1465506281c3d0b'
7
- data.tar.gz: f9d398150d78a71ed3682a6556cbcbd5e61e9d9304bc38fbaa0935f85798a571fcb9885feed73c50f64e20f7fde06bb79aa120ae7928b183531ac08bc656e4f4
6
+ metadata.gz: 791f213bfff0092f762ba0e87f3cf1eacb319f8b4530854f9d6bf20dab76b29a47eedb6f582d2c1f9fb8ff94a6f4c26226d3c2f170cb03a173fe16f33d73bb5b
7
+ data.tar.gz: 803d55a39f54fc9ab52affb71dad317957626614c3f9fc6edbbfce9ecaef038be74de52a011a6d79b501a6cc177f85c874cedb0339fa23fd61eec28e5a7b6d67
@@ -0,0 +1,78 @@
1
+ AllCops:
2
+ DisplayCopNames: true
3
+ TargetRubyVersion: 2.5
4
+ Exclude:
5
+ - vendor/**/*
6
+ - tmp/**/*
7
+ - pkg/*
8
+ - test_usage/**/*.rb
9
+
10
+ Layout/LineLength:
11
+ Max: 180
12
+
13
+ Style/SymbolArray:
14
+ EnforcedStyle: brackets
15
+
16
+ Style/Lambda:
17
+ EnforcedStyle: literal
18
+
19
+ Naming/MethodParameterName:
20
+ AllowedNames:
21
+ - id
22
+ - cb
23
+ - fd
24
+
25
+ Naming/AccessorMethodName:
26
+ Enabled: false
27
+
28
+ Style/HashEachMethods:
29
+ Enabled: true
30
+
31
+ Style/HashTransformKeys:
32
+ Enabled: true
33
+
34
+ Style/HashTransformValues:
35
+ Enabled: true
36
+
37
+ Style/Documentation:
38
+ Enabled: false
39
+
40
+ Metrics/PerceivedComplexity:
41
+ Enabled: false
42
+
43
+ Metrics/MethodLength:
44
+ Enabled: false
45
+
46
+ Metrics/AbcSize:
47
+ Enabled: false
48
+
49
+ Metrics/ModuleLength:
50
+ Enabled: false
51
+
52
+ Metrics/BlockLength:
53
+ Enabled: false
54
+
55
+ Metrics/ClassLength:
56
+ Enabled: false
57
+
58
+ Metrics/CyclomaticComplexity:
59
+ Enabled: false
60
+
61
+ Layout/MultilineOperationIndentation:
62
+ Enabled: false
63
+
64
+ Layout/FirstHashElementIndentation:
65
+ Enabled: false
66
+
67
+ Layout/FirstArrayElementIndentation:
68
+ Enabled: false
69
+
70
+ Layout/FirstArgumentIndentation:
71
+ Enabled: false
72
+
73
+ Layout/ClosingParenthesisIndentation:
74
+ Enabled: false
75
+
76
+ Layout/ArgumentAlignment:
77
+ Enabled: false
78
+
data/Gemfile CHANGED
@@ -1,13 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in libvirt.gemspec
4
6
  gemspec
5
7
 
6
- gem 'rake', '~> 12.0'
7
8
  gem 'minitest', '~> 5.0'
9
+ gem 'rake', '~> 12.0'
10
+
11
+ gem 'nokogiri'
8
12
 
9
13
  group :development do
10
- gem 'async', '~> 1.24'
11
14
  gem 'activesupport'
15
+ gem 'async', '~> 1.24'
16
+ gem 'gc_tracer'
12
17
  gem 'get_process_mem'
13
18
  end
data/Rakefile CHANGED
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rake/testtask'
5
+ require 'rubocop/rake_task'
3
6
 
4
7
  Rake::TestTask.new(:test) do |t|
5
8
  t.libs << 'test'
@@ -7,4 +10,6 @@ Rake::TestTask.new(:test) do |t|
7
10
  t.test_files = FileList['test/**/*_test.rb']
8
11
  end
9
12
 
10
- task default: :test
13
+ RuboCop::RakeTask.new(:rubocop)
14
+
15
+ task default: [:rubocop, :test]
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'libvirt'
@@ -1,3 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'libvirt'
@@ -2,18 +2,20 @@
2
2
 
3
3
  require 'ffi'
4
4
  require 'objspace'
5
+ require 'libvirt/domain_callback_storage'
5
6
  require 'libvirt/util'
6
- require 'libvirt/error'
7
- require 'libvirt/ffi/common'
8
- require 'libvirt/ffi/libvirt'
9
- require 'libvirt/ffi/connection'
10
- require 'libvirt/ffi/domain'
11
- require 'libvirt/ffi/event'
12
- require 'libvirt/ffi/node_info'
7
+ require 'libvirt/errors'
8
+ require 'libvirt/ffi'
9
+ require 'libvirt/base_info'
10
+ require 'libvirt/node_info'
11
+ require 'libvirt/storage_pool_info'
12
+ require 'libvirt/storage_volume_info'
13
13
  require 'libvirt/event'
14
14
  require 'libvirt/connection'
15
15
  require 'libvirt/domain'
16
- require 'libvirt/node_info'
16
+ require 'libvirt/stream'
17
+ require 'libvirt/storage_pool'
18
+ require 'libvirt/storage_volume'
17
19
  require 'libvirt/version'
18
20
 
19
21
  module Libvirt
@@ -22,15 +24,14 @@ module Libvirt
22
24
  EVENT_HANDLE_ERROR = 4
23
25
  EVENT_HANDLE_HANGUP = 8
24
26
 
25
- DOMAIN_EVENT_ID_LIFECYCLE = 0
26
-
27
27
  class << self
28
28
  def lib_version
29
29
  version_ptr = ::FFI::MemoryPointer.new(:ulong)
30
- code = FFI::Libvirt.virGetVersion(version_ptr, nil, nil)
31
- raise Error, 'failed to get version' if code < 0
30
+ code = FFI::Host.virGetVersion(version_ptr, nil, nil)
31
+ raise Errors::LibError, 'failed to get version' if code.negative?
32
+
32
33
  version_number = version_ptr.get_ulong(0)
33
- Libvirt::Util.parse_version(version_number)
34
+ Util.parse_version(version_number)
34
35
  end
35
36
 
36
37
  def logger
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Libvirt
4
+ class BaseInfo
5
+ # Abstract Base class for info
6
+
7
+ class << self
8
+ attr_accessor :_struct_class
9
+
10
+ # @param [Class<FFI::Struct>]
11
+ def struct_class(klass)
12
+ self._struct_class = klass
13
+ klass.members.each do |attr|
14
+ define_method(attr) { @struct[attr] }
15
+ end
16
+ end
17
+ end
18
+
19
+ def initialize(pointer)
20
+ raise ArgumentError, "Can't initialize base class #{self.class}" if self.class == BaseInfo
21
+
22
+ @ptr = pointer
23
+ @struct = self.class._struct_class.new(pointer)
24
+ end
25
+
26
+ def [](attr)
27
+ @struct[attr]
28
+ end
29
+
30
+ def to_h
31
+ @struct.members.map { |attr| [attr, @struct[attr]] }.to_h
32
+ end
33
+ end
34
+ end
@@ -2,18 +2,54 @@
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 = DOMAIN_EVENT_IDS.map do |event_id_sym|
10
+ func = FFI::Domain.event_callback_for(event_id_sym) 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
+ [event_id_sym, func]
17
+ end.to_h.freeze
18
+
19
+ def self.load_ref(conn_ptr)
20
+ ref_result = FFI::Host.virConnectRef(conn_ptr)
21
+ raise Errors::LibError, "Couldn't retrieve connection reference" if ref_result.negative?
22
+
23
+ new(nil).tap { |r| r.send(:set_connection, conn_ptr) }
24
+ end
25
+
5
26
  def initialize(uri)
6
27
  @uri = uri
7
28
  @conn_ptr = ::FFI::Pointer.new(0)
8
- @cb_data = {}
9
- ObjectSpace.define_finalizer(self, proc { |obj_id|
10
- STDOUT.puts("finalized Libvirt::Connection #{obj_id.to_s(16)}")
11
- })
29
+ @close_data = nil
30
+
31
+ free = ->(obj_id) do
32
+ Util.log(:debug) { "Finalize Libvirt::Connection 0x#{obj_id.to_s(16)} @conn_ptr=#{@conn_ptr}," }
33
+ return if @conn_ptr.null?
34
+
35
+ cl_result = FFI::Host.virConnectClose(@conn_ptr)
36
+ warn "Couldn't close Libvirt::Connection (0x#{obj_id.to_s(16)}) pointer #{@conn_ptr.address}" if cl_result.negative?
37
+ end
38
+ ObjectSpace.define_finalizer(self, free)
12
39
  end
13
40
 
14
41
  def open
15
- @conn_ptr = FFI::Connection.virConnectOpen(@uri)
16
- raise Error, "Couldn't connect to #{@uri.inspect}" if @conn_ptr.null?
42
+ @conn_ptr = FFI::Host.virConnectOpen(@uri)
43
+ raise Errors::LibError, "Couldn't open connection to #{@uri.inspect}" if @conn_ptr.null?
44
+
45
+ true
46
+ end
47
+
48
+ def close
49
+ result = FFI::Host.virConnectClose(@conn_ptr)
50
+ raise Errors::LibError, "Couldn't close connection to #{@uri.inspect}" if result.negative?
51
+
52
+ @conn_ptr = ::FFI::Pointer.new(0)
17
53
  true
18
54
  end
19
55
 
@@ -29,16 +65,18 @@ module Libvirt
29
65
  check_open!
30
66
 
31
67
  version_ptr = ::FFI::MemoryPointer.new(:ulong)
32
- result = FFI::Connection.virConnectGetVersion(@conn_ptr, version_ptr)
33
- raise Error, "Couldn't retrieve connection version" if result < 0
68
+ result = FFI::Host.virConnectGetVersion(@conn_ptr, version_ptr)
69
+ raise Errors::LibError, "Couldn't retrieve connection version" if result.negative?
70
+
34
71
  version_number = version_ptr.get_ulong(0)
35
- Libvirt::Util::parse_version(version_number)
72
+ Util.parse_version(version_number)
36
73
  end
37
74
 
38
75
  def set_keep_alive(interval, count)
39
- result = FFI::Connection.virConnectSetKeepAlive(@conn_ptr, interval, count)
40
- raise Error, "Couldn't set connection keep_alive" if result < 0
41
- result == 0
76
+ result = FFI::Host.virConnectSetKeepAlive(@conn_ptr, interval, count)
77
+ raise Errors::LibError, "Couldn't set connection keep_alive" if result.negative?
78
+
79
+ result.zero?
42
80
  end
43
81
 
44
82
  def to_s
@@ -51,90 +89,161 @@ module Libvirt
51
89
 
52
90
  def list_all_domains_qty(flags = 0)
53
91
  result = FFI::Domain.virConnectListAllDomains(@conn_ptr, nil, flags)
54
- raise Error, "Couldn't retrieve domains qty with flags #{flags.to_s(16)}" if result < 0
92
+ raise Errors::LibError, "Couldn't retrieve domains qty with flags #{flags.to_s(16)}" if result.negative?
93
+
55
94
  result
56
95
  end
57
96
 
58
97
  def list_all_domains(flags = 0)
59
98
  size = list_all_domains_qty(flags)
99
+ return [] if size.zero?
100
+
60
101
  domains_ptr = ::FFI::MemoryPointer.new(:pointer, size)
61
102
  result = FFI::Domain.virConnectListAllDomains(@conn_ptr, domains_ptr, flags)
62
- raise Error, "Couldn't retrieve domains list with flags #{flags.to_s(16)}" if result < 0
103
+ raise Errors::LibError, "Couldn't retrieve domains list with flags #{flags.to_s(16)}" if result.negative?
104
+
63
105
  ptr = domains_ptr.read_pointer
64
- ptr.get_array_of_pointer(0, size).map { |dom_ptr| Libvirt::Domain.new(dom_ptr, self) }
106
+ ptr.get_array_of_pointer(0, size).map { |dom_ptr| Libvirt::Domain.new(dom_ptr) }
65
107
  end
66
108
 
67
- # @yield conn, dom
68
- def register_domain_event_callback(event_id, domain = nil, opaque = nil, &block)
69
- if event_id == Libvirt::DOMAIN_EVENT_ID_LIFECYCLE
70
- cb = FFI::Domain::domain_event_id_lifecycle_callback(&block)
71
- else
72
- raise Error, "not supported event_id #{event_id.inspect}"
109
+ def list_all_storage_pools_qty(options_or_flags = nil)
110
+ flags = Util.parse_flags options_or_flags, FFI::Storage.enum_type(:list_all_pools_flags)
111
+ result = FFI::Storage.virConnectListAllStoragePools(@conn_ptr, nil, flags)
112
+ raise Errors::LibError, "Couldn't retrieve storage pools qty with flags #{flags.to_s(16)}" if result.negative?
113
+
114
+ result
115
+ end
116
+
117
+ def list_all_storage_pools(options_or_flags = nil)
118
+ flags = Util.parse_flags options_or_flags, FFI::Storage.enum_type(:list_all_pools_flags)
119
+ size = list_all_storage_pools_qty(flags)
120
+ return [] if size.zero?
121
+
122
+ storage_pools_ptr = ::FFI::MemoryPointer.new(:pointer, size)
123
+ result = FFI::Storage.virConnectListAllStoragePools(@conn_ptr, storage_pools_ptr, flags)
124
+ raise Errors::LibError, "Couldn't retrieve storage pools list with flags #{flags.to_s(16)}" if result.negative?
125
+
126
+ ptr = storage_pools_ptr.read_pointer
127
+ ptr.get_array_of_pointer(0, size).map { |stp_ptr| StoragePool.new(stp_ptr) }
128
+ end
129
+
130
+ def register_close_callback(opaque = nil, &block)
131
+ dbg { "#register_close_callback opaque=#{opaque}" }
132
+ raise ArgumentError, 'close function already registered' if @close_data
133
+
134
+ @close_data = { opaque: opaque, block: block }
135
+ @close_cb = FFI::Host.callback_function(:virConnectCloseFunc) do |_conn, reason, _op|
136
+ dbg { "CONNECTION CLOSED @conn_ptr=#{@conn_ptr} reason=#{reason}" }
137
+ @close_data[:block].call(self, reason, @close_data[:opaque])
73
138
  end
139
+ @close_free_func = FFI::Common.free_function do
140
+ dbg { "CONNECTION CLOSED FREE FUNC @conn_ptr=#{@conn_ptr}" }
141
+ @close_cb = @close_free_func = @close_data = nil
142
+ end
143
+ FFI::Host.virConnectRegisterCloseCallback(@conn_ptr, @close_cb, nil, @close_free_func)
144
+ end
145
+
146
+ # @yield conn, dom, *args
147
+ def register_domain_event_callback(event_id, domain = nil, opaque = nil, &block)
148
+ dbg { "#register_domain_event_callback event_id=#{event_id}" }
149
+
150
+ enum = FFI::Domain.enum_type(:event_id)
151
+ event_id, event_id_sym = Util.parse_enum(enum, event_id)
152
+ cb = DOMAIN_EVENT_CALLBACKS.fetch(event_id_sym)
153
+
154
+ cb_data, cb_data_free_func = STORAGE.allocate_struct
74
155
 
75
156
  result = FFI::Domain.virConnectDomainEventRegisterAny(
76
157
  @conn_ptr,
77
158
  domain&.to_ptr,
78
159
  event_id,
79
160
  cb,
80
- opaque&.to_ptr,
81
- nil # free_opaque
161
+ cb_data.pointer,
162
+ cb_data_free_func
82
163
  )
83
- raise Error, "Couldn't register domain event callback" if result < 0
164
+ if result.negative?
165
+ cb_data.pointer.free
166
+ raise Errors::LibError, "Couldn't register domain event callback"
167
+ end
84
168
 
85
- @cb_data[result] = { event_id: event_id, cb: cb, opaque: opaque }
169
+ STORAGE.store_struct(
170
+ cb_data,
171
+ connection_pointer: @conn_ptr,
172
+ callback_id: result,
173
+ cb: block,
174
+ opaque: opaque
175
+ )
86
176
  result
87
177
  end
88
178
 
89
179
  def deregister_domain_event_callback(callback_id)
90
- @cb_data.delete(callback_id)
180
+ dbg { "#deregister_domain_event_callback callback_id=#{callback_id}" }
181
+
91
182
  result = FFI::Domain.virConnectDomainEventDeregisterAny(@conn_ptr, callback_id)
92
- raise Error, "Couldn't deregister domain event callback" if result < 0
93
- true
94
- end
183
+ raise Errors::LibError, "Couldn't deregister domain event callback" if result.negative?
95
184
 
96
- def version
97
- version_ptr = ::FFI::MemoryPointer.new(:ulong)
98
- result = FFI::Connection.virConnectGetVersion(@conn_ptr, version_ptr)
99
- raise Error, "Couldn't get connection version" if result < 0
100
- version_number = version_ptr.get_ulong(0)
101
- # version_number = FFI::Connection.virConnectGetVersion(@conn_ptr)
102
- Libvirt::Util.parse_version(version_number)
185
+ # virConnectDomainEventDeregisterAny will call free func
186
+ # So we don't need to remove object from STORAGE here.
187
+ true
103
188
  end
104
189
 
105
190
  def lib_version
106
191
  version_ptr = ::FFI::MemoryPointer.new(:ulong)
107
- result = FFI::Connection.virConnectGetLibVersion(@conn_ptr, version_ptr)
108
- raise Error, "Couldn't get connection lib version" if result < 0
192
+ result = FFI::Host.virConnectGetLibVersion(@conn_ptr, version_ptr)
193
+ raise Errors::LibError, "Couldn't get connection lib version" if result.negative?
194
+
109
195
  version_number = version_ptr.get_ulong(0)
110
- # version_number = FFI::Connection.virConnectGetLibVersion(@conn_ptr)
111
- Libvirt::Util.parse_version(version_number)
196
+ Util.parse_version(version_number)
112
197
  end
113
198
 
114
199
  def hostname
115
- FFI::Connection.virConnectGetHostname(@conn_ptr)
200
+ FFI::Host.virConnectGetHostname(@conn_ptr)
116
201
  end
117
202
 
118
203
  # @param type [String,NilClass]
119
204
  def max_vcpus(type = nil)
120
- FFI::Connection.virConnectGetMaxVcpus(@conn_ptr, type)
205
+ FFI::Host.virConnectGetMaxVcpus(@conn_ptr, type)
121
206
  end
122
207
 
123
208
  def capabilities
124
- FFI::Connection.virConnectGetCapabilities(@conn_ptr)
209
+ FFI::Host.virConnectGetCapabilities(@conn_ptr)
125
210
  end
126
211
 
127
212
  def node_info
128
- node_info_ptr = ::FFI::MemoryPointer.new(FFI::NodeInfo::Struct.by_value)
129
- result = FFI::NodeInfo.virNodeGetInfo(@conn_ptr, node_info_ptr)
130
- raise Error, "Couldn't get connection node info" if result < 0
213
+ node_info_ptr = ::FFI::MemoryPointer.new(FFI::Host::NodeInfoStruct.by_value)
214
+ result = FFI::Host.virNodeGetInfo(@conn_ptr, node_info_ptr)
215
+ raise Errors::LibError, "Couldn't get connection node info" if result.negative?
216
+
131
217
  NodeInfo.new(node_info_ptr)
132
218
  end
133
219
 
220
+ def stream(flags = 0)
221
+ pointer = FFI::Stream.virStreamNew(@conn_ptr, flags)
222
+ raise Errors::LibError, "Couldn't create stream" if pointer.null?
223
+
224
+ Stream.new(pointer)
225
+ end
226
+
227
+ def define_domain(xml, options_or_flags = nil)
228
+ flags = Util.parse_flags options_or_flags, FFI::Domain.enum_type(:define_flags)
229
+ pointer = FFI::Domain.virDomainDefineXMLFlags(@conn_ptr, xml, flags)
230
+ raise Errors::LibError, "Couldn't define domain" if pointer.null?
231
+
232
+ Domain.new(pointer)
233
+ end
234
+
134
235
  private
135
236
 
237
+ def set_connection(conn_ptr)
238
+ @conn_ptr = conn_ptr
239
+ end
240
+
136
241
  def check_open!
137
- raise Error, "Connection to #{@uri.inspect} is not open" if @conn_ptr.null?
242
+ raise Errors::LibError, "Connection to #{@uri.inspect} is not open" if @conn_ptr.null?
243
+ end
244
+
245
+ def dbg(&block)
246
+ Util.log(:debug, 'Libvirt::Connection', &block)
138
247
  end
139
248
  end
140
249
  end