libvirt_ffi 0.6.1 → 0.8.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.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +26 -0
- data/.gitignore +2 -1
- data/.rspec +1 -0
- data/.rubocop.yml +1 -1
- data/Gemfile +7 -10
- data/README.md +2 -2
- data/Rakefile +3 -8
- data/lib/libvirt/base_info.rb +8 -0
- data/lib/libvirt/connection.rb +228 -69
- data/lib/libvirt/domain.rb +18 -0
- data/lib/libvirt/ffi/domain.rb +53 -41
- data/lib/libvirt/ffi/host.rb +78 -39
- data/lib/libvirt/ffi/interface.rb +175 -0
- data/lib/libvirt/ffi/network.rb +392 -0
- data/lib/libvirt/ffi/storage.rb +1 -1
- data/lib/libvirt/ffi.rb +2 -0
- data/lib/libvirt/host_callback_storage.rb +10 -2
- data/lib/libvirt/interface.rb +92 -0
- data/lib/libvirt/loggable.rb +58 -0
- data/lib/libvirt/network.rb +176 -0
- data/lib/libvirt/network_dhcp_lease.rb +20 -0
- data/lib/libvirt/storage_pool.rb +2 -2
- data/lib/libvirt/util.rb +87 -64
- data/lib/libvirt/version.rb +1 -1
- data/lib/libvirt/xml/generic.rb +8 -5
- data/lib/libvirt/xml/interface.rb +79 -0
- data/lib/libvirt/xml/ip_address.rb +51 -0
- data/lib/libvirt/xml/network.rb +204 -0
- data/lib/libvirt/xml.rb +6 -2
- data/lib/libvirt.rb +18 -16
- data/libvirt.gemspec +11 -13
- metadata +14 -26
- data/.travis.yml +0 -6
- data/test_usage/support/libvirt_async.rb +0 -536
- data/test_usage/support/log_formatter.rb +0 -33
- data/test_usage/test_domain.rb +0 -43
- data/test_usage/test_event_loop.rb +0 -185
- data/test_usage/test_libvirtd_restart.rb +0 -63
- data/test_usage/test_metadata.rb +0 -104
- data/test_usage/test_screenshot.rb +0 -197
- data/test_usage/test_storage.rb +0 -52
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Libvirt
|
4
|
+
module Loggable
|
5
|
+
# caller[0].match(/`(.*)'/)[1]
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def dbg(prog_name = nil, &block)
|
9
|
+
return if Libvirt.logger.nil?
|
10
|
+
|
11
|
+
if prog_name.nil?
|
12
|
+
meth = caller[0].match(/`(.*)'/)[1]
|
13
|
+
meth = "<#{meth}>" if meth.include?(' ')
|
14
|
+
prog_name = "#{name}.#{meth}"
|
15
|
+
end
|
16
|
+
Libvirt.logger.debug(prog_name, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def err(prog_name = nil, &block)
|
20
|
+
return if Libvirt.logger.nil?
|
21
|
+
|
22
|
+
if prog_name.nil?
|
23
|
+
meth = caller[0].match(/`(.*)'/)[1]
|
24
|
+
meth = "<#{meth}>" if meth.include?(' ')
|
25
|
+
prog_name = "#{name}.#{meth}"
|
26
|
+
end
|
27
|
+
Libvirt.logger.error(prog_name, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.included(base)
|
32
|
+
base.extend ClassMethods
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def dbg(prog_name = nil, &block)
|
37
|
+
return if Libvirt.logger.nil?
|
38
|
+
|
39
|
+
if prog_name.nil?
|
40
|
+
meth = caller[0].match(/`(.*)'/)[1]
|
41
|
+
meth = "<#{meth}>" if meth.include?(' ')
|
42
|
+
prog_name = "#{self.class.name}##{meth}"
|
43
|
+
end
|
44
|
+
Libvirt.logger.debug(prog_name, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def err(prog_name = nil, &block)
|
48
|
+
return if Libvirt.logger.nil?
|
49
|
+
|
50
|
+
if prog_name.nil?
|
51
|
+
meth = caller[0].match(/`(.*)'/)[1]
|
52
|
+
meth = "<#{meth}>" if meth.include?(' ')
|
53
|
+
prog_name = "#{self.class.name}##{meth}"
|
54
|
+
end
|
55
|
+
Libvirt.logger.error(prog_name, &block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Libvirt
|
4
|
+
class Network
|
5
|
+
# @param pointer [FFI::Pointer]
|
6
|
+
def self.load_ref(pointer)
|
7
|
+
result = FFI::Network.virNetworkRef(pointer)
|
8
|
+
raise Errors::LibError, "Couldn't retrieve network reference" if result.negative?
|
9
|
+
|
10
|
+
new(pointer)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param pointer [FFI::Pointer]
|
14
|
+
def initialize(pointer)
|
15
|
+
@ptr = pointer
|
16
|
+
|
17
|
+
free = ->(obj_id) do
|
18
|
+
dbg { "Finalize Libvirt::Network object_id=0x#{obj_id.to_s(16)}, pointer=0x#{@ptr.address.to_s(16)}" }
|
19
|
+
return unless @ptr
|
20
|
+
|
21
|
+
warn "Couldn't free Libvirt::Network object_id=0x#{obj_id.to_s(16)}, pointer=0x#{@ptr.address.to_s(16)}" if FFI::Network.virNetworkFree(@ptr).negative?
|
22
|
+
end
|
23
|
+
ObjectSpace.define_finalizer(self, free)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [FFI::Pointer]
|
27
|
+
def to_ptr
|
28
|
+
@ptr
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String]
|
32
|
+
# @raise [Libvirt::Errors::LibError]
|
33
|
+
def uuid
|
34
|
+
buff = ::FFI::MemoryPointer.new(:char, Util::UUID_STRING_BUFLEN)
|
35
|
+
result = FFI::Network.virNetworkGetUUIDString(@ptr, buff)
|
36
|
+
raise Errors::LibError, "Couldn't get network uuid" if result.negative?
|
37
|
+
|
38
|
+
buff.read_string
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String]
|
42
|
+
# @raise [Libvirt::Errors::LibError]
|
43
|
+
def name
|
44
|
+
result = FFI::Network.virNetworkGetName(@ptr)
|
45
|
+
raise Errors::LibError, "Couldn't get network name" if result.nil?
|
46
|
+
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param options_or_flags [Array<Symbol>,Hash{Symbol=>Boolean},Integer,Symbol,nil]
|
51
|
+
# @raise [Libvirt::Errors::LibError]
|
52
|
+
def xml_desc(options_or_flags = nil)
|
53
|
+
flags = Util.parse_flags options_or_flags, FFI::Network.enum_type(:xml_flags)
|
54
|
+
result = FFI::Network.virNetworkGetXMLDesc(@ptr, flags)
|
55
|
+
raise Errors::LibError, "Couldn't get network xml_desc" if result.nil?
|
56
|
+
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Boolean]
|
61
|
+
# @raise [Libvirt::Errors::LibError]
|
62
|
+
def active?
|
63
|
+
result = FFI::Network.virNetworkIsActive(@ptr)
|
64
|
+
raise Errors::LibError, "Couldn't get network is active" if result.nil?
|
65
|
+
|
66
|
+
result == 1
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Boolean]
|
70
|
+
# @raise [Libvirt::Errors::LibError]
|
71
|
+
def persistent?
|
72
|
+
result = FFI::Network.virNetworkIsPersistent(@ptr)
|
73
|
+
raise Errors::LibError, "Couldn't get network is persistent" if result.nil?
|
74
|
+
|
75
|
+
result == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [String]
|
79
|
+
# @raise [Libvirt::Errors::LibError]
|
80
|
+
def bridge_name
|
81
|
+
result = FFI::Network.virNetworkGetBridgeName(@ptr)
|
82
|
+
raise Errors::LibError, "Couldn't get network bridge_name" if result.nil?
|
83
|
+
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Boolean]
|
88
|
+
# @raise [Libvirt::Errors::LibError]
|
89
|
+
def auto_start?
|
90
|
+
value = ::FFI::MemoryPointer.new(:int)
|
91
|
+
result = FFI::Network.virNetworkGetAutostart(@ptr, value)
|
92
|
+
raise Errors::LibError, "Couldn't get network auto_start" if result.negative?
|
93
|
+
|
94
|
+
value.read_int == 1
|
95
|
+
end
|
96
|
+
|
97
|
+
# @param value [Boolean]
|
98
|
+
# @raise [Libvirt::Errors::LibError]
|
99
|
+
def set_auto_start(value)
|
100
|
+
value = value ? 1 : 0
|
101
|
+
result = FFI::Network.virNetworkSetAutostart(@ptr, value)
|
102
|
+
raise Errors::LibError, "Couldn't set network auto_start" if result.negative?
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param mac [String]
|
106
|
+
# @return [Integer]
|
107
|
+
# @raise [Libvirt::Errors::LibError]
|
108
|
+
def dhcp_leases_qty(mac = nil)
|
109
|
+
result = FFI::Network.virNetworkGetDHCPLeases(@ptr, mac, nil, 0)
|
110
|
+
raise Errors::LibError, "Couldn't get network dhcp leases qty" if result.nil?
|
111
|
+
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
# @param mac [String]
|
116
|
+
# @return [Array<Libvirt::NetworkDhcpLease>, Array]
|
117
|
+
# @raise [Libvirt::Errors::LibError]
|
118
|
+
def dhcp_leases(mac = nil)
|
119
|
+
size = dhcp_leases_qty(mac)
|
120
|
+
return [] if size.zero?
|
121
|
+
|
122
|
+
dhcp_leases_ptr = ::FFI::MemoryPointer.new(:pointer, size)
|
123
|
+
result = FFI::Network.virNetworkGetDHCPLeases(@ptr, mac, dhcp_leases_ptr, 0)
|
124
|
+
raise Errors::LibError, "Couldn't retrieve network dhcp leases" if result.negative?
|
125
|
+
|
126
|
+
ptr = dhcp_leases_ptr.read_pointer
|
127
|
+
ptr.get_array_of_pointer(0, size).map { |dhcpl_ptr| NetworkDhcpLease.new(dhcpl_ptr) }
|
128
|
+
end
|
129
|
+
|
130
|
+
# @raise [Libvirt::Errors::LibError]
|
131
|
+
def start
|
132
|
+
result = FFI::Network.virNetworkCreate(@ptr)
|
133
|
+
raise Errors::LibError, "Couldn't start network" if result.negative?
|
134
|
+
end
|
135
|
+
|
136
|
+
# @raise [Libvirt::Errors::LibError]
|
137
|
+
def destroy
|
138
|
+
result = FFI::Network.virNetworkDestroy(@ptr)
|
139
|
+
raise Errors::LibError, "Couldn't destroy network" if result.negative?
|
140
|
+
end
|
141
|
+
|
142
|
+
# @raise [Libvirt::Errors::LibError]
|
143
|
+
def undefine
|
144
|
+
result = FFI::Network.virNetworkUndefine(@ptr)
|
145
|
+
raise Errors::LibError, "Couldn't undefine network" if result.negative?
|
146
|
+
end
|
147
|
+
|
148
|
+
# @param xml [String]
|
149
|
+
# @param command [Integer, Symbol]
|
150
|
+
# @param section [Integer, Symbol]
|
151
|
+
# @param flags [Integer, Symbol]
|
152
|
+
# @param parent_index [Integer] default -1 (means don't care)
|
153
|
+
# @raise [Libvirt::Errors::LibError]
|
154
|
+
def update(xml, command, section, flags, parent_index = -1)
|
155
|
+
command = Util.parse_flags command, FFI::Network.enum_type(:update_command)
|
156
|
+
section = Util.parse_flags section, FFI::Network.enum_type(:update_section)
|
157
|
+
flags = Util.parse_flags flags, FFI::Network.enum_type(:update_flags)
|
158
|
+
|
159
|
+
result = FFI::Network.virNetworkUpdate(
|
160
|
+
@ptr,
|
161
|
+
command,
|
162
|
+
section,
|
163
|
+
parent_index,
|
164
|
+
xml,
|
165
|
+
flags
|
166
|
+
)
|
167
|
+
raise Errors::LibError, "Couldn't update network" if result.negative?
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def dbg(&block)
|
173
|
+
Util.log(:debug, 'Libvirt::Network', &block)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Libvirt
|
4
|
+
class NetworkDhcpLease < BaseInfo
|
5
|
+
struct_class FFI::Network::DhcpLeaseStruct
|
6
|
+
|
7
|
+
# @param pointer [FFI::Pointer]
|
8
|
+
def initialize(pointer)
|
9
|
+
super
|
10
|
+
|
11
|
+
free = ->(obj_id) do
|
12
|
+
dbg { "Finalize Libvirt::NetworkDhcpLease object_id=0x#{obj_id.to_s(16)}, pointer=0x#{@ptr.address.to_s(16)}" }
|
13
|
+
return unless @ptr
|
14
|
+
|
15
|
+
warn "Couldn't free Libvirt::NetworkDhcpLease object_id=0x#{obj_id.to_s(16)}, pointer=0x#{@ptr.address.to_s(16)}" if FFI::Storage.virNetworkDHCPLeaseFree(@ptr).negative?
|
16
|
+
end
|
17
|
+
ObjectSpace.define_finalizer(self, free)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/libvirt/storage_pool.rb
CHANGED
@@ -13,7 +13,7 @@ module Libvirt
|
|
13
13
|
@ptr = pointer
|
14
14
|
|
15
15
|
free = ->(obj_id) do
|
16
|
-
|
16
|
+
dbg { "Finalize Libvirt::StoragePool 0x#{obj_id.to_s(16)} @ptr=#{@ptr}," }
|
17
17
|
return unless @ptr
|
18
18
|
|
19
19
|
fr_result = FFI::Storage.virStoragePoolFree(@ptr)
|
@@ -79,7 +79,7 @@ module Libvirt
|
|
79
79
|
private
|
80
80
|
|
81
81
|
def dbg(&block)
|
82
|
-
Util.log(:debug, 'Libvirt::
|
82
|
+
Util.log(:debug, 'Libvirt::StoragePool', &block)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
data/lib/libvirt/util.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'objspace'
|
4
|
+
|
3
5
|
module Libvirt
|
4
6
|
module Util
|
7
|
+
extend Loggable::ClassMethods
|
8
|
+
|
5
9
|
UNIT_TO_BYTES = {
|
6
10
|
b: 1,
|
7
11
|
bytes: 1,
|
@@ -21,83 +25,102 @@ module Libvirt
|
|
21
25
|
|
22
26
|
UUID_STRING_BUFLEN = 0x80 # RFC4122
|
23
27
|
|
24
|
-
|
25
|
-
attr_writer :logger
|
26
|
-
|
27
|
-
attr_reader :logger
|
28
|
+
module_function
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
def logger
|
31
|
+
@logger if defined?(@logger)
|
32
|
+
end
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
+
def logger=(value)
|
35
|
+
@logger = value
|
36
|
+
end
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
+
def log(severity, prog = nil, &block)
|
39
|
+
return if logger.nil?
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
major = version_number / 1_000_000
|
42
|
-
minor = (version_number - major * 1_000_000) / 1_000
|
43
|
-
release = version_number - major * 1_000_000 - minor * 1_000
|
44
|
-
"#{major}.#{minor}.#{release}"
|
45
|
-
end
|
41
|
+
logger.public_send(severity, prog, &block)
|
42
|
+
end
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# @raise ArgumentError
|
51
|
-
def parse_enum(enum, value)
|
52
|
-
if value.is_a?(Symbol)
|
53
|
-
raise ArgumentError, 'invalid enum value' unless enum.symbols.include?(value)
|
44
|
+
def library_path
|
45
|
+
%w[libvirt libvirt.so.0]
|
46
|
+
end
|
54
47
|
|
55
|
-
|
56
|
-
|
48
|
+
# @param [Integer] version_number ulong
|
49
|
+
def parse_version(version_number)
|
50
|
+
major = version_number / 1_000_000
|
51
|
+
minor = (version_number - major * 1_000_000) / 1_000
|
52
|
+
release = version_number - major * 1_000_000 - minor * 1_000
|
53
|
+
"#{major}.#{minor}.#{release}"
|
54
|
+
end
|
57
55
|
|
58
|
-
|
56
|
+
# @param enum [FFI::Enum]
|
57
|
+
# @param value [Symbol, Integer]
|
58
|
+
# @return [Array] event_id, event_id_sym
|
59
|
+
# @raise ArgumentError
|
60
|
+
def parse_enum(enum, value)
|
61
|
+
if value.is_a?(Symbol)
|
62
|
+
raise ArgumentError, 'invalid enum value' unless enum.symbols.include?(value)
|
59
63
|
|
60
|
-
[value,
|
64
|
+
return [enum.find(value), value]
|
61
65
|
end
|
62
66
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
67
|
+
raise ArgumentError, 'invalid enum value' unless enum.symbol_map.values.include?(value)
|
68
|
+
|
69
|
+
[value, enum.symbol_map[value]]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Bitwise OR integer flags calculation for C language.
|
73
|
+
# @param flags [Integer,Symbol,Array<Symbol>,Hash{Symbol=>Boolean},nil]
|
74
|
+
# @param enum [FFI::Enum]
|
75
|
+
# @param default [Integer] optional (default 0x0)
|
76
|
+
# @return [Integer] bitwise OR of keys
|
77
|
+
# @example Usage:
|
78
|
+
# parse_flags(nil, enum)
|
79
|
+
# parse_flags({MANAGED_SAVE: true, SNAPSHOTS_METADATA: true, NVRAM: false}, enum)
|
80
|
+
# parse_flags({managed_save: true, snapshots_metadata: true, keep_nvram: nil}, enum)
|
81
|
+
# parse_flags(3, enum)
|
82
|
+
# parse_flags([:MANAGED_SAVE, :SNAPSHOTS_METADATA], enum)
|
83
|
+
# parse_flags([:managed_save, :snapshots_metadata], enum)
|
84
|
+
#
|
85
|
+
def parse_flags(flags, enum, default: 0x0)
|
86
|
+
flags = default if flags.nil?
|
87
|
+
flags = enum[flags] if flags.is_a?(Symbol)
|
88
|
+
return flags if flags.is_a?(Integer)
|
89
|
+
|
90
|
+
result = 0x0
|
91
|
+
flags = flags.select { |_, v| v }.keys if flags.is_a?(Hash)
|
92
|
+
|
93
|
+
raise ArgumentError, 'flags must be an Integer or a Hash or an Array' unless flags.is_a?(Array)
|
94
|
+
|
95
|
+
flags.each do |key|
|
96
|
+
result |= enum[key.to_s.upcase.to_sym]
|
91
97
|
end
|
92
98
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
99
|
+
result
|
100
|
+
end
|
101
|
+
|
102
|
+
# @param value [Integer,String]
|
103
|
+
# @param unit [String,Symbol] default 'bytes'
|
104
|
+
# @return [Integer] memory in bytes
|
105
|
+
def parse_memory(value, unit)
|
106
|
+
unit ||= 'bytes'
|
107
|
+
multiplier = UNIT_TO_BYTES.fetch(unit.to_sym)
|
108
|
+
Integer(value) * multiplier
|
109
|
+
end
|
110
|
+
|
111
|
+
def define_finalizer(object, &block)
|
112
|
+
free = ->(obj_id) do
|
113
|
+
obj_id_hex = "0x#{obj_id.to_s(16)}"
|
114
|
+
ptr = object.to_ptr
|
115
|
+
ptr_hex = "0x#{ptr.address.to_s(16)}"
|
116
|
+
klass = object.class
|
117
|
+
dbg { "Finalize #{klass} object_id=#{obj_id_hex}, pointer=#{ptr_hex}" }
|
118
|
+
return if ptr.null?
|
119
|
+
|
120
|
+
cl_result = block.call(ptr)
|
121
|
+
err { "Couldn't close #{klass} object_id=#{obj_id_hex}, pointer=#{ptr_hex}" } if cl_result.negative?
|
100
122
|
end
|
123
|
+
ObjectSpace.define_finalizer(object, free)
|
101
124
|
end
|
102
125
|
end
|
103
126
|
end
|
data/lib/libvirt/version.rb
CHANGED
data/lib/libvirt/xml/generic.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
module Libvirt
|
4
4
|
module Xml
|
5
5
|
class Generic
|
6
|
+
TRUE_VALUES = %w[yes on].freeze
|
7
|
+
FALSE_VALUES = %w[no off].freeze
|
8
|
+
|
6
9
|
class_attribute :_root_path, instance_writer: false, default: '.'
|
7
10
|
class_attribute :_attributes_opts, instance_writer: false, default: {}
|
8
11
|
|
@@ -23,7 +26,7 @@ module Libvirt
|
|
23
26
|
attr_accessor(*names)
|
24
27
|
end
|
25
28
|
|
26
|
-
def self.attribute(name, options
|
29
|
+
def self.attribute(name, **options)
|
27
30
|
_attributes_opts.merge!(name.to_sym => options.dup)
|
28
31
|
attr_accessor name
|
29
32
|
end
|
@@ -38,7 +41,7 @@ module Libvirt
|
|
38
41
|
# Build xml object with attributes.
|
39
42
|
# @param attrs [Hash]
|
40
43
|
# @return [Xml::Base]
|
41
|
-
def self.build(attrs
|
44
|
+
def self.build(**attrs)
|
42
45
|
xml_node = Nokogiri::XML(nil)
|
43
46
|
obj = new(xml_node)
|
44
47
|
attrs.each { |key, val| obj.public_send("#{key}=", val) }
|
@@ -111,7 +114,7 @@ module Libvirt
|
|
111
114
|
# @param opts [Hash{Symbol=>Object}]
|
112
115
|
# @return [Object, nil]
|
113
116
|
def decode(value, opts)
|
114
|
-
return if value.nil?
|
117
|
+
return opts[:default] if value.nil?
|
115
118
|
|
116
119
|
cast = opts[:cast]
|
117
120
|
return value if cast.nil?
|
@@ -144,9 +147,9 @@ module Libvirt
|
|
144
147
|
def decode_bool(value, _opts)
|
145
148
|
return value if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
146
149
|
|
147
|
-
return true if value
|
150
|
+
return true if TRUE_VALUES.include?(value)
|
148
151
|
|
149
|
-
return false if value
|
152
|
+
return false if FALSE_VALUES.include?(value)
|
150
153
|
|
151
154
|
nil
|
152
155
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Libvirt
|
4
|
+
module Xml
|
5
|
+
class Interface < Generic
|
6
|
+
# no official doc found
|
7
|
+
#
|
8
|
+
# <interface type='ethernet' name='lo'>
|
9
|
+
# <protocol family='ipv4'>
|
10
|
+
# <ip address='127.0.0.1' prefix='8'/>
|
11
|
+
# </protocol>
|
12
|
+
# <protocol family='ipv6'>
|
13
|
+
# <ip address='::1' prefix='128'/>
|
14
|
+
# </protocol>
|
15
|
+
# <link state='unknown'/>
|
16
|
+
# </interface>
|
17
|
+
#
|
18
|
+
# <interface type='bridge'>
|
19
|
+
# <mac address='52:54:00:4f:7e:b2'/>
|
20
|
+
# <source bridge='vbr107'/>
|
21
|
+
# <target dev='vnet4'/>
|
22
|
+
# <model type='virtio'/>
|
23
|
+
# <alias name='net0'/>
|
24
|
+
# <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
|
25
|
+
# </interface>
|
26
|
+
|
27
|
+
root_path './interface'
|
28
|
+
|
29
|
+
attribute :type, type: :attr
|
30
|
+
|
31
|
+
attribute :name, type: :attr
|
32
|
+
attribute :link_state, type: :attr, path: './link', name: 'state'
|
33
|
+
attribute :ip_addresses, type: :ip_addresses
|
34
|
+
|
35
|
+
attribute :mac_address, type: :attr, path: './mac', name: 'address'
|
36
|
+
attribute :source_bridge, type: :attr, path: './source', name: 'bridge'
|
37
|
+
attribute :target_dev, type: :attr, path: './target', name: 'dev'
|
38
|
+
attribute :model_type, type: :attr, path: './model', name: 'type'
|
39
|
+
attribute :alias_names, type: :attr, path: './alias', name: 'name', array: true
|
40
|
+
attribute :addresses, type: :addresses
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def parse_node_addresses(_, _opts)
|
45
|
+
nodes = find_nodes(nil, path: './address')
|
46
|
+
|
47
|
+
nodes.map do |node|
|
48
|
+
{
|
49
|
+
type: node['type'],
|
50
|
+
domain: node['domain'],
|
51
|
+
bus: node['bus'],
|
52
|
+
slot: node['slot'],
|
53
|
+
function: node['function']
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_node_ip_addresses(_, _opts)
|
59
|
+
protocols = find_nodes(nil, path: './protocol')
|
60
|
+
ip_addresses = []
|
61
|
+
|
62
|
+
protocols.each do |protocol|
|
63
|
+
family = protocol['family']
|
64
|
+
|
65
|
+
protocol.xpath('./ip').each do |ip|
|
66
|
+
# ip['netmask'], ip['localPtr']
|
67
|
+
ip_addresses.push(
|
68
|
+
address: ip['address'],
|
69
|
+
prefix: ip['prefix'],
|
70
|
+
family: family
|
71
|
+
)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
ip_addresses
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Libvirt
|
4
|
+
module Xml
|
5
|
+
class IpAddress < Generic
|
6
|
+
# https://libvirt.org/formatnetwork.html#elementsAddress
|
7
|
+
|
8
|
+
# <ip address="192.168.122.1" netmask="255.255.255.0" localPtr="yes">
|
9
|
+
# <dhcp>
|
10
|
+
# <range start="192.168.122.100" end="192.168.122.254"/>
|
11
|
+
# <host mac="00:16:3e:77:e2:ed" name="foo.example.com" ip="192.168.122.10"/>
|
12
|
+
# <host mac="00:16:3e:3e:a9:1a" name="bar.example.com" ip="192.168.122.11"/>
|
13
|
+
# </dhcp>
|
14
|
+
# </ip>
|
15
|
+
# <ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" localPtr="yes"/>
|
16
|
+
attribute :address, type: :attr
|
17
|
+
attribute :netmask, type: :attr
|
18
|
+
attribute :prefix, type: :attr
|
19
|
+
attribute :local_ptr, type: :attr, name: 'localPtr', cast: :bool, default: false
|
20
|
+
attribute :family, type: :attr, default: 'ipv4'
|
21
|
+
attribute :tftp_root, type: :attr, path: './tftp', name: 'root'
|
22
|
+
attribute :dhcp_ranges, type: :dhcp_ranges
|
23
|
+
attribute :dhcp_hosts, type: :dhcp_hosts
|
24
|
+
attribute :dhcp_bootp_file, type: :attr, path: './dhcp/bootp', name: 'file'
|
25
|
+
attribute :dhcp_bootp_server, type: :attr, path: './dhcp/bootp', name: 'server'
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def parse_node_dhcp_ranges(_, _opts)
|
30
|
+
nodes = find_nodes(nil, path: './dhcp/range')
|
31
|
+
|
32
|
+
nodes.map do |node|
|
33
|
+
[node['start'], node['end']]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_node_dhcp_hosts(_, _opts)
|
38
|
+
nodes = find_nodes(nil, path: './dhcp/host')
|
39
|
+
|
40
|
+
nodes.map do |node|
|
41
|
+
{
|
42
|
+
mac: node['mac'],
|
43
|
+
ip: node['ip'],
|
44
|
+
name: node['name'],
|
45
|
+
host: node['host']
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|