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.
- checksums.yaml +4 -4
- data/.rubocop.yml +78 -0
- data/Gemfile +7 -2
- data/Rakefile +6 -1
- data/bin/console +1 -0
- data/exe/libvirt +1 -0
- data/lib/libvirt.rb +14 -13
- data/lib/libvirt/base_info.rb +34 -0
- data/lib/libvirt/connection.rb +156 -47
- data/lib/libvirt/domain.rb +136 -8
- data/lib/libvirt/domain_callback_storage.rb +69 -0
- data/lib/libvirt/errors.rb +65 -0
- data/lib/libvirt/event.rb +60 -38
- data/lib/libvirt/ffi.rb +17 -0
- data/lib/libvirt/ffi/common.rb +8 -1
- data/lib/libvirt/ffi/domain.rb +796 -69
- data/lib/libvirt/ffi/error.rb +243 -0
- data/lib/libvirt/ffi/event.rb +30 -36
- data/lib/libvirt/ffi/helpers.rb +17 -0
- data/lib/libvirt/ffi/host.rb +122 -0
- data/lib/libvirt/ffi/storage.rb +149 -0
- data/lib/libvirt/ffi/stream.rb +74 -0
- data/lib/libvirt/node_info.rb +2 -41
- data/lib/libvirt/storage_pool.rb +70 -0
- data/lib/libvirt/storage_pool_info.rb +7 -0
- data/lib/libvirt/storage_volume.rb +51 -0
- data/lib/libvirt/storage_volume_info.rb +7 -0
- data/lib/libvirt/stream.rb +124 -0
- data/lib/libvirt/util.rb +75 -8
- data/lib/libvirt/version.rb +1 -1
- data/lib/libvirt/xml.rb +23 -0
- data/lib/libvirt/xml/disk.rb +59 -0
- data/lib/libvirt/xml/domain.rb +76 -0
- data/lib/libvirt/xml/generic.rb +252 -0
- data/lib/libvirt/xml/graphics.rb +14 -0
- data/lib/libvirt/xml/max_vcpu.rb +12 -0
- data/lib/libvirt/xml/memory.rb +14 -0
- data/lib/libvirt/xml/storage_pool.rb +24 -0
- data/lib/libvirt/xml/storage_volume.rb +32 -0
- data/lib/libvirt/xml/vcpu.rb +12 -0
- data/lib/libvirt_ffi.rb +2 -0
- data/libvirt.gemspec +5 -1
- data/test_usage/support/libvirt_async.rb +33 -31
- data/test_usage/support/log_formatter.rb +5 -10
- data/test_usage/test_domain.rb +43 -0
- data/test_usage/test_event_loop.rb +134 -33
- data/test_usage/test_libvirtd_restart.rb +63 -0
- data/test_usage/test_metadata.rb +104 -0
- data/test_usage/test_screenshot.rb +197 -0
- data/test_usage/test_storage.rb +52 -0
- metadata +46 -6
- data/lib/libvirt/error.rb +0 -6
- data/lib/libvirt/ffi/connection.rb +0 -84
- data/lib/libvirt/ffi/libvirt.rb +0 -17
- data/lib/libvirt/ffi/node_info.rb +0 -37
data/lib/libvirt/util.rb
CHANGED
@@ -2,23 +2,36 @@
|
|
2
2
|
|
3
3
|
module Libvirt
|
4
4
|
module Util
|
5
|
+
UNIT_TO_BYTES = {
|
6
|
+
b: 1,
|
7
|
+
bytes: 1,
|
8
|
+
KB: 1_000,
|
9
|
+
KiB: 1_024,
|
10
|
+
k: 1_024,
|
11
|
+
MB: 1_000_000,
|
12
|
+
M: 1_048_576,
|
13
|
+
MiB: 1_048_576,
|
14
|
+
GB: 1_000_000_000,
|
15
|
+
G: 1_073_741_824,
|
16
|
+
GiB: 1_073_741_824,
|
17
|
+
TB: 1_000_000_000_000,
|
18
|
+
T: 1_099_511_627_776,
|
19
|
+
TiB: 1_099_511_627_776
|
20
|
+
}.freeze
|
21
|
+
|
5
22
|
class << self
|
23
|
+
attr_writer :logger
|
6
24
|
|
7
|
-
|
8
|
-
@logger = logger
|
9
|
-
end
|
10
|
-
|
11
|
-
def logger
|
12
|
-
@logger
|
13
|
-
end
|
25
|
+
attr_reader :logger
|
14
26
|
|
15
27
|
def log(severity, prog = nil, &block)
|
16
28
|
return if @logger.nil?
|
29
|
+
|
17
30
|
@logger.public_send(severity, prog, &block)
|
18
31
|
end
|
19
32
|
|
20
33
|
def library_path
|
21
|
-
%w
|
34
|
+
%w[libvirt libvirt.so.0]
|
22
35
|
end
|
23
36
|
|
24
37
|
# @param [Integer] version_number ulong
|
@@ -29,6 +42,60 @@ module Libvirt
|
|
29
42
|
"#{major}.#{minor}.#{release}"
|
30
43
|
end
|
31
44
|
|
45
|
+
# @param enum [FFI::Enum]
|
46
|
+
# @param value [Symbol, Integer]
|
47
|
+
# @return [Array] event_id, event_id_sym
|
48
|
+
# @raise ArgumentError
|
49
|
+
def parse_enum(enum, value)
|
50
|
+
if value.is_a?(Symbol)
|
51
|
+
raise ArgumentError, 'invalid enum value' unless enum.symbols.include?(value)
|
52
|
+
|
53
|
+
return [enum.find(value), value]
|
54
|
+
end
|
55
|
+
|
56
|
+
raise ArgumentError, 'invalid enum value' unless enum.symbol_map.values.include?(value)
|
57
|
+
|
58
|
+
[value, enum.symbol_map[value]]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Bitwise OR integer flags calculation for C language.
|
62
|
+
# @param flags [Integer,Symbol,Array<Symbol>,Hash{Symbol=>Boolean},nil]
|
63
|
+
# @param enum [FFI::Enum]
|
64
|
+
# @param default [Integer] optional (default 0x0)
|
65
|
+
# @return [Integer] bitwise OR of keys
|
66
|
+
# @example Usage:
|
67
|
+
# parse_flags(nil, enum)
|
68
|
+
# parse_flags({MANAGED_SAVE: true, SNAPSHOTS_METADATA: true, NVRAM: false}, enum)
|
69
|
+
# parse_flags({managed_save: true, snapshots_metadata: true, keep_nvram: nil}, enum)
|
70
|
+
# parse_flags(3, enum)
|
71
|
+
# parse_flags([:MANAGED_SAVE, :SNAPSHOTS_METADATA], enum)
|
72
|
+
# parse_flags([:managed_save, :snapshots_metadata], enum)
|
73
|
+
#
|
74
|
+
def parse_flags(flags, enum, default: 0x0)
|
75
|
+
flags = default if flags.nil?
|
76
|
+
flags = enum[flags] if flags.is_a?(Symbol)
|
77
|
+
return flags if flags.is_a?(Integer)
|
78
|
+
|
79
|
+
result = 0x0
|
80
|
+
flags = flags.select { |_, v| v }.keys if flags.is_a?(Hash)
|
81
|
+
|
82
|
+
raise ArgumentError, 'flags must be an Integer or a Hash or an Array' unless flags.is_a?(Array)
|
83
|
+
|
84
|
+
flags.each do |key|
|
85
|
+
result |= enum[key.to_s.upcase.to_sym]
|
86
|
+
end
|
87
|
+
|
88
|
+
result
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param value [Integer,String]
|
92
|
+
# @param unit [String,Symbol] default 'bytes'
|
93
|
+
# @return [Integer] memory in bytes
|
94
|
+
def parse_memory(value, unit)
|
95
|
+
unit ||= 'bytes'
|
96
|
+
multiplier = UNIT_TO_BYTES.fetch(unit.to_sym)
|
97
|
+
Integer(value) * multiplier
|
98
|
+
end
|
32
99
|
end
|
33
100
|
end
|
34
101
|
end
|
data/lib/libvirt/version.rb
CHANGED
data/lib/libvirt/xml.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'libvirt/util'
|
5
|
+
|
6
|
+
module Libvirt
|
7
|
+
module Xml
|
8
|
+
# https://libvirt.org/format.html
|
9
|
+
# namespace for libvirt xml objects.
|
10
|
+
# does not loaded by default.
|
11
|
+
# requires nokogiri.
|
12
|
+
|
13
|
+
require 'libvirt/xml/generic'
|
14
|
+
require 'libvirt/xml/storage_pool'
|
15
|
+
require 'libvirt/xml/storage_volume'
|
16
|
+
require 'libvirt/xml/memory'
|
17
|
+
require 'libvirt/xml/graphics'
|
18
|
+
require 'libvirt/xml/disk'
|
19
|
+
require 'libvirt/xml/max_vcpu'
|
20
|
+
require 'libvirt/xml/vcpu'
|
21
|
+
require 'libvirt/xml/domain'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Libvirt
|
4
|
+
module Xml
|
5
|
+
class Disk < Generic
|
6
|
+
# https://libvirt.org/formatdomain.html#elementsDisks
|
7
|
+
|
8
|
+
attribute :type, type: :attr
|
9
|
+
attribute :device, type: :attr
|
10
|
+
attribute :model, type: :attr
|
11
|
+
attribute :raw_io, type: :attr, name: :rawio, cast: :bool
|
12
|
+
attribute :sg_io, type: :attr, name: :sgio
|
13
|
+
attribute :snapshot, type: :attr
|
14
|
+
attribute :source_file, name: :file, path: './source', type: :attr
|
15
|
+
attribute :source_dev, name: :dev, path: './source', type: :attr
|
16
|
+
attribute :source_dir, name: :dir, path: './source', type: :attr
|
17
|
+
attribute :source_protocol, name: :protocol, path: './source', type: :attr
|
18
|
+
attribute :source_pool, name: :pool, path: './source', type: :attr
|
19
|
+
attribute :source_volume, name: :volume, path: './source', type: :attr
|
20
|
+
attribute :source_mode, name: :mode, path: './source', type: :attr
|
21
|
+
attribute :source_name, name: :name, path: './source', type: :attr
|
22
|
+
attribute :source_type, name: :type, path: './source', type: :attr
|
23
|
+
attribute :source_managed, name: :managed, path: './source', type: :attr, cast: :bool
|
24
|
+
attribute :source_namespace, name: :namespace, path: './source', type: :attr
|
25
|
+
attribute :source_index, name: :index, path: './source', type: :attr
|
26
|
+
attribute :source_host_name, name: :name, path: './source/host', type: :attr
|
27
|
+
attribute :source_host_port, name: :port, path: './source/host', type: :attr
|
28
|
+
attribute :source_host_transport, name: :transport, path: './source/host', type: :attr
|
29
|
+
attribute :source_host_socket, name: :socket, path: './source/host', type: :attr
|
30
|
+
attribute :source_snapshot_name, name: :name, path: './source/snapshot', type: :attr
|
31
|
+
attribute :source_config_file, name: :file, path: './source/config', type: :attr
|
32
|
+
# TODO: source/auth
|
33
|
+
# TODO: source/encryption
|
34
|
+
# TODO: source/reservations
|
35
|
+
# TODO: source/initiator
|
36
|
+
# TODO: source/address
|
37
|
+
# TODO: source/slices
|
38
|
+
# TODO: backingStore
|
39
|
+
# TODO: mirror
|
40
|
+
# TODO: target
|
41
|
+
# TODO: iotune
|
42
|
+
# TODO: driver
|
43
|
+
# TODO: backenddomain
|
44
|
+
# TODO: boot
|
45
|
+
# TODO: encryption
|
46
|
+
# TODO: readonly
|
47
|
+
# TODO: shareable
|
48
|
+
# TODO: transient
|
49
|
+
# TODO: serial
|
50
|
+
# TODO: wwn
|
51
|
+
# TODO: vendor
|
52
|
+
# TODO: product
|
53
|
+
# TODO: address
|
54
|
+
# TODO: auth
|
55
|
+
# TODO: geometry
|
56
|
+
# TODO: blockio
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Libvirt
|
4
|
+
module Xml
|
5
|
+
class Domain < Generic
|
6
|
+
# https://libvirt.org/formatdomain.html
|
7
|
+
|
8
|
+
root_path './domain'
|
9
|
+
|
10
|
+
attribute :name
|
11
|
+
attribute :uuid
|
12
|
+
attribute :gen_id, path: './genid'
|
13
|
+
attribute :title
|
14
|
+
attribute :description
|
15
|
+
attribute :metadata, type: :raw
|
16
|
+
attribute :vcpu, type: :struct, class: MaxVcpu
|
17
|
+
attribute :vcpus, type: :struct, array: true, class: Vcpu, cast: ->(objects) { objects.sort_by(&:id) }
|
18
|
+
attribute :memory, type: :struct, class: Memory
|
19
|
+
attribute :current_memory, type: :struct, class: Memory
|
20
|
+
attribute :max_memory, type: :struct, class: Memory
|
21
|
+
attribute :resource_partitions, path: './resource/partition', array: true
|
22
|
+
attribute :on_power_off
|
23
|
+
attribute :on_reboot
|
24
|
+
attribute :on_crash
|
25
|
+
attribute :on_lock_failure
|
26
|
+
attribute :device_graphics, type: :struct, path: './devices/graphics', class: Graphics, array: true
|
27
|
+
attribute :device_disks, type: :struct, path: './devices/disk', class: Disk, array: true
|
28
|
+
# https://libvirt.org/formatdomain.html#elementsDevices
|
29
|
+
# todo devices/emulator
|
30
|
+
# todo devices/interface
|
31
|
+
# todo devices/filesystem
|
32
|
+
# todo devices/controller
|
33
|
+
# todo devices/lease
|
34
|
+
# todo devices/hostdev
|
35
|
+
# todo devices/redirdev
|
36
|
+
# todo devices/smartcard
|
37
|
+
# todo devices/input
|
38
|
+
# todo devices/hub
|
39
|
+
# todo devices/video
|
40
|
+
# todo devices/parallel
|
41
|
+
# todo devices/serial
|
42
|
+
# todo devices/console
|
43
|
+
# todo devices/channel
|
44
|
+
# todo devices/sound
|
45
|
+
# todo devices/watchdog
|
46
|
+
# todo devices/memballoon
|
47
|
+
# todo devices/rng
|
48
|
+
# todo devices/tpm
|
49
|
+
# todo devices/nvram
|
50
|
+
# todo devices/panic
|
51
|
+
# todo devices/shmem
|
52
|
+
# todo devices/memory
|
53
|
+
# todo devices/iommu
|
54
|
+
# todo devices/vsock
|
55
|
+
# todo os
|
56
|
+
# todo bootloader
|
57
|
+
# todo bootloader_args
|
58
|
+
# todo sysinfo
|
59
|
+
# todo iothreads
|
60
|
+
# todo iothreadids
|
61
|
+
# todo cputune
|
62
|
+
# todo memoryBacking
|
63
|
+
# todo memtune
|
64
|
+
# todo numatune
|
65
|
+
# todo blkiotune
|
66
|
+
# todo cpu
|
67
|
+
# todo pm
|
68
|
+
# todo features
|
69
|
+
# todo clock
|
70
|
+
# todo perf
|
71
|
+
# todo seclabel
|
72
|
+
# todo keywrap
|
73
|
+
# todo launchSecurity
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,252 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Libvirt
|
4
|
+
module Xml
|
5
|
+
class Generic
|
6
|
+
class_attribute :_root_path, instance_writer: false, default: '.'
|
7
|
+
class_attribute :_attributes_opts, instance_writer: false, default: {}
|
8
|
+
|
9
|
+
def self.inherited(subclass)
|
10
|
+
subclass._root_path = '.'
|
11
|
+
subclass._attributes_opts = _attributes_opts.dup
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.root_path(path)
|
15
|
+
self._root_path = path
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.attributes(*names)
|
19
|
+
options = names.extract_options!
|
20
|
+
names.each do |name|
|
21
|
+
_attributes_opts.merge!(name.to_sym => options.dup)
|
22
|
+
end
|
23
|
+
attr_accessor(*names)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.attribute(name, options = {})
|
27
|
+
_attributes_opts.merge!(name.to_sym => options.dup)
|
28
|
+
attr_accessor name
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param xml [String]
|
32
|
+
# @return [Class<LibvirtXml::Generic>]
|
33
|
+
def self.load(xml)
|
34
|
+
xml_node = Nokogiri::XML(xml).xpath(_root_path).first
|
35
|
+
new(xml_node)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Build xml object with attributes.
|
39
|
+
# @param attrs [Hash]
|
40
|
+
# @return [Xml::Base]
|
41
|
+
def self.build(attrs = {})
|
42
|
+
xml_node = Nokogiri::XML(nil)
|
43
|
+
obj = new(xml_node)
|
44
|
+
attrs.each { |key, val| obj.public_send("#{key}=", val) }
|
45
|
+
obj
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param xml_node [Nokogiri::XML::Element]
|
49
|
+
def initialize(xml_node)
|
50
|
+
@xml_node = xml_node
|
51
|
+
parse_xml_node
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param attr [Symbol,String]
|
55
|
+
# @return [Object,nil]
|
56
|
+
def [](attr)
|
57
|
+
read_attribute(attr)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param attr [Symbol,String]
|
61
|
+
# @param value [Object,nil]
|
62
|
+
# @return [Object,nil]
|
63
|
+
def []=(attr, value)
|
64
|
+
write_attribute(attr, value)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Hash{Symbol=>(Object,nil)}]
|
68
|
+
def to_h
|
69
|
+
_attributes_opts.map do |name, _opts|
|
70
|
+
value = public_send(name)
|
71
|
+
[name, serialize_for_hash(value)]
|
72
|
+
end.to_h
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [String]
|
76
|
+
def to_xml
|
77
|
+
@xml_node.to_xml
|
78
|
+
end
|
79
|
+
|
80
|
+
delegate :as_json, :to_json, to: :to_h
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def parse_xml_node
|
85
|
+
_attributes_opts.each do |name, opts|
|
86
|
+
value = parse_node(name, opts)
|
87
|
+
value = decode(value, opts)
|
88
|
+
write_attribute name, value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Parse node value using "parse_node_#{type}" method.
|
93
|
+
# @param name [Symbol]
|
94
|
+
# @param opts [Hash{Symbol=>Object}]
|
95
|
+
# @return [Object, nil]
|
96
|
+
def parse_node(name, opts)
|
97
|
+
type = opts[:type] || :text
|
98
|
+
meth = "parse_node_#{type}"
|
99
|
+
|
100
|
+
if opts[:apply]
|
101
|
+
opts[:apply].call(@xml_node, opts)
|
102
|
+
elsif respond_to?(meth, true)
|
103
|
+
send(meth, name, opts)
|
104
|
+
else
|
105
|
+
raise ArgumentError, "Invalid :type option #{type.inspect} for attribute #{name}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Cast value using "decode_#{type}" method.
|
110
|
+
# @param value [String]
|
111
|
+
# @param opts [Hash{Symbol=>Object}]
|
112
|
+
# @return [Object, nil]
|
113
|
+
def decode(value, opts)
|
114
|
+
return if value.nil?
|
115
|
+
|
116
|
+
cast = opts[:cast]
|
117
|
+
return value if cast.nil?
|
118
|
+
|
119
|
+
meth = "decode_#{cast}"
|
120
|
+
|
121
|
+
if opts[:array]
|
122
|
+
value.map do |val|
|
123
|
+
if cast.is_a?(Proc)
|
124
|
+
cast.call(val, opts)
|
125
|
+
elsif respond_to?(meth, true)
|
126
|
+
send(meth, val, opts)
|
127
|
+
else
|
128
|
+
raise ArgumentError, "invalid :cast option #{cast.inspect}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
if cast.is_a?(Proc)
|
134
|
+
cast.call(value, opts)
|
135
|
+
elsif respond_to?(meth, true)
|
136
|
+
send(meth, value, opts)
|
137
|
+
else
|
138
|
+
raise ArgumentError, "invalid :cast option #{cast.inspect}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# @param value [String, Boolean]
|
143
|
+
# @return [Boolean]
|
144
|
+
def decode_bool(value, _opts)
|
145
|
+
return value if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
146
|
+
|
147
|
+
return true if value == 'yes'
|
148
|
+
|
149
|
+
return false if value == 'no'
|
150
|
+
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
|
154
|
+
# @param value [String, Integer]
|
155
|
+
# @return [Integer]
|
156
|
+
# @raise [ArgumentError]
|
157
|
+
def decode_int(value, _opts)
|
158
|
+
Integer(value)
|
159
|
+
end
|
160
|
+
|
161
|
+
def find_nodes(name, opts)
|
162
|
+
value_name = opts[:name]&.to_sym || name
|
163
|
+
path = opts[:path] || "./#{value_name}"
|
164
|
+
path == :root ? [@xml_node] : @xml_node.xpath(path)
|
165
|
+
end
|
166
|
+
|
167
|
+
def parse_node_text(name, opts)
|
168
|
+
nodes = find_nodes(name, opts)
|
169
|
+
|
170
|
+
nodes.map(&:text) if opts[:array]
|
171
|
+
|
172
|
+
node = nodes.first
|
173
|
+
return if node.nil?
|
174
|
+
|
175
|
+
node.text
|
176
|
+
end
|
177
|
+
|
178
|
+
def parse_node_attr(name, opts)
|
179
|
+
nodes = find_nodes name, { path: :root }.merge(opts)
|
180
|
+
value_name = opts[:name]&.to_sym || name
|
181
|
+
|
182
|
+
nodes.map { |node| node[value_name.to_s] } if opts[:array]
|
183
|
+
|
184
|
+
node = nodes.first
|
185
|
+
return if node.nil?
|
186
|
+
|
187
|
+
node[value_name.to_s]
|
188
|
+
end
|
189
|
+
|
190
|
+
def parse_node_struct(name, opts)
|
191
|
+
klass = opts[:class]
|
192
|
+
raise ArgumentError, "Invalid :class option nil for attribute #{name}" if klass.nil?
|
193
|
+
|
194
|
+
nodes = find_nodes(name, opts)
|
195
|
+
|
196
|
+
nodes.map { |node| klass.new(node) } if opts[:array]
|
197
|
+
|
198
|
+
node = nodes.first
|
199
|
+
return if node.nil?
|
200
|
+
|
201
|
+
klass.new(node)
|
202
|
+
end
|
203
|
+
|
204
|
+
def parse_node_raw(name, opts)
|
205
|
+
nodes = find_nodes(name, opts)
|
206
|
+
|
207
|
+
nodes.map(&:to_xml) if opts[:array]
|
208
|
+
|
209
|
+
node = nodes.first
|
210
|
+
return if node.nil?
|
211
|
+
|
212
|
+
node.to_xml
|
213
|
+
end
|
214
|
+
|
215
|
+
def parse_node_memory(name, opts)
|
216
|
+
nodes = find_nodes(name, opts)
|
217
|
+
|
218
|
+
if opts[:array]
|
219
|
+
return [] if nodes.empty?
|
220
|
+
|
221
|
+
nodes.map { |node| Util.parse_memory node.text, node['unit'] }
|
222
|
+
end
|
223
|
+
|
224
|
+
node = nodes.first
|
225
|
+
return if node.nil?
|
226
|
+
|
227
|
+
Util.parse_memory node.text, node['unit']
|
228
|
+
end
|
229
|
+
|
230
|
+
def read_attribute(attr)
|
231
|
+
attr = attr.to_sym
|
232
|
+
raise ArgumentError, "can't find attribute #{attr}" unless _attributes_opts.key?(attr)
|
233
|
+
|
234
|
+
instance_variable_get :"@#{attr}"
|
235
|
+
end
|
236
|
+
|
237
|
+
def write_attribute(attr, value)
|
238
|
+
attr = attr.to_sym
|
239
|
+
raise ArgumentError, "can't find attribute #{attr}" unless _attributes_opts.key?(attr)
|
240
|
+
|
241
|
+
instance_variable_set :"@#{attr}", value
|
242
|
+
end
|
243
|
+
|
244
|
+
def serialize_for_hash(value)
|
245
|
+
return value.to_h if value.is_a?(Generic)
|
246
|
+
return value.map { |val| serialize_for_hash(val) } if value.is_a?(Array)
|
247
|
+
|
248
|
+
value
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|