Add initial meta-stx to support StarlingX build
[pti/rtp.git] / meta-stx / recipes-support / puppet / files / puppet-network / puppet-network-Kilo-quilt-changes.patch
1 From 8e14e2e258a8f2f7189ed37c6337c41fbff0362a Mon Sep 17 00:00:00 2001
2 From: Al Bailey <al.bailey@windriver.com>
3 Date: Mon, 6 Jun 2016 17:13:09 -0400
4 Subject: [PATCH] puppet-network Kilo quilt changes
5
6 ---
7  .../lib/puppet/provider/network_config/redhat.rb   |  39 ++-
8  .../lib/puppet/provider/network_config/wrlinux.rb  | 296 +++++++++++++++++++++
9  .../lib/puppet/provider/network_route/wrlinux.rb   | 109 ++++++++
10  .../network/lib/puppet/type/network_config.rb      |   4 +
11  packstack/puppet/modules/network/manifests/bond.pp |  22 ++
12  .../puppet/modules/network/manifests/bond/setup.pp |   2 +
13  .../modules/network/manifests/bond/wrlinux.pp      |  56 ++++
14  7 files changed, 521 insertions(+), 7 deletions(-)
15  create mode 100644 packstack/puppet/modules/network/lib/puppet/provider/network_config/wrlinux.rb
16  create mode 100644 packstack/puppet/modules/network/lib/puppet/provider/network_route/wrlinux.rb
17  create mode 100644 packstack/puppet/modules/network/manifests/bond/wrlinux.pp
18
19 diff --git a/packstack/puppet/modules/network/lib/puppet/provider/network_config/redhat.rb b/packstack/puppet/modules/network/lib/puppet/provider/network_config/redhat.rb
20 index 4b6de7e..758f387 100644
21 --- a/packstack/puppet/modules/network/lib/puppet/provider/network_config/redhat.rb
22 +++ b/packstack/puppet/modules/network/lib/puppet/provider/network_config/redhat.rb
23 @@ -19,7 +19,12 @@ Puppet::Type.type(:network_config).provide(:redhat) do
24    has_feature :provider_options
25  
26    # @return [String] The path to network-script directory on redhat systems
27 -  SCRIPT_DIRECTORY = "/etc/sysconfig/network-scripts"
28 +  # SCRIPT_DIRECTORY = "/etc/sysconfig/network-scripts"
29 +  # WRS: Generate temporary copies.  It will get compared to files under
30 +  # /etc/sysconfig/network-scripts afterward.  Only config that have changed
31 +  # will get replaced.  Don't let puppet directly manage them, else it will
32 +  # trigger un-wanted networking actions (like up/down).
33 +  SCRIPT_DIRECTORY = "/var/run/network-scripts.puppet"
34  
35    # The valid vlan ID range is 0-4095; 4096 is out of range
36    VLAN_RANGE_REGEX = %r[\d{1,3}|40[0-9][0-5]]
37 @@ -35,6 +40,7 @@ Puppet::Type.type(:network_config).provide(:redhat) do
38      :name       => 'DEVICE',
39      :hotplug    => 'HOTPLUG',
40      :mtu        => 'MTU',
41 +    :gateway => 'GATEWAY',
42    }
43  
44    # Map provider instances to files based on their name
45 @@ -60,8 +66,14 @@ Puppet::Type.type(:network_config).provide(:redhat) do
46    #   RedhatProvider.target_files
47    #   # => ['/etc/sysconfig/network-scripts/ifcfg-eth0', '/etc/sysconfig/network-scripts/ifcfg-eth1']
48    def self.target_files(script_dir = SCRIPT_DIRECTORY)
49 -    entries = Dir.entries(script_dir).select {|entry| entry.match SCRIPT_REGEX}
50 -    entries.map {|entry| File.join(SCRIPT_DIRECTORY, entry)}
51 +    entries = []
52 +    if Dir.exists?(SCRIPT_DIRECTORY)
53 +      Dir.foreach(SCRIPT_DIRECTORY) do |item|
54 +        next if not item.match SCRIPT_REGEX
55 +        entries << item
56 +      end
57 +    end
58 +    entries
59    end
60  
61    # Convert a redhat network script into a hash
62 @@ -184,6 +196,8 @@ Puppet::Type.type(:network_config).provide(:redhat) do
63    end
64  
65    def self.format_file(filename, providers)
66 +    Dir.mkdir(SCRIPT_DIRECTORY) unless File.exists?(SCRIPT_DIRECTORY)
67 +
68      if providers.length == 0
69        return ""
70      elsif providers.length > 1
71 @@ -193,11 +207,11 @@ Puppet::Type.type(:network_config).provide(:redhat) do
72      provider = providers[0]
73      props    = {}
74  
75 -    # Map everything to a flat hash
76 -    props = (provider.options || {})
77 +    props = provider.options if provider.options && provider.options != :absent
78  
79 +    # Map everything to a flat hash
80      NAME_MAPPINGS.keys.each do |type_name|
81 -      if (val = provider.send(type_name))
82 +      if (val = provider.send(type_name)) && val != :absent
83          props[type_name] = val
84        end
85      end
86 @@ -214,11 +228,11 @@ Puppet::Type.type(:network_config).provide(:redhat) do
87        str << %{#{key}=#{val}\n}
88      end
89  
90 +    content.prepend(header)
91      content
92    end
93  
94    def self.unmunge(props)
95 -
96      pairs = {}
97  
98      [:onboot, :hotplug].each do |bool_property|
99 @@ -245,6 +259,17 @@ Puppet::Type.type(:network_config).provide(:redhat) do
100      pairs
101    end
102  
103 +  def self.header
104 +    str = <<-HEADER
105 +# HEADER: This file is is being managed by puppet. Changes to
106 +# HEADER: interfaces that are not being managed by puppet will persist;
107 +# HEADER: however changes to interfaces that are being managed by puppet will
108 +# HEADER: be overwritten. In addition, file order is NOT guaranteed.
109 +# HEADER: Last generated at: #{Time.now}
110 +HEADER
111 +    str
112 +  end
113 +
114    def self.post_flush_hook(filename)
115      File.chmod(0644, filename)
116    end
117 diff --git a/packstack/puppet/modules/network/lib/puppet/provider/network_config/wrlinux.rb b/packstack/puppet/modules/network/lib/puppet/provider/network_config/wrlinux.rb
118 new file mode 100644
119 index 0000000..44c645a
120 --- /dev/null
121 +++ b/packstack/puppet/modules/network/lib/puppet/provider/network_config/wrlinux.rb
122 @@ -0,0 +1,296 @@
123 +require 'puppetx/filemapper'
124 +
125 +Puppet::Type.type(:network_config).provide(:wrlinux) do
126 +  # Wind River Linux network_config interfaces provider.
127 +  #
128 +  # This provider uses the filemapper mixin to map the interfaces file to a
129 +  # collection of network_config providers, and back.
130 +  #
131 +  include PuppetX::FileMapper
132 +
133 +  desc "Wind River interfaces style provider"
134 +
135 +  confine    :osfamily => :wrlinux
136 +  defaultfor :osfamily => :wrlinux
137 +
138 +  has_feature :provider_options
139 +  has_feature :hotpluggable
140 +
141 +  def select_file
142 +    '/var/run/interfaces.puppet'
143 +  end
144 +
145 +  def self.target_files
146 +    ['/var/run/interfaces.puppet']
147 +  end
148 +
149 +  class MalformedInterfacesError < Puppet::Error
150 +    def initialize(msg = nil)
151 +      msg = 'Malformed wrlinux interfaces file; cannot instantiate network_config resources' if msg.nil?
152 +      super
153 +    end
154 +  end
155 +
156 +  def self.raise_malformed
157 +    @failed = true
158 +    raise MalformedInterfacesError
159 +  end
160 +
161 +  class Instance
162 +
163 +    attr_reader :name
164 +
165 +    # Booleans
166 +    attr_accessor :onboot, :hotplug
167 +
168 +
169 +    # These fields are going to get rearranged to resolve issue 16
170 +    # https://github.com/adrienthebo/puppet-network/issues/16
171 +    attr_accessor :ipaddress, :netmask, :family, :method, :mtu
172 +
173 +    # Options hash
174 +    attr_reader :options
175 +
176 +    def initialize(name)
177 +      @name = name
178 +
179 +      @options = Hash.new {|hash, key| hash[key] = []}
180 +    end
181 +
182 +    def to_hash
183 +      h = {
184 +        :name      => @name,
185 +        :onboot    => @onboot,
186 +        :hotplug   => @hotplug,
187 +        :ipaddress => @ipaddress,
188 +        :netmask   => @netmask,
189 +        :family    => @family,
190 +        :method    => @method,
191 +        :mtu       => @mtu,
192 +        :options   => squeeze_options
193 +      }
194 +
195 +      h.inject({}) do |hash, (key, val)|
196 +        hash[key] = val unless val.nil?
197 +        hash
198 +      end
199 +    end
200 +
201 +    def squeeze_options
202 +      @options.inject({}) do |hash, (key, value)|
203 +        if value.size <= 1
204 +          hash[key] = value.pop
205 +        else
206 +          hash[key] = value
207 +        end
208 +
209 +      hash
210 +      end
211 +    end
212 +
213 +    class << self
214 +
215 +      def reset!
216 +        @interfaces = {}
217 +      end
218 +
219 +      # @return [Array<Instance>] All class instances
220 +      def all_instances
221 +        @interfaces ||= {}
222 +        @interfaces
223 +      end
224 +
225 +      def [](name)
226 +        if all_instances[name]
227 +          obj = all_instances[name]
228 +        else
229 +          obj = self.new(name)
230 +          all_instances[name] = obj
231 +        end
232 +
233 +        obj
234 +      end
235 +    end
236 +  end
237 +
238 +  def self.parse_file(filename, contents)
239 +    # Debian has a very irregular format for the interfaces file. The
240 +    # parse_file method is somewhat derived from the ifup executable
241 +    # supplied in the debian ifupdown package. The source can be found at
242 +    # http://packages.debian.org/squeeze/ifupdown
243 +
244 +
245 +    # The debian interfaces implementation requires global state while parsing
246 +    # the file; namely, the stanza being parsed as well as the interface being
247 +    # parsed.
248 +    status = :none
249 +    current_interface = nil
250 +
251 +    lines = contents.split("\n")
252 +    # TODO Join lines that end with a backslash
253 +
254 +    # Iterate over all lines and determine what attributes they create
255 +    lines.each do |line|
256 +
257 +      # Strip off any trailing comments
258 +      line.sub!(/#.*$/, '')
259 +
260 +      case line
261 +      when /^\s*#|^\s*$/
262 +        # Ignore comments and blank lines
263 +        next
264 +
265 +      when /^auto|^allow-auto/
266 +        # Parse out any auto sections
267 +        interfaces = line.split(' ')
268 +        interfaces.delete_at(0)
269 +
270 +        interfaces.each do |name|
271 +          Instance[name].onboot = true
272 +        end
273 +
274 +        # Reset the current parse state
275 +        current_interface = nil
276 +
277 +      when /^allow-hotplug/
278 +        # parse out allow-hotplug lines
279 +
280 +        interfaces = line.split(' ')
281 +        interfaces.delete_at(0)
282 +
283 +        interfaces.each do |name|
284 +          Instance[name].hotplug = true
285 +        end
286 +
287 +        # Don't reset Reset the current parse state
288 +      when /^iface/
289 +
290 +        # Format of the iface line:
291 +        #
292 +        # iface <iface> <family> <method>
293 +        # zero or more options for <iface>
294 +
295 +        if match = line.match(/^iface\s+(\S+)\s+(\S+)\s+(\S+)/)
296 +          name   = match[1]
297 +          family = match[2]
298 +          method = match[3]
299 +
300 +          # If an iface block for this interface has been seen, the file is
301 +          # malformed.
302 +          raise_malformed if Instance[name] and Instance[name].family
303 +
304 +          status = :iface
305 +          current_interface = name
306 +
307 +          # This is done automatically
308 +          #Instance[name].name   = name
309 +          Instance[name].family = family
310 +          Instance[name].method = method
311 +
312 +        else
313 +          # If we match on a string with a leading iface, but it isn't in the
314 +          # expected format, malformed blar blar
315 +          raise_malformed
316 +        end
317 +
318 +      when /^mapping/
319 +
320 +        # XXX dox
321 +        raise Puppet::DevError, "Debian interfaces mapping parsing not implemented."
322 +        status = :mapping
323 +
324 +      else
325 +        # We're currently examining a line that is within a mapping or iface
326 +        # stanza, so we need to validate the line and add the options it
327 +        # specifies to the known state of the interface.
328 +
329 +        case status
330 +        when :iface
331 +          if match = line.match(/(\S+)\s+(\S.*)/)
332 +            # If we're parsing an iface stanza, then we should receive a set of
333 +            # lines that contain two or more space delimited strings. Append
334 +            # them as options to the iface in an array.
335 +
336 +            key = match[1]
337 +            val = match[2]
338 +
339 +            name = current_interface
340 +
341 +            case key
342 +            when 'address'; Instance[name].ipaddress    = val
343 +            when 'netmask'; Instance[name].netmask      = val
344 +            when 'mtu';     Instance[name].mtu          = val
345 +            else            Instance[name].options[key] << val
346 +            end
347 +          else
348 +            raise_malformed
349 +          end
350 +        when :mapping
351 +          raise Puppet::DevError, "Debian interfaces mapping parsing not implemented."
352 +        when :none
353 +          raise_malformed
354 +        end
355 +      end
356 +    end
357 +
358 +    Instance.all_instances.map {|name, instance| instance.to_hash }
359 +  end
360 +
361 +  # Generate an array of sections
362 +  def self.format_file(filename, providers)
363 +    contents = []
364 +    contents << header
365 +
366 +    # Add onboot interfaces
367 +    if (auto_interfaces = providers.select {|provider| provider.onboot == true })
368 +      stanza = []
369 +      stanza << "auto " + auto_interfaces.map(&:name).sort.join(" ")
370 +      contents << stanza.join("\n")
371 +    end
372 +
373 +    # Build iface stanzas
374 +    providers.sort_by(&:name).each do |provider|
375 +      # TODO add validation method
376 +      raise Puppet::Error, "#{provider.name} does not have a method." if provider.method.nil?
377 +      raise Puppet::Error, "#{provider.name} does not have a family." if provider.family.nil?
378 +
379 +      stanza = []
380 +      stanza << %{iface #{provider.name} #{provider.family} #{provider.method}}
381 +
382 +      [
383 +        [:ipaddress, 'address'],
384 +        [:netmask,   'netmask'],
385 +        [:mtu,       'mtu'],
386 +      ].each do |(property, section)|
387 +        stanza << "    #{section} #{provider.send property}" if provider.send(property) and provider.send(property) != :absent
388 +      end
389 +
390 +      if provider.options and provider.options != :absent
391 +        provider.options.each_pair do |key, val|
392 +          if val.is_a? String
393 +            stanza << "    #{key} #{val}"
394 +          elsif val.is_a? Array
395 +            val.each { |entry| stanza << "    #{key} #{entry}" }
396 +          else
397 +            raise Puppet::Error, "#{self} options key #{key} expects a String or Array, got #{val.class}"
398 +          end
399 +        end
400 +      end
401 +
402 +      contents << stanza.join("\n")
403 +    end
404 +
405 +    contents.map {|line| line + "\n\n"}.join
406 +  end
407 +
408 +  def self.header
409 +    str = <<-HEADER
410 +# HEADER: This file is is being managed by puppet. Changes to
411 +# HEADER: interfaces that are not being managed by puppet will persist;
412 +# HEADER: however changes to interfaces that are being managed by puppet will
413 +# HEADER: be overwritten. In addition, file order is NOT guaranteed.
414 +# HEADER: Last generated at: #{Time.now}
415 +HEADER
416 +    str
417 +  end
418 +end
419 diff --git a/packstack/puppet/modules/network/lib/puppet/provider/network_route/wrlinux.rb b/packstack/puppet/modules/network/lib/puppet/provider/network_route/wrlinux.rb
420 new file mode 100644
421 index 0000000..d3fa7b5
422 --- /dev/null
423 +++ b/packstack/puppet/modules/network/lib/puppet/provider/network_route/wrlinux.rb
424 @@ -0,0 +1,109 @@
425 +require 'ipaddr'
426 +require 'puppetx/filemapper'
427 +
428 +Puppet::Type.type(:network_route).provide(:wrlinux) do
429 +  # Wind River Linux network_route routes provider.
430 +  #
431 +  # This provider uses the filemapper mixin to map the routes file to a
432 +  # collection of network_route providers, and back.
433 +  #
434 +  include PuppetX::FileMapper
435 +
436 +  desc "Wind River routes style provider"
437 +
438 +  confine    :osfamily => :wrlinux
439 +
440 +  # $ dpkg -S /etc/network/if-up.d/20static-routes
441 +  # ifupdown-extra: /etc/network/if-up.d/20static-routes
442 +  confine    :exists   => '/etc/network/if-up.d/20static-routes'
443 +
444 +  defaultfor :osfamily => :wrlinux
445 +
446 +  has_feature :provider_options
447 +
448 +  def select_file
449 +    '/etc/network/routes'
450 +  end
451 +
452 +  def self.target_files
453 +    ['/etc/network/routes']
454 +  end
455 +
456 +  class MalformedRoutesError < Puppet::Error
457 +    def initialize(msg = nil)
458 +      msg = 'Malformed wrlinux routes file; cannot instantiate network_route resources' if msg.nil?
459 +      super
460 +    end
461 +  end
462 +
463 +  def self.raise_malformed
464 +    @failed = true
465 +    raise MalformedRoutesError
466 +  end
467 +
468 +  def self.parse_file(filename, contents)
469 +    # Build out an empty hash for new routes for storing their configs.
470 +    route_hash = Hash.new do |hash, key|
471 +      hash[key] = {}
472 +      hash[key][:name] = key
473 +      hash[key]
474 +    end
475 +
476 +    lines = contents.split("\n")
477 +    lines.each do |line|
478 +      # Strip off any trailing comments
479 +      line.sub!(/#.*$/, '')
480 +
481 +      if line =~ /^\s*#|^\s*$/
482 +        # Ignore comments and blank lines
483 +        next
484 +      end
485 +
486 +      route = line.split(' ', 5)
487 +
488 +      if route.length < 4
489 +        raise_malformed
490 +      end
491 +
492 +      # use the CIDR version of the target as :name
493 +      cidr_target = "#{route[0]}/#{IPAddr.new(route[1]).to_i.to_s(2).count('1')}"
494 +
495 +      route_hash[cidr_target][:network] = route[0]
496 +      route_hash[cidr_target][:netmask] = route[1]
497 +      route_hash[cidr_target][:gateway] = route[2]
498 +      route_hash[cidr_target][:interface] = route[3]
499 +      route_hash[cidr_target][:options] = route[4] if route[4]
500 +    end
501 +
502 +    route_hash.values
503 +  end
504 +
505 +  # Generate an array of sections
506 +  def self.format_file(filename, providers)
507 +    contents = []
508 +    contents << header
509 +
510 +    # Build routes
511 +    providers.sort_by(&:name).each do |provider|
512 +      raise Puppet::Error, "#{provider.name} is missing the required parameter 'network'." if provider.network.nil?
513 +      raise Puppet::Error, "#{provider.name} is missing the required parameter 'netmask'." if provider.netmask.nil?
514 +      raise Puppet::Error, "#{provider.name} is missing the required parameter 'gateway'." if provider.gateway.nil?
515 +      raise Puppet::Error, "#{provider.name} is missing the required parameter 'interface'." if provider.interface.nil?
516 +
517 +      contents << "#{provider.network} #{provider.netmask} #{provider.gateway} #{provider.interface} #{provider.options}\n"
518 +    end
519 +
520 +    contents.join
521 +  end
522 +
523 +  def self.header
524 +    str = <<-HEADER
525 +# HEADER: This file is is being managed by puppet. Changes to
526 +# HEADER: routes that are not being managed by puppet will persist;
527 +# HEADER: however changes to routes that are being managed by puppet will
528 +# HEADER: be overwritten. In addition, file order is NOT guaranteed.
529 +# HEADER: Last generated at: #{Time.now}
530 +HEADER
531 +    str
532 +  end
533 +end
534 diff --git a/packstack/puppet/modules/network/lib/puppet/type/network_config.rb b/packstack/puppet/modules/network/lib/puppet/type/network_config.rb
535 index a50a0df..1297ad7 100644
536 --- a/packstack/puppet/modules/network/lib/puppet/type/network_config.rb
537 +++ b/packstack/puppet/modules/network/lib/puppet/type/network_config.rb
538 @@ -95,6 +95,10 @@ Puppet::Type.newtype(:network_config) do
539      defaultto :raw
540    end
541  
542 +  newproperty(:gateway) do
543 +    desc 'The IP address of the network router or gateway device (if any)'
544 +  end
545 +
546    # `:options` provides an arbitrary passthrough for provider properties, so
547    # that provider specific behavior doesn't clutter up the main type but still
548    # allows for more powerful actions to be taken.
549 diff --git a/packstack/puppet/modules/network/manifests/bond.pp b/packstack/puppet/modules/network/manifests/bond.pp
550 index d6d98ce..26ca104 100644
551 --- a/packstack/puppet/modules/network/manifests/bond.pp
552 +++ b/packstack/puppet/modules/network/manifests/bond.pp
553 @@ -188,6 +188,28 @@ define network::bond(
554          require          => Kmod::Alias[$name],
555        }
556      }
557 +    WRLinux: {
558 +      network::bond::wrlinux { $name:
559 +        slaves    => $slaves,
560 +        ensure    => $ensure,
561 +        ipaddress => $ipaddress,
562 +        netmask   => $netmask,
563 +        method    => $method,
564 +        family    => $family,
565 +        onboot    => $onboot,
566 +
567 +        mode             => $mode,
568 +        miimon           => $miimon,
569 +        downdelay        => $downdelay,
570 +        updelay          => $updelay,
571 +        lacp_rate        => $lacp_rate,
572 +        primary          => $primary,
573 +        primary_reselect => $primary_reselect,
574 +        xmit_hash_policy => $xmit_hash_policy,
575 +
576 +        require   => Kmod::Alias[$name],
577 +      }
578 +    }
579      RedHat: {
580        network::bond::redhat { $name:
581          ensure           => $ensure,
582 diff --git a/packstack/puppet/modules/network/manifests/bond/setup.pp b/packstack/puppet/modules/network/manifests/bond/setup.pp
583 index abe1252..0a30767 100644
584 --- a/packstack/puppet/modules/network/manifests/bond/setup.pp
585 +++ b/packstack/puppet/modules/network/manifests/bond/setup.pp
586 @@ -10,5 +10,7 @@ class network::bond::setup {
587          ensure => present,
588        }
589      }
590 +    WRLinux: {
591 +    }
592    }
593  }
594 diff --git a/packstack/puppet/modules/network/manifests/bond/wrlinux.pp b/packstack/puppet/modules/network/manifests/bond/wrlinux.pp
595 new file mode 100644
596 index 0000000..e240341
597 --- /dev/null
598 +++ b/packstack/puppet/modules/network/manifests/bond/wrlinux.pp
599 @@ -0,0 +1,56 @@
600 +# = Define: network::bond::wrlinux
601 +#
602 +# Instantiate bonded interfaces on Debian based systems.
603 +#
604 +# == See also
605 +#
606 +# * Debian Network Bonding http://wiki.wrlinux.org/Bonding
607 +define network::bond::wrlinux(
608 +  $slaves,
609 +  $ensure    = present,
610 +  $ipaddress = undef,
611 +  $netmask   = undef,
612 +  $method    = undef,
613 +  $family    = undef,
614 +  $onboot    = undef,
615 +
616 +  $mode             = undef,
617 +  $miimon           = undef,
618 +  $downdelay        = undef,
619 +  $updelay          = undef,
620 +  $lacp_rate        = undef,
621 +  $primary          = undef,
622 +  $primary_reselect = undef,
623 +  $xmit_hash_policy = undef,
624 +) {
625 +
626 +  $raw = {
627 +    'bond-slaves'    => join($slaves, ' '),
628 +    'bond-mode'      => $mode,
629 +    'bond-miimon'    => $miimon,
630 +    'bond-downdelay' => $downdelay,
631 +    'bond-updelay'   => $updelay,
632 +    'bond-lacp-rate' => $lacp_rate,
633 +    'bond-primary'   => $primary,
634 +    'bond-primary-reselect' => $primary_reselect,
635 +    'bond-xmit-hash-policy' => $xmit_hash_policy,
636 +  }
637 +
638 +  $opts = compact_hash($raw)
639 +
640 +  network_config { $name:
641 +    ensure    => $ensure,
642 +    ipaddress => $ipaddress,
643 +    netmask   => $netmask,
644 +    family    => $family,
645 +    method    => $method,
646 +    onboot    => $onboot,
647 +    options   => $opts,
648 +  }
649 +
650 +  network_config { $slaves:
651 +    ensure      => absent,
652 +    reconfigure => true,
653 +    before      => Network_config[$name],
654 +  }
655 +}
656 -- 
657 1.8.3.1
658