Files
ubicloud/prog/vnet/nic_nexus.rb
Furkan Sahin 7ed27c3c4e Don't perform any work for subnet and nics in wait if aws?
If the location is aws? we don't need to do anything in SubnetNexus and
NicNexus except for provisioning and destroy. One exception is the
distribution of firewall update to the VMs which we move into its own
method and call.
2025-07-07 11:15:08 +02:00

158 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
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 = Nic.create(private_ipv6: ipv6_addr, private_ipv4: ipv4_addr, mac: gen_mac, name: name, private_subnet_id: private_subnet_id) { it.id = ubid.to_uuid }
label = if subnet.location.aws?
"create_aws_nic"
else
"wait_allocation"
end
Strand.create(prog: "Vnet::NicNexus", label:) { it.id = nic.id }
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 { it.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