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.
@@ -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
@@ -13,7 +13,7 @@ module Libvirt
13
13
  @ptr = pointer
14
14
 
15
15
  free = ->(obj_id) do
16
- Util.log(:debug) { "Finalize Libvirt::StoragePool 0x#{obj_id.to_s(16)} @ptr=#{@ptr}," }
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::Domain', &block)
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
- class << self
25
- attr_writer :logger
26
-
27
- attr_reader :logger
28
+ module_function
28
29
 
29
- def log(severity, prog = nil, &block)
30
- return if @logger.nil?
30
+ def logger
31
+ @logger if defined?(@logger)
32
+ end
31
33
 
32
- @logger.public_send(severity, prog, &block)
33
- end
34
+ def logger=(value)
35
+ @logger = value
36
+ end
34
37
 
35
- def library_path
36
- %w[libvirt libvirt.so.0]
37
- end
38
+ def log(severity, prog = nil, &block)
39
+ return if logger.nil?
38
40
 
39
- # @param [Integer] version_number ulong
40
- def parse_version(version_number)
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
- # @param enum [FFI::Enum]
48
- # @param value [Symbol, Integer]
49
- # @return [Array] event_id, event_id_sym
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
- return [enum.find(value), value]
56
- end
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
- raise ArgumentError, 'invalid enum value' unless enum.symbol_map.values.include?(value)
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, enum.symbol_map[value]]
64
+ return [enum.find(value), value]
61
65
  end
62
66
 
63
- # Bitwise OR integer flags calculation for C language.
64
- # @param flags [Integer,Symbol,Array<Symbol>,Hash{Symbol=>Boolean},nil]
65
- # @param enum [FFI::Enum]
66
- # @param default [Integer] optional (default 0x0)
67
- # @return [Integer] bitwise OR of keys
68
- # @example Usage:
69
- # parse_flags(nil, enum)
70
- # parse_flags({MANAGED_SAVE: true, SNAPSHOTS_METADATA: true, NVRAM: false}, enum)
71
- # parse_flags({managed_save: true, snapshots_metadata: true, keep_nvram: nil}, enum)
72
- # parse_flags(3, enum)
73
- # parse_flags([:MANAGED_SAVE, :SNAPSHOTS_METADATA], enum)
74
- # parse_flags([:managed_save, :snapshots_metadata], enum)
75
- #
76
- def parse_flags(flags, enum, default: 0x0)
77
- flags = default if flags.nil?
78
- flags = enum[flags] if flags.is_a?(Symbol)
79
- return flags if flags.is_a?(Integer)
80
-
81
- result = 0x0
82
- flags = flags.select { |_, v| v }.keys if flags.is_a?(Hash)
83
-
84
- raise ArgumentError, 'flags must be an Integer or a Hash or an Array' unless flags.is_a?(Array)
85
-
86
- flags.each do |key|
87
- result |= enum[key.to_s.upcase.to_sym]
88
- end
89
-
90
- result
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
- # @param value [Integer,String]
94
- # @param unit [String,Symbol] default 'bytes'
95
- # @return [Integer] memory in bytes
96
- def parse_memory(value, unit)
97
- unit ||= 'bytes'
98
- multiplier = UNIT_TO_BYTES.fetch(unit.to_sym)
99
- Integer(value) * multiplier
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Libvirt
4
- VERSION = '0.6.1'
4
+ VERSION = '0.8.1'
5
5
  end
@@ -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 == 'yes'
150
+ return true if TRUE_VALUES.include?(value)
148
151
 
149
- return false if value == 'no'
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