-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
INFRA-3218 Initial commit of ip_compare()
Initial commit of implementation and tests for ip_compare(), designed for use with Puppet's `sort()` to sort a series of IP addresses into binary-numerical order, regardless of the human-readable representation in which they were originally written.
- Loading branch information
1 parent
56bd874
commit ed615a9
Showing
3 changed files
with
81 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,4 @@ | |
--- | ||
fixtures: | ||
forge_modules: | ||
# stdlib: "puppetlabs/stdlib" | ||
stdlib: "puppetlabs/stdlib" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'ipaddr' | ||
|
||
Puppet::Functions.create_function(:"ipcalc::ip_compare") do | ||
# Compare two IP addresses and return a `sort()`-compatible Integer comparison result. This will | ||
# work with either plain addresses or CIDR-notation addresses; if a plain address is supplied, a | ||
# full-width netmask is assumed. That is, '127.0.0.1' and '127.0.0.1/32' are equivalent, just as | ||
# 'fe80::1' and 'fe80::1/128' are equivalent. The netmask IS assessed in the comparison, but is | ||
# only relevant if all bits of the address are equivalent. | ||
# @param left | ||
# The left address for comparison. If no netmask is given, a full-width mask is assumed. | ||
# @param right | ||
# The right address for comparison. If no netmask is given, a full-width mask is assumed. | ||
# @return [Integer[-1, 1]] | ||
# Either 1, 0, or -1 if the left operand is larger than, equal to, or smaller than the right, | ||
# respectively. | ||
# @example Usage with `sort()` | ||
# $my_addr_array.sort |$left, $right| { | ||
# ipcalc::ip_compare($left, $right) | ||
# } | ||
dispatch :ip_compare do | ||
param 'Stdlib::IP::Address::V4', :left | ||
param 'Stdlib::IP::Address::V4', :right | ||
return_type 'Integer[-1, 1]' | ||
end | ||
|
||
dispatch :ip_compare do | ||
param 'Stdlib::IP::Address::V6', :left | ||
param 'Stdlib::IP::Address::V6', :right | ||
return_type 'Integer[-1, 1]' | ||
end | ||
|
||
# We refuse to handle addresses in different families. There isn't a clear precedence between | ||
# them, and if needed, any relative ordering required can be handled in your Puppet code by | ||
# assessing the types handed to `sort()`. There are examples of this in the documentation for the | ||
# Puppet `sort()` function, but a specific example for sorting all IPv6 addresses before all IPv4 | ||
# address is included for reference. | ||
# @example Usage with `sort()` where IPv6 sorts above IPv4 | ||
# $my_ip_array.sort |$left, $right| { | ||
# case [$left, $right] { | ||
# [Stdlib::IP::Address::V6, Stdlib::IP::Address::V4]: { 1 } | ||
# [Stdlib::IP::Address::V4, Stdlib::IP::Address::V6]: { -1 } | ||
# default: { ipcalc::ip_compare($left, $right) } | ||
# } | ||
# } | ||
argument_mismatch :mixed_families do | ||
param 'Stdlib::IP::Address::V4', :left | ||
param 'Stdlib::IP::Address::V6', :right | ||
end | ||
|
||
argument_mismatch :mixed_families do | ||
param 'Stdlib::IP::Address::V6', :left | ||
param 'Stdlib::IP::Address::V4', :right | ||
end | ||
|
||
def ip_compare(left, right) | ||
left_addr = IPAddr.new(left) | ||
right_addr = IPAddr.new(right) | ||
|
||
left_addr <=> right_addr | ||
end | ||
|
||
def mixed_families(*) | ||
'both addresses must be in the same family' | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'spec_helper' | ||
|
||
describe 'ipcalc::ip_compare' do | ||
it { is_expected.to run.with_params('127.0.0.1', '127.0.0.2').and_return(-1) } | ||
it { is_expected.to run.with_params('127.0.0.2', '127.0.0.1').and_return(1) } | ||
it { is_expected.to run.with_params('fe80::1', 'fe80::2').and_return(-1) } | ||
it { is_expected.to run.with_params('fe80::2', 'fe80::1').and_return(1) } | ||
it { is_expected.to run.with_params(nil).and_raise_error(StandardError) } | ||
it { is_expected.to run.with_params('127.0.0.1', 'fe80::1').and_raise_error(StandardError) } | ||
it { is_expected.to run.with_params('fe80::1', '127.0.0.1').and_raise_error(StandardError) } | ||
end |