Files
ubicloud/prog/vnet/nic_nexus.rb
Jeremy Evans 59621ae323 Use create_with_id in progs and routes
Only changes to the specs in this commit are to fix mocking issues.
2025-08-07 02:13:08 +09:00

159 lines
3.7 KiB
Ruby

# frozen_string_literal: true
class Prog::Vnet::NicNexus < Prog::Base
subject_is :nic
def self.assemble(private_subnet_id, name: nil, ipv6_addr: nil, ipv4_addr: nil)
unless (subnet = PrivateSubnet[private_subnet_id])
fail "Given subnet doesn't exist with the id #{private_subnet_id}"
end
ubid = Nic.generate_ubid
id = ubid.to_uuid
name ||= Nic.ubid_to_name(ubid)
ipv6_addr ||= subnet.random_private_ipv6.to_s
ipv4_addr ||= subnet.random_private_ipv4.to_s
DB.transaction do
Nic.create_with_id(id, private_ipv6: ipv6_addr, private_ipv4: ipv4_addr, mac: gen_mac, name:, private_subnet_id:)
label = if subnet.location.aws?
"create_aws_nic"
else
"wait_allocation"
end
Strand.create_with_id(id, prog: "Vnet::NicNexus", label:)
end
end
def before_run
when_destroy_set? do
hop_destroy if strand.label != "destroy"
end
end
label def create_aws_nic
nap 10 unless nic.private_subnet.strand.label == "wait"
NicAwsResource.create_with_id(nic.id)
bud Prog::Aws::Nic, {"subject_id" => nic.id}, :create_network_interface
hop_wait_aws_nic_created
end
label def wait_aws_nic_created
reap(:wait, nap: 10)
end
label def wait_allocation
when_vm_allocated_set? do
hop_wait_setup
end
nap 5
end
label def wait_setup
decr_vm_allocated
when_setup_nic_set? do
DB.transaction do
decr_setup_nic
nic.private_subnet.incr_add_new_nic
end
end
when_start_rekey_set? do
hop_start_rekey
end
nap 5
end
label def wait
if nic.private_subnet.location.aws?
nic.semaphores.each(&:destroy)
nap 60 * 60 * 24 * 365
end
when_repopulate_set? do
nic.private_subnet.incr_refresh_keys
decr_repopulate
end
when_start_rekey_set? do
hop_start_rekey
end
nap 6 * 60 * 60
end
label def start_rekey
decr_start_rekey
if retval&.dig("msg") == "inbound_setup is complete"
hop_wait_rekey_outbound_trigger
end
push Prog::Vnet::RekeyNicTunnel, {}, :setup_inbound
end
label def wait_rekey_outbound_trigger
if retval&.dig("msg") == "outbound_setup is complete"
hop_wait_rekey_old_state_drop_trigger
end
when_trigger_outbound_update_set? do
decr_trigger_outbound_update
push Prog::Vnet::RekeyNicTunnel, {}, :setup_outbound
end
nap 5
end
label def wait_rekey_old_state_drop_trigger
if retval&.dig("msg")&.include?("drop_old_state is complete")
hop_wait
end
when_old_state_drop_trigger_set? do
decr_old_state_drop_trigger
push Prog::Vnet::RekeyNicTunnel, {}, :drop_old_state
end
nap 5
end
label def destroy
if nic.vm
Clog.emit("Cannot destroy nic with active vm, first clean up the attached resources") { nic }
nap 5
end
decr_destroy
if nic.private_subnet.location.aws?
strand.children.select { it.prog == "Aws::Nic" }.each { it.destroy }
bud Prog::Aws::Nic, {"subject_id" => nic.id}, :destroy
hop_wait_aws_nic_destroyed
end
nic.private_subnet.incr_refresh_keys
nic.destroy
pop "nic deleted"
end
label def wait_aws_nic_destroyed
reap(nap: 10) do
nic.private_subnet.incr_refresh_keys
nic.destroy
pop "nic deleted"
end
end
# Generate a MAC with the "local" (generated, non-manufacturer) bit
# set and the multicast bit cleared in the first octet.
#
# Accuracy here is not a formality: otherwise assigning a ipv6 link
# local address errors out.
def self.gen_mac
([rand(256) & 0xFE | 0x02] + Array.new(5) { rand(256) }).map {
"%0.2X" % it
}.join(":").downcase
end
end