From 9f17f068af424aabc98094663fd7266c24638872 Mon Sep 17 00:00:00 2001 From: Steve Russell Date: Fri, 28 Jan 2022 13:22:35 -0800 Subject: [PATCH] INFRA-507 Added ip_range_size() and associated unit tests --- lib/puppet/parser/functions/ip_range_size.rb | 16 +++++++ lib/puppetx/ip.rb | 18 +++++++ metadata.json | 2 +- spec/functions/ip_range_size_spec.rb | 49 ++++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 lib/puppet/parser/functions/ip_range_size.rb create mode 100644 spec/functions/ip_range_size_spec.rb diff --git a/lib/puppet/parser/functions/ip_range_size.rb b/lib/puppet/parser/functions/ip_range_size.rb new file mode 100644 index 0000000..6fcec9e --- /dev/null +++ b/lib/puppet/parser/functions/ip_range_size.rb @@ -0,0 +1,16 @@ +# ex: syntax=ruby ts=2 sw=2 si et +# frozen_string_literal: true + +begin + require 'puppetx/ip' +rescue LoadError + # work around for puppet bug SERVER-973 + Puppet.info('Puppet did not autoload from the lib directory... falling back to relative path load.') + require File.join(File.expand_path(File.join(__FILE__, '../../../..')), 'puppetx/ip') +end + +module Puppet::Parser::Functions + newfunction(:ip_range_size, type: :rvalue) do |args| + PuppetX::Ip.new(args[0]).range_size(args[1]).to_i + end +end diff --git a/lib/puppetx/ip.rb b/lib/puppetx/ip.rb index 1028029..e6a6c49 100644 --- a/lib/puppetx/ip.rb +++ b/lib/puppetx/ip.rb @@ -49,6 +49,15 @@ def offset address.to_i - cidr.to_i end + def range_size(range_cidr) + other_address = IPAddr.new(range_cidr.split(%r{/})[0]) + raise ArgumentError, 'Both addresses must be in same family' if other_address.family != address.family + + # Range size should be inclusive of starting and ending addresses, hence +1 + range_subtraction = other_address.to_i - address.to_i + range_subtraction.abs + 1 + end + def split [ subnet(prefixlength + 1, 0), subnet(prefixlength + 1, 1) ] end @@ -72,6 +81,15 @@ def to_s address.to_s end + def family + case address.family + when Socket::AF_INET + 'IPv4' + when Socket::AF_INET6 + 'IPv6' + end + end + private def unicast_prefixlength diff --git a/metadata.json b/metadata.json index 73c170a..64bd688 100644 --- a/metadata.json +++ b/metadata.json @@ -1,6 +1,6 @@ { "name": "inkblot-ipcalc", - "version": "2.2.1", + "version": "2.3.0", "author": "inkblot", "summary": "IP and subnet puppet parser functions", "license": "Apache-2.0", diff --git a/spec/functions/ip_range_size_spec.rb b/spec/functions/ip_range_size_spec.rb new file mode 100644 index 0000000..fe99f78 --- /dev/null +++ b/spec/functions/ip_range_size_spec.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'ip_range_size' do + # please note that these tests are examples only + # you will need to replace the params and return value + # with your expectations + it 'given adjacent IPv4 CIDR addresses, returns range size of 2' do + is_expected.to run.with_params('192.168.1.1/32', '192.168.1.2/32').and_return(2) + end + it 'given adjacent IPv6 CIDR addresses, returns range size of 2' do + is_expected.to run.with_params('2001:db8::8c28:c929:72db:49fd/64', '2001:db8::8c28:c929:72db:49fe/64').and_return(2) + end + it 'given adjacent IPv4 plain addresses, returns range size of 2' do + is_expected.to run.with_params('192.168.1.1', '192.168.1.2').and_return(2) + end + it 'given adjacent IPv6 plain addresses, returns range size of 2' do + is_expected.to run.with_params('2001:db8::8c28:c929:72db:49fd', '2001:db8::8c28:c929:72db:49fe').and_return(2) + end + it 'given adjacent IPv4 plain addresses in reversed order, returns range size of 2' do + is_expected.to run.with_params('192.168.1.2', '192.168.1.1').and_return(2) + end + it 'given adjacent IPv6 plain addresses in reversed order, returns range size of 2' do + is_expected.to run.with_params('2001:db8::8c28:c929:72db:49fe', '2001:db8::8c28:c929:72db:49fd').and_return(2) + end + it 'given IPv4 CIDR addresses with same offset in different /24 networks, returns range size of 257' do + is_expected.to run.with_params('192.168.1.1/24', '192.168.2.1/24').and_return(257) + end + it 'given IPv6 CIDR addresses with same offset in different /56 networks, returns range size of 257' do + is_expected.to run.with_params('2001:db8::8c28:c929:72db:49fe/56', '2001:db8::8c28:c929:72db:4afe/56').and_return(257) + end + it 'given IPv4 plain addresses in wildly different networks, returns correct range size' do + is_expected.to run.with_params('10.0.57.1', '192.168.2.1').and_return(3_064_449_281) + end + it 'given IPv6 plain addresses in wildly different networks, returns correct range size' do + is_expected.to run + .with_params('2001:db8::8c28:c929:72db:49fe/64', 'fe80::9656:d028:8652:66b6/64') + .and_return(295_747_758_515_978_496_797_848_443_371_614_837_945) + end + it 'given addresses in different families, raises an exception' do + is_expected.to run + .with_params('10.0.57.1', 'fe80::9656:d028:8652:66b6') + .and_raise_error(ArgumentError, %r{addresses must be in same family}) + is_expected.to run + .with_params('fe80::9656:d028:8652:66b6', '10.0.57.1') + .and_raise_error(ArgumentError, %r{addresses must be in same family}) + end +end