Class: Puppet::Provider::IosNetworkTrunk::CiscoIos

Inherits:
ResourceApi::SimpleProvider
  • Object
show all
Defined in:
lib/puppet/provider/ios_network_trunk/cisco_ios.rb

Overview

Network Trunk Puppet Provider for Cisco IOS devices

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.array_to_string(array_value) ⇒ Object

If given an array, converts it to a string



75
76
77
78
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 75

def self.array_to_string(array_value)
  return array_value unless array_value.class == Array
  _string_value = "#{array_value[0]} #{array_value[1]}"
end

.commands_from_instance(property_hash) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 30

def self.commands_from_instance(property_hash)
  commands_array = []
  ensure_command = if PuppetX::CiscoIOS::Utility.attribute_safe_to_run(commands_hash, 'ensure')
                     PuppetX::CiscoIOS::Utility.attribute_value_foraged_from_command_hash(commands_hash, 'ensure', 'set_value')
                   else
                     ''
                   end
  if property_hash[:ensure] == 'absent'
    # delete with a 'no'
    ensure_command = PuppetX::CiscoIOS::Utility.insert_attribute_into_command_line(ensure_command, 'state', 'no', false)
    commands_array.push(ensure_command) if ensure_command != ''
  else
    ensure_command = PuppetX::CiscoIOS::Utility.insert_attribute_into_command_line(ensure_command, 'state', '', false)
    commands_array.push(ensure_command.strip) if ensure_command != ''
    unless property_hash[:mode].nil?
      property_hash[:mode] = PuppetX::CiscoIOS::Utility.convert_network_trunk_mode_modelled(property_hash[:mode])
    end
    unless property_hash[:allowed_vlans].nil?
      property_hash[:allowed_vlans] = Puppet::Provider::IosNetworkTrunk::CiscoIos.array_to_string(property_hash[:allowed_vlans])
    end
    property_hash.each do |key, _value|
      property_hash[key] = Puppet::Provider::IosNetworkTrunk::CiscoIos.false_to_unset(property_hash[key])
    end
    commands_array += PuppetX::CiscoIOS::Utility.build_commmands_from_attribute_set_values(property_hash, commands_hash)
  end
  commands_array
end

.commands_hashObject



11
12
13
14
15
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 11

def self.commands_hash
  @local_commands_hash ||= PuppetX::CiscoIOS::Utility.load_yaml(File.expand_path(__dir__) + '/command.yaml')
  @network_trunk_commands_hash ||= PuppetX::CiscoIOS::Utility.load_yaml(File.expand_path(__dir__) + '/../network_trunk/command.yaml')
  @commands_hash ||= @local_commands_hash.merge(@network_trunk_commands_hash) { |_key, oldval, newval| (oldval.to_a + newval.to_a).to_h }
end

.create_array_from_string(all_vlans) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 142

def self.create_array_from_string(all_vlans)
  # split the string based on ',' and then '-'
  # so "1-3,5-9" becomes [["1", "3"], ["5", "9"]]
  split_vlans = all_vlans.split(',').map { |x| x.split('-') }
  # create the Range of the values from the split, i.e.
  # [["1", "3"], ["5", "9"]] will become
  # [[1,2,3], [5,6,7,8,9]]
  ranged_vlans = split_vlans.map do |x|
    if x[1].nil?
      [x[0].to_i]
    else
      (x[0].to_i..x[1].to_i).to_a unless x[1].nil?
    end
  end
  # reconstruct the full array of all values sort them and
  # only return uniques
  ranged_vlans.join(',').split(',').sort.map { |x| x.to_i }.uniq
end

.create_cli_range_from_array(array) ⇒ Object

convert [1,2,3,4,5,8,100,101,102] in to a valid cli range such as, ‘1-5,8,100-102’



137
138
139
140
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 137

def self.create_cli_range_from_array(array)
  # inspiration and code gathered from https://www.rosettacode.org/wiki/Range_extraction#Ruby
  array.sort.slice_when { |i, j| i + 1 != j }.map { |a| (a.size < 3) ? a : "#{a[0]}-#{a[-1]}" }.join(',')
end

.false_to_unset(false_value) ⇒ Object

Returns ‘unset’ if the given calue is false



69
70
71
72
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 69

def self.false_to_unset(false_value)
  return 'unset' if false_value == false
  false_value
end

.instance_from_cli(output) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 17

def self.instance_from_cli(output)
  new_instance = PuppetX::CiscoIOS::Utility.parse_resource(output, commands_hash)
  new_instance[:name] = PuppetX::CiscoIOS::Utility.shorthand_to_full(new_instance[:name])
  new_instance[:mode] = PuppetX::CiscoIOS::Utility.convert_network_trunk_mode_cli(new_instance[:mode])
  new_instance.delete_if { |_k, v| v.nil? }
  new_instance[:ensure] = if new_instance[:ensure] || new_instance.size > 1
                            'present'
                          else
                            'absent'
                          end
  new_instance
end

.make_allowed_vlans_idempotent(current_vlans, allowed_vlans) ⇒ Object

the cli will return the allowed_vlans in the following format, ‘1-3,5,7,100-300’ to specify the ranges, or individual vlans allowed.

if all vlans are allowed, it’ll return ‘ALL’, if none then ‘NONE’ is used. this method will convert user manifests in to the expected format of the cli allowing idempotency to be maintained even for complex things like ‘allowed_vlans => [’except’, ‘500-600’]“



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 87

def self.make_allowed_vlans_idempotent(current_vlans, allowed_vlans)
  # if it is not an arrary then it'll either already be a valid cli range
  # i.e. '1-3,6-10,100-300' or one of the key words, `all`, `none` etc.
  return allowed_vlans.upcase unless allowed_vlans.class == Array
  if allowed_vlans[0] == 'add'
    # add needs to know what current vlans are
    # allowed and extend them
    return allowed_vlans[1] if current_vlans == 'NONE'
    # if current vlans is `ALL` then
    # there is no need to add to them
    # so returning all will surfice
    return 'ALL' if current_vlans == 'ALL'
    # need to create a string with the current and
    # ones that need to be added
    all_vlans = current_vlans + ',' + allowed_vlans[1]
    array_of_all_vlans = Puppet::Provider::IosNetworkTrunk::CiscoIos.create_array_from_string(all_vlans)
    return Puppet::Provider::IosNetworkTrunk::CiscoIos.create_cli_range_from_array(array_of_all_vlans)

  elsif allowed_vlans[0] == 'remove'
    if current_vlans == 'ALL'
      # if it is all vlans, we need to remove the
      # expected vlans that need removed from
      # all available vlans
      array_of_all_vlans = (1..4094).to_a
      array_of_allowed_vlans = Puppet::Provider::IosNetworkTrunk::CiscoIos.create_array_from_string(allowed_vlans[1])
      array_without_allowed = array_of_all_vlans - array_of_allowed_vlans
      return Puppet::Provider::IosNetworkTrunk::CiscoIos.create_cli_range_from_array(array_without_allowed)
    elsif current_vlans == 'NONE'
      # if current vlans is `NONE` then
      # there is no need to remove any from them
      # so returning none is enough
      return 'NONE'
    else
      array_of_current_vlans = Puppet::Provider::IosNetworkTrunk::CiscoIos.create_array_from_string(current_vlans)
      array_of_allowed_vlans = Puppet::Provider::IosNetworkTrunk::CiscoIos.create_array_from_string(allowed_vlans[1])
      array_without_allowed = array_of_current_vlans - array_of_allowed_vlans
      return Puppet::Provider::IosNetworkTrunk::CiscoIos.create_cli_range_from_array(array_without_allowed)
    end
  elsif allowed_vlans[0] == 'except'
    # except is all possible vlans without the specified ones
    # so no need to handle if it is currently 'all' or 'none' etc.
    array_of_all_vlans = (1..4094).to_a
    array_of_allowed_vlans = Puppet::Provider::IosNetworkTrunk::CiscoIos.create_array_from_string(allowed_vlans[1])
    array_without_allowed = array_of_all_vlans - array_of_allowed_vlans
    return Puppet::Provider::IosNetworkTrunk::CiscoIos.create_cli_range_from_array(array_without_allowed)
  end
end

.switchport_nonegotiate_from_output(output) ⇒ Object

Replaces switchport_nonegotiate value ‘Off’ with true and ‘On’ with false



59
60
61
62
63
64
65
66
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 59

def self.switchport_nonegotiate_from_output(output)
  output_switchport = output[:switchport_nonegotiate]
  if output_switchport
    output[:switchport_nonegotiate] = true if output_switchport == 'Off'
    output[:switchport_nonegotiate] = false if output_switchport == 'On'
  end
  output
end

Instance Method Details

#canonicalize(context, resources) ⇒ Object



194
195
196
197
198
199
200
201
202
203
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 194

def canonicalize(context, resources)
  get(context) if @cache.nil?
  resources.each do |resource|
    if resource[:allowed_vlans]
      current_vlans = @cache.find { |key| key[:name] == resource[:name] }[:allowed_vlans]
      resource[:allowed_vlans] = Puppet::Provider::IosNetworkTrunk::CiscoIos.make_allowed_vlans_idempotent(current_vlans, resource[:allowed_vlans])
    end
  end
  resources
end

#commands_hashObject



161
162
163
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 161

def commands_hash
  Puppet::Provider::IosNetworkTrunk::CiscoIos.commands_hash
end

#create(context, name, should) ⇒ Object Also known as: update



182
183
184
185
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 182

def create(context, name, should)
  commands = Puppet::Provider::IosNetworkTrunk::CiscoIos.commands_from_instance(should).join("\n")
  context.transport.run_command_interface_mode(name, commands)
end

#delete(context, name) ⇒ Object



189
190
191
192
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 189

def delete(context, name)
  delete_hash = { name: name, ensure: 'absent' }
  context.transport.run_command_interface_mode(name, Puppet::Provider::IosNetworkTrunk::CiscoIos.commands_from_instance(delete_hash).join("\n"))
end

#get(context, _names = nil) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/puppet/provider/ios_network_trunk/cisco_ios.rb', line 165

def get(context, _names = nil)
  output = context.transport.run_command_enable_mode(PuppetX::CiscoIOS::Utility.get_values(commands_hash))
  # convert the output to an array, breaking at `Name:`
  output_array = output.split("\n").slice_before(%r{Name:(.*)}).to_a

  return_instances = []
  # drop the first item in the array which is the command...
  output_array.drop(1).each do |interface|
    interface_output = interface.join("\n")
    unless interface_output.include? ' is not a switchable port'
      return_instance = Puppet::Provider::IosNetworkTrunk::CiscoIos.instance_from_cli(interface_output)
      return_instances << Puppet::Provider::IosNetworkTrunk::CiscoIos.switchport_nonegotiate_from_output(return_instance)
    end
  end
  @cache = PuppetX::CiscoIOS::Utility.enforce_simple_types(context, return_instances)
end