b1f2fff045
BinaryLane edge hosts have a public primary IP, so region/environment/country/zone resolve to unknown even though their VPC NIC sits in a known subnet. - match the primary IP first, unchanged for existing hosts - otherwise scan interface bindings in name order, skipping lo, dum* and wg* - add modules/libs/test/subnet_facts_check.rb (`ruby modules/libs/test/subnet_facts_check.rb`) Reviewed-on: #557 Co-authored-by: unkin-agent <unkin-agent@unkin.net> Co-committed-by: unkin-agent <unkin-agent@unkin.net>
70 lines
3.8 KiB
Ruby
70 lines
3.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'ipaddr'
|
|
|
|
# a class that creates facts based on the subnet
|
|
class SubnetAttributes
|
|
SUBNET_TO_ATTRIBUTES = {
|
|
'198.18.2.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # router loopbacks
|
|
'198.18.13.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
|
'198.18.14.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
|
'198.18.15.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' },
|
|
'198.18.16.0/24' => { environment: 'test', region: 'syd1', country: 'au', zone: 'common' },
|
|
'198.18.17.0/24' => { environment: 'prod', region: 'drw1', country: 'au', zone: 'common' },
|
|
'198.18.18.0/24' => { environment: 'test', region: 'drw1', country: 'au', zone: 'common' },
|
|
'198.18.19.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # loopbacks
|
|
'198.18.20.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # MPLS CORE BLOCKS
|
|
'198.18.21.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # physical network 2.5gbe
|
|
'198.18.22.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # ceph cluster
|
|
'198.18.23.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # ceph public
|
|
'198.18.24.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'dmz' }, # dmz 1
|
|
'198.18.25.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # common node0009
|
|
'198.18.26.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # common node0010
|
|
'198.18.27.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # common node0011
|
|
'198.18.28.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # common node0012
|
|
'198.18.29.0/24' => { environment: 'prod', region: 'syd1', country: 'au', zone: 'common' }, # common node0013
|
|
'198.18.30.0/24' => { environment: 'prod', region: 'syd2', country: 'au', zone: 'dmz' }, # binarylane syd dmz vpc
|
|
'198.18.31.0/24' => { environment: 'prod', region: 'mel1', country: 'au', zone: 'dmz' } # binarylane mel dmz vpc
|
|
}.freeze
|
|
|
|
# Default attributes if no subnet matches, also defined as a constant
|
|
DEFAULT_ATTRIBUTES = { environment: 'unknown', region: 'unknown', country: 'unknown' }.freeze
|
|
|
|
# loopbacks and wg /31s sit in syd1 ranges, so they must not decide where a host lives
|
|
SKIPPED_INTERFACES = /\A(lo\z|dum|wg)/.freeze
|
|
|
|
# primary ip first, then the remaining interfaces in name order
|
|
def self.from_networking(networking)
|
|
match(networking['ip']) || interface_match(networking['interfaces'] || {}) || DEFAULT_ATTRIBUTES
|
|
end
|
|
|
|
def self.interface_match(interfaces)
|
|
interfaces.sort
|
|
.reject { |name, _interface| name.match?(SKIPPED_INTERFACES) }
|
|
.flat_map { |_name, interface| addresses(interface) }
|
|
.lazy.filter_map { |address| match(address) }.first
|
|
end
|
|
|
|
def self.addresses(interface)
|
|
(interface['bindings'] || []).map { |binding| binding['address'] }
|
|
end
|
|
|
|
def self.match(ip)
|
|
return unless ip
|
|
|
|
addr = IPAddr.new(ip)
|
|
SUBNET_TO_ATTRIBUTES.each do |subnet, attrs|
|
|
return attrs if IPAddr.new(subnet).include?(addr)
|
|
end
|
|
nil
|
|
end
|
|
end
|
|
|
|
subnet_attributes = SubnetAttributes.from_networking(Facter.value(:networking))
|
|
|
|
# Add separate facts for environment, region, and country
|
|
Facter.add('environment') { setcode { subnet_attributes[:environment] } }
|
|
Facter.add('region') { setcode { subnet_attributes[:region] } }
|
|
Facter.add('country') { setcode { subnet_attributes[:country] } }
|
|
Facter.add('zone') { setcode { subnet_attributes[:zone] } }
|