|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +require 'ipaddr' |
| 4 | + |
| 5 | +Puppet::Functions.create_function(:"ipcalc::equal_to") do |
| 6 | + # Compare two IP addresses and return a Boolean indicating whether the first operand is equal to |
| 7 | + # the second. This differs from comparing the address Strings in that it compares native 32-bit |
| 8 | + # (or for IPv6, 128-bit) binary values, regardless of their human-readable representations. For |
| 9 | + # IPv4 addresses this is usually not much of a problem, as representations are simpler and |
| 10 | + # zero-padded values are relatively rare (enough that Stdlib::IP::Address::V4 filters them out as |
| 11 | + # invalid). For IPv6 addresses, however, IPv6's collapsed notation can be a very serious problem, |
| 12 | + # and this function allows IPv6 addresses with un-collapsed runs of zeroes, leading zeroes, etc. |
| 13 | + # to be compared meaningfully without needing to worry about normalizing their human-readable |
| 14 | + # representations first. |
| 15 | + # |
| 16 | + # Contextually, this function makes the most sense when using Puppet's dotted function notation, |
| 17 | + # because the function name sits where a comparison operator would normally go. This will work |
| 18 | + # with either plain addresses or CIDR-notation addresses; if a plain address is supplied, a |
| 19 | + # full-width netmask is assumed. That is, '127.0.0.1' and '127.0.0.1/32' are equivalent, just as |
| 20 | + # 'fe80::1' and 'fe80::1/128' are equivalent. The netmask IS assessed in the comparison, but is |
| 21 | + # only relevant if the remainder of the address is exactly equivalent down to the start of the |
| 22 | + # netmask. Addresses of mixed families are always considered unequal. |
| 23 | + # @param first |
| 24 | + # The first address for comparison. If no netmask is given, full-width is assumed. |
| 25 | + # @param second |
| 26 | + # The second address for comparison. If no netmask is given, full-width is assumed. |
| 27 | + # @return [Boolean] |
| 28 | + # `true` if the operands are equal, or `false` otherwise. |
| 29 | + # @example Use with dotted function notation |
| 30 | + # $first_ip.equal_to($second_ip) ? { |
| 31 | + # true => { 'We did it, go team, the operands are equal' }, |
| 32 | + # default => { 'I\'m afraid I have some bad news...' }, |
| 33 | + # } |
| 34 | + dispatch :equal_to do |
| 35 | + param 'Stdlib::IP::Address::V4', :first |
| 36 | + param 'Stdlib::IP::Address::V4', :second |
| 37 | + return_type 'Boolean' |
| 38 | + end |
| 39 | + |
| 40 | + dispatch :equal_to do |
| 41 | + param 'Stdlib::IP::Address::V6', :first |
| 42 | + param 'Stdlib::IP::Address::V6', :second |
| 43 | + return_type 'Boolean' |
| 44 | + end |
| 45 | + |
| 46 | + dispatch :mixed_families do |
| 47 | + param 'Stdlib::IP::Address::V4', :first |
| 48 | + param 'Stdlib::IP::Address::V6', :second |
| 49 | + end |
| 50 | + |
| 51 | + dispatch :mixed_families do |
| 52 | + param 'Stdlib::IP::Address::V6', :first |
| 53 | + param 'Stdlib::IP::Address::V4', :second |
| 54 | + end |
| 55 | + |
| 56 | + def equal_to(first, second) |
| 57 | + first_addr = IPAddr.new(first) |
| 58 | + second_addr = IPAddr.new(second) |
| 59 | + |
| 60 | + first_addr == second_addr |
| 61 | + end |
| 62 | + |
| 63 | + def mixed_families(*) |
| 64 | + false |
| 65 | + end |
| 66 | +end |
0 commit comments