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.
@@ -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