Skip to content

Commit

Permalink
Add Extlib::CIDR DataType
Browse files Browse the repository at this point in the history
Example:
```
$ip = Extlib::CIDR('192.168.1.0/24')
notice $ip.host_min, $ip.host_max
```
  • Loading branch information
jay7x committed Apr 1, 2024
1 parent 4b938f9 commit 7963634
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 0 deletions.
57 changes: 57 additions & 0 deletions lib/puppet/datatypes/extlib/cidr.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

# The `Extlib::CIDR` object represents a CIDR.
#
# @param cidr
# @!method address
# @!method canonical
# @!method netmask
# @!method family
# @!method prefix_length
# @!method first
# @!method last
# @!method host_rewind
# @!method host_next
# @!method host_prev
# @!method host_count
# @!method host_min
# @!method host_max
# @!method to_i
# @!method compare
# @!method include
#
Puppet::DataTypes.create_type('Extlib::CIDR') do
interface <<-PUPPET
attributes => {
cidr => String[1],
address => { type => String[1], kind => derived },
canonical => { type => String[1], kind => derived },
netmask => { type => String[1], kind => derived },
family => { type => String[1], kind => derived },
prefix_length => { type => Integer[0], kind => derived },
is_single_address => { type => Boolean, kind => derived },
is_link_local => { type => Boolean, kind => derived },
is_loopback => { type => Boolean, kind => derived },
is_private => { type => Boolean, kind => derived },
first => { type => String[1], kind => derived },
last => { type => String[1], kind => derived },
count => { type => Integer[0], kind => derived },
host_count => { type => Integer[0], kind => derived },
host_min => { type => String[1], kind => derived },
host_max => { type => String[1], kind => derived },
host_next => { type => String[1], kind => derived },
host_prev => { type => String[1], kind => derived },
},
functions => {
host_rewind => Callable[[String[1]], String[1]],
to_i => Callable[[], Integer[0]],
compare => Callable[[Variant[Extlib::CIDR, String[1]]], Integer[-1,1]],
include => Callable[[Variant[Extlib::CIDR, String[1]]], Boolean],
}
PUPPET

load_file('puppet_x/extlib/cidr')

PuppetX::Extlib::CIDR.include(Puppet::Pops::Types::PuppetObject)
implementation_class PuppetX::Extlib::CIDR
end
151 changes: 151 additions & 0 deletions lib/puppet_x/extlib/cidr.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# frozen_string_literal: true

require 'ipaddr'

module PuppetX
class Extlib
class CIDR
attr_reader :ip

def initialize(cidr)
@ip = IPAddr.new(cidr)
@first = @ip.to_range.first
@last = @ip.to_range.last
@single_address = (@ip.ipv4? && @ip.prefix == 32) || (@ip.ipv6? && @ip.prefix == 128)

if (@ip.ipv4? && @ip.prefix.between?(31, 32)) || (@ip.ipv6? && @ip.prefix.between?(127, 128))
@host_min = @first
@host_max = @last
else
@host_min = IPAddr.new(@first.to_i + 1, @ip.family)
@host_max = IPAddr.new(@last.to_i - 1, @ip.family)
end
@host_current = @first
end

def address
@ip.to_s
end

def canonical
"#{@ip.to_string}/#{@ip.prefix}"
end

def netmask
@ip.inspect.gsub(%r{.*/(.*)>}, '\1')
end

# ipv4/ipv6
def family
@ip.inspect.split(':')[1].strip.downcase
end

def prefix_length
@ip.prefix
end

def is_single_address
@single_address
end

def is_link_local
@ip.link_local?
end

def is_loopback
@ip.loopback?
end

def is_private
@ip.private?
end

def first
@first.to_s
end

def last
@last.to_s
end

# Total amount of addresses in the range
def count
@last.to_i - @first.to_i + 1
end

# Amount of usable addresses in the range (except first and last addresses)
def host_count
@host_max.to_i - @host_min.to_i + 1
end

def host_rewind(new_ip)
raise ArgumentError, "IP should be between #{@first} and #{@last}" unless new_ip.between?(@first, @last)

@host_current = IPAddr.new(new_ip)
new_ip.to_s
end

def host_next
host_next_by_step(1)
end

def host_prev
host_next_by_step(-1)
end

# If our CIDR is just an IP address then just return next one.
# Don't care about network range.
def host_next_by_step(step = 1)
next_ip = IPAddr.new(@host_current.to_i + step, @ip.family)

if !@single_address
if !next_ip.between?(@host_min, @host_max)
return nil
end
end

@host_current = next_ip
return @host_current.to_s
end

def host_min
@host_min.to_s
end

def host_max
@host_max.to_s
end

def include?(other)
if other.is_a? Extlib::CIDR
@ip.include? other.ip
else
@ip.include? IPAddr.new(other)
end
end
alias include include?

def to_s
if @single_address
@ip.to_s
else
"#{@ip.to_s}/#{@ip.prefix}"
end
end

def to_i
@ip.to_i
end

# Compare IP addresses
def <=>(other)
@ip.to_i <=> if other.is_a? Extlib::CIDR
other.to_i
else
IPAddr.new(other).to_i
end
end
alias compare <=>
end
end
end

0 comments on commit 7963634

Please sign in to comment.