Merge remote-tracking branch 'origin/develop' into benvin/mail-edge-dnsmasq
ci/woodpecker/pr/puppet-lint Pipeline was successful
ci/woodpecker/pr/ruby-validate Pipeline was successful
ci/woodpecker/pr/erb-validate Pipeline was successful
ci/woodpecker/pr/bolt-validate Pipeline was successful
ci/woodpecker/pr/yamllint Pipeline was successful
ci/woodpecker/pr/epp-validate Pipeline was successful
ci/woodpecker/pr/ruby-check Pipeline was successful
ci/woodpecker/pr/puppet-validate Pipeline was successful
ci/woodpecker/pr/puppet-lint Pipeline was successful
ci/woodpecker/pr/ruby-validate Pipeline was successful
ci/woodpecker/pr/erb-validate Pipeline was successful
ci/woodpecker/pr/bolt-validate Pipeline was successful
ci/woodpecker/pr/yamllint Pipeline was successful
ci/woodpecker/pr/epp-validate Pipeline was successful
ci/woodpecker/pr/ruby-check Pipeline was successful
ci/woodpecker/pr/puppet-validate Pipeline was successful
# Conflicts: # hieradata/roles/infra/mail/gateway.yaml # site/roles/manifests/infra/mail/gateway.pp
This commit is contained in:
@@ -22,27 +22,45 @@ class SubnetAttributes
|
||||
'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.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
|
||||
|
||||
# provide ip to return attributes
|
||||
def self.attributes(ip)
|
||||
SUBNET_TO_ATTRIBUTES.each do |subnet, attrs|
|
||||
return attrs if IPAddr.new(subnet).include?(IPAddr.new(ip))
|
||||
end
|
||||
# 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
|
||||
|
||||
DEFAULT_ATTRIBUTES
|
||||
# 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
|
||||
|
||||
# Use the primary IP address from facts
|
||||
ip = Facter.value(:networking)['ip']
|
||||
|
||||
# Call the class method directly without creating an instance
|
||||
subnet_attributes = SubnetAttributes.attributes(ip)
|
||||
subnet_attributes = SubnetAttributes.from_networking(Facter.value(:networking))
|
||||
|
||||
# Add separate facts for environment, region, and country
|
||||
Facter.add('environment') { setcode { subnet_attributes[:environment] } }
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# ruby modules/libs/test/subnet_facts_check.rb
|
||||
module Facter
|
||||
def self.value(_name)
|
||||
{}
|
||||
end
|
||||
|
||||
def self.add(*); end
|
||||
end
|
||||
load File.expand_path('../lib/facter/subnet_facts.rb', __dir__)
|
||||
|
||||
iface = ->(*addresses) { { 'bindings' => addresses.map { |address| { 'address' => address } } } }
|
||||
|
||||
checks = {
|
||||
'primary ip wins over other interfaces' => [
|
||||
{ 'ip' => '198.18.17.5', 'interfaces' => { 'eth1' => iface.call('198.18.13.5') } }, 'drw1'
|
||||
],
|
||||
'unmatched primary ip falls back to an interface' => [
|
||||
{ 'ip' => '203.0.113.5', 'interfaces' => { 'eth0' => iface.call('203.0.113.5'), 'eth1' => iface.call('198.18.24.11') } }, 'syd1'
|
||||
],
|
||||
'lo, dum and wg interfaces are skipped' => [
|
||||
{ 'ip' => '203.0.113.5',
|
||||
'interfaces' => { 'dum0' => iface.call('198.18.2.161'), 'lo' => iface.call('198.18.19.1'),
|
||||
'wg0' => iface.call('198.18.2.177') } }, 'unknown'
|
||||
],
|
||||
'interfaces are scanned in name order' => [
|
||||
{ 'ip' => '203.0.113.5', 'interfaces' => { 'eth2' => iface.call('198.18.24.1'), 'eth1' => iface.call('198.18.17.1') } }, 'drw1'
|
||||
],
|
||||
'missing ip and interfaces resolve to unknown' => [{}, 'unknown']
|
||||
}
|
||||
|
||||
failures = checks.reject { |_name, (networking, expected)| SubnetAttributes.from_networking(networking)[:region] == expected }
|
||||
failures.each_key { |name| warn "FAIL: #{name}" }
|
||||
abort if failures.any?
|
||||
puts "ok (#{checks.size} checks)"
|
||||
Reference in New Issue
Block a user