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 +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
|