1 diff -ruN a/lib/puppet/provider/network_config/interfaces.rb b/lib/puppet/provider/network_config/interfaces.rb
2 --- a/lib/puppet/provider/network_config/interfaces.rb 2020-04-14 15:30:26.488316830 +0800
3 +++ b/lib/puppet/provider/network_config/interfaces.rb 2020-04-14 15:30:11.388316418 +0800
5 desc "Debian interfaces style provider"
7 confine :osfamily => :debian
8 - defaultfor :osfamily => :debian
9 + defaultfor :operatingsystem => [:debian, :ubuntu]
11 has_feature :provider_options
12 has_feature :hotpluggable
13 diff -ruN a/lib/puppet/provider/network_config/poky-stx.rb b/lib/puppet/provider/network_config/poky-stx.rb
14 --- a/lib/puppet/provider/network_config/poky-stx.rb 1970-01-01 08:00:00.000000000 +0800
15 +++ b/lib/puppet/provider/network_config/poky-stx.rb 2020-04-15 15:40:31.266687901 +0800
17 +require 'puppetx/filemapper'
19 +Puppet::Type.type(:network_config).provide(:pokystx) do
20 + # Wind River Linux network_config interfaces provider.
22 + # This provider uses the filemapper mixin to map the interfaces file to a
23 + # collection of network_config providers, and back.
25 + include PuppetX::FileMapper
27 + desc "Poky starlingX interfaces style provider"
29 + defaultfor :operatingsystem => :'poky-stx'
31 + has_feature :provider_options
32 + has_feature :hotpluggable
35 + '/var/run/interfaces.puppet'
38 + def self.target_files
39 + ['/var/run/interfaces.puppet']
42 + class MalformedInterfacesError < Puppet::Error
43 + def initialize(msg = nil)
44 + msg = 'Malformed poky-stx interfaces file; cannot instantiate network_config resources' if msg.nil?
49 + def self.raise_malformed
51 + raise MalformedInterfacesError
59 + attr_accessor :onboot, :hotplug
62 + # These fields are going to get rearranged to resolve issue 16
63 + # https://github.com/adrienthebo/puppet-network/issues/16
64 + attr_accessor :ipaddress, :netmask, :family, :method, :mtu
67 + attr_reader :options
69 + def initialize(name)
72 + @options = Hash.new {|hash, key| hash[key] = []}
79 + :hotplug => @hotplug,
80 + :ipaddress => @ipaddress,
81 + :netmask => @netmask,
85 + :options => squeeze_options
88 + h.inject({}) do |hash, (key, val)|
89 + hash[key] = val unless val.nil?
95 + @options.inject({}) do |hash, (key, value)|
97 + hash[key] = value.pop
112 + # @return [Array<Instance>] All class instances
119 + if all_instances[name]
120 + obj = all_instances[name]
122 + obj = self.new(name)
123 + all_instances[name] = obj
131 + def self.parse_file(filename, contents)
132 + # Debian has a very irregular format for the interfaces file. The
133 + # parse_file method is somewhat derived from the ifup executable
134 + # supplied in the debian ifupdown package. The source can be found at
135 + # http://packages.debian.org/squeeze/ifupdown
138 + # The debian interfaces implementation requires global state while parsing
139 + # the file; namely, the stanza being parsed as well as the interface being
142 + current_interface = nil
144 + lines = contents.split("\n")
145 + # TODO Join lines that end with a backslash
147 + # Iterate over all lines and determine what attributes they create
148 + lines.each do |line|
150 + # Strip off any trailing comments
151 + line.sub!(/#.*$/, '')
155 + # Ignore comments and blank lines
158 + when /^auto|^allow-auto/
159 + # Parse out any auto sections
160 + interfaces = line.split(' ')
161 + interfaces.delete_at(0)
163 + interfaces.each do |name|
164 + Instance[name].onboot = true
167 + # Reset the current parse state
168 + current_interface = nil
170 + when /^allow-hotplug/
171 + # parse out allow-hotplug lines
173 + interfaces = line.split(' ')
174 + interfaces.delete_at(0)
176 + interfaces.each do |name|
177 + Instance[name].hotplug = true
180 + # Don't reset Reset the current parse state
183 + # Format of the iface line:
185 + # iface <iface> <family> <method>
186 + # zero or more options for <iface>
188 + if match = line.match(/^iface\s+(\S+)\s+(\S+)\s+(\S+)/)
193 + # If an iface block for this interface has been seen, the file is
195 + raise_malformed if Instance[name] and Instance[name].family
198 + current_interface = name
200 + # This is done automatically
201 + #Instance[name].name = name
202 + Instance[name].family = family
203 + Instance[name].method = method
206 + # If we match on a string with a leading iface, but it isn't in the
207 + # expected format, malformed blar blar
214 + raise Puppet::DevError, "Debian interfaces mapping parsing not implemented."
218 + # We're currently examining a line that is within a mapping or iface
219 + # stanza, so we need to validate the line and add the options it
220 + # specifies to the known state of the interface.
224 + if match = line.match(/(\S+)\s+(\S.*)/)
225 + # If we're parsing an iface stanza, then we should receive a set of
226 + # lines that contain two or more space delimited strings. Append
227 + # them as options to the iface in an array.
232 + name = current_interface
235 + when 'address'; Instance[name].ipaddress = val
236 + when 'netmask'; Instance[name].netmask = val
237 + when 'mtu'; Instance[name].mtu = val
238 + else Instance[name].options[key] << val
244 + raise Puppet::DevError, "Debian interfaces mapping parsing not implemented."
251 + Instance.all_instances.map {|name, instance| instance.to_hash }
254 + # Generate an array of sections
255 + def self.format_file(filename, providers)
259 + # Add onboot interfaces
260 + if (auto_interfaces = providers.select {|provider| provider.onboot == true })
262 + stanza << "auto " + auto_interfaces.map(&:name).sort.join(" ")
263 + contents << stanza.join("\n")
266 + # Build iface stanzas
267 + providers.sort_by(&:name).each do |provider|
268 + # TODO add validation method
269 + raise Puppet::Error, "#{provider.name} does not have a method." if provider.method.nil?
270 + raise Puppet::Error, "#{provider.name} does not have a family." if provider.family.nil?
273 + if provider.method == :static and (not provider.ipaddress or provider.ipaddress == :absent)
274 + stanza << %{iface #{provider.name} #{provider.family} manual}
276 + stanza << %{iface #{provider.name} #{provider.family} #{provider.method}}
280 + [:ipaddress, 'address'],
281 + [:netmask, 'netmask'],
282 + [:gateway, 'gateway'],
284 + ].each do |(property, section)|
285 + stanza << " #{section} #{provider.send property}" if provider.send(property) and provider.send(property) != :absent
288 + if provider.options and provider.options != :absent
289 + provider.options.each_pair do |key_f, val|
290 + key = key_f.gsub('_', '-')
291 + if ['pre-up', 'up', 'post-up', 'down', 'pre-down', 'post-down'].include? key
292 + if val.is_a? String
293 + stanza << " #{key} #{val}"
294 + elsif val.is_a? Array
295 + val.each { |entry| stanza << " #{key} #{entry}" }
297 + raise Puppet::Error, "#{self} options key #{key} expects a String or Array, got #{val.class}"
301 + if val.is_a? String
302 + stanza << " #{val}"
304 + raise Puppet::Error, "#{self} options key #{key} expects a String, got #{val.class}"
310 + contents << stanza.join("\n")
313 + contents.map {|line| line + "\n\n"}.join
318 +# HEADER: This file is is being managed by puppet. Changes to
319 +# HEADER: interfaces that are not being managed by puppet will persist;
320 +# HEADER: however changes to interfaces that are being managed by puppet will
321 +# HEADER: be overwritten. In addition, file order is NOT guaranteed.
322 +# HEADER: Last generated at: #{Time.now}