Files
ubicloud/prog/learn_network.rb
Furkan Sahin 63c6cfa574 dirty
2025-01-24 17:09:58 +01:00

91 lines
2.8 KiB
Ruby

# frozen_string_literal: true
require "json"
class Prog::LearnNetwork < Prog::Base
subject_is :sshable, :vm_host
label def start
if vm_host.provider == "leaseweb"
payload = JSON.generate(vm_host.assigned_subnets.map do |as|
{
cidr: if as.cidr.version == 4
as.cidr.network.to_s
else
NetAddr::IPv6Net.new(as.cidr.network, NetAddr::Mask128.new(as.mask)).nth(2).to_s
end,
gateway: as.gateway,
mask: as.mask
}
end)
puts "payload: #{payload}"
sshable.cmd("sudo host/bin/setup-leaseweb-networking #{payload.shellescape}")
hop_leaseweb_verify_networking
end
hop_learn_network_info
end
label def leaseweb_verify_networking
unless sshable.cmd("sudo pkill -SIGUSR1 -f 'netplan try'")
Clog.error("netplan try failed")
raise "netplan try failed"
end
hop_learn_network_info
end
label def learn_network_info
if vm_host.provider == "leaseweb"
adr = vm_host.assigned_subnets.find { |as| as.cidr.version == 6 && as.mask == 64 }
vm_host.update(
ip6: NetAddr::IPv6Net.new(NetAddr.parse_ip(adr.cidr.network), NetAddr::Mask128.new(adr.mask)).nth(2).to_s,
net6: NetAddr::IPv6Net.new(adr.cidr.network, NetAddr::Mask128.new(adr.mask)).to_s
)
pop "learned network information"
end
ip6 = parse_ip_addr_j(sshable.cmd("/usr/sbin/ip -j -6 addr show scope global"))
# While it would be ideal for NetAddr's IPv6 support to convey
# both address and prefix information together as `ip` does, it's
# designed in a more IPv4-centric way where IP addresses and CIDRs
# tend to be disaggregated.
#
# Postgres's "inet" does support this IPv6-style mixture of
# addresses and prefixlens, the "cidr" type requires masked-out
# bits to be zero. NetAddr's IPv6Net type clears low bits beyond
# the prefix.
#
# Maybe we can improve support for inet in a fork later, NetAddr
# is not a fast moving project, there is room to improve it, but
# some would be backwards-incompatible.
vm_host.update(
ip6: ip6.addr,
net6: NetAddr::IPv6Net.new(NetAddr.parse_ip(ip6.addr), NetAddr::Mask128.new(ip6.prefixlen)).to_s
)
pop "learned network information"
end
Ip6 = Struct.new(:addr, :prefixlen)
def parse_ip_addr_j(s)
case JSON.parse(s)
in [iface]
case iface.fetch("addr_info").filter_map { |info|
if (local = info["local"]) && (prefixlen = info["prefixlen"]) && prefixlen <= 64
Ip6.new(local, prefixlen)
end
}
in [net6]
net6
else
fail "only one global unique address prefix supported on interface"
end
else
fail "only one one interface supported"
end
end
end