libvirt_ffi 0.2.1 → 0.5.1

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