mirror of
https://github.com/ubicloud/ubicloud.git
synced 2025-10-05 14:23:03 +08:00
Instead of creating separate EIPs, runner instances now rely on AWS to assign public IPs during instance creation, simplifying the networking setup and reducing resource overhead.
168 lines
6.3 KiB
Ruby
168 lines
6.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "aws-sdk-ec2"
|
|
class Prog::Aws::Nic < Prog::Base
|
|
subject_is :nic
|
|
|
|
label def create_subnet
|
|
register_deadline("attach_eip_network_interface", 3 * 60)
|
|
vpc_response = client.describe_vpcs({filters: [{name: "vpc-id", values: [private_subnet.private_subnet_aws_resource.vpc_id]}]}).vpcs[0]
|
|
ipv_6_cidr_block = NetAddr::IPv6Net.parse(vpc_response.ipv_6_cidr_block_association_set[0].ipv_6_cidr_block).nth_subnet(64, SecureRandom.random_number(2**8))
|
|
subnet_response = client.describe_subnets({filters: [{name: "tag:Name", values: [nic.name]}]})
|
|
subnet_id = if private_subnet.old_aws_subnet?
|
|
client.describe_subnets({filters: [{name: "vpc-id", values: [private_subnet.private_subnet_aws_resource.vpc_id]}]}).subnets[0].subnet_id
|
|
elsif subnet_response.subnets.empty?
|
|
subnet_id = client.create_subnet({
|
|
vpc_id: private_subnet.private_subnet_aws_resource.vpc_id,
|
|
cidr_block: NetAddr::IPv4Net.new(nic.private_ipv4.network, NetAddr::Mask32.new(24)).to_s,
|
|
ipv_6_cidr_block: ipv_6_cidr_block.to_s,
|
|
availability_zone: private_subnet.location.name + az_to_provision_subnet,
|
|
tag_specifications: Util.aws_tag_specifications("subnet", nic.name)
|
|
}).subnet.subnet_id
|
|
client.modify_subnet_attribute({
|
|
subnet_id:,
|
|
assign_ipv_6_address_on_creation: {value: true}
|
|
})
|
|
subnet_id
|
|
else
|
|
subnet_response.subnets[0].subnet_id
|
|
end
|
|
nic.nic_aws_resource.update(subnet_id:, subnet_az: az_to_provision_subnet)
|
|
|
|
hop_wait_subnet_created
|
|
end
|
|
|
|
label def wait_subnet_created
|
|
subnet_response = if private_subnet.old_aws_subnet?
|
|
hop_create_network_interface
|
|
else
|
|
client.describe_subnets({filters: [{name: "tag:Name", values: [nic.name]}]}).subnets[0]
|
|
end
|
|
|
|
if subnet_response.state == "available"
|
|
route_table_response = client.describe_route_tables({filters: [{name: "vpc-id", values: [private_subnet.private_subnet_aws_resource.vpc_id]}]})
|
|
route_table_id = route_table_response.route_tables[0].route_table_id
|
|
route_table_details = client.describe_route_tables({route_table_ids: [route_table_id]}).route_tables.first
|
|
if route_table_details.associations.empty?
|
|
client.associate_route_table({
|
|
route_table_id:,
|
|
subnet_id: nic.nic_aws_resource.subnet_id
|
|
})
|
|
end
|
|
|
|
# Runner instances don't need to have EIP, so we pop here.
|
|
# Public IP will be assigned by AWS while creating the instance.
|
|
pop "subnet created" if is_runner?
|
|
|
|
hop_create_network_interface
|
|
end
|
|
nap 1
|
|
end
|
|
|
|
label def create_network_interface
|
|
network_interface_response = client.create_network_interface({
|
|
subnet_id: nic.nic_aws_resource.subnet_id,
|
|
private_ip_address: nic.private_ipv4.network.to_s,
|
|
ipv_6_prefix_count: 1,
|
|
groups: [
|
|
nic.private_subnet.private_subnet_aws_resource.security_group_id
|
|
],
|
|
tag_specifications: Util.aws_tag_specifications("network-interface", nic.name),
|
|
client_token: nic.id
|
|
})
|
|
network_interface_id = network_interface_response.network_interface.network_interface_id
|
|
nic.nic_aws_resource.update(network_interface_id:)
|
|
|
|
hop_assign_ipv6_address
|
|
end
|
|
|
|
label def assign_ipv6_address
|
|
client.assign_ipv_6_addresses({network_interface_id: nic.nic_aws_resource.network_interface_id, ipv_6_address_count: 1}) if get_network_interface.ipv_6_addresses.empty?
|
|
hop_wait_network_interface_created
|
|
end
|
|
|
|
label def wait_network_interface_created
|
|
if get_network_interface.status == "available"
|
|
hop_allocate_eip
|
|
end
|
|
|
|
nap 1
|
|
end
|
|
|
|
label def allocate_eip
|
|
eip_response = client.describe_addresses({filters: [{name: "tag:Name", values: [nic.name]}]})
|
|
eip_allocation_id = if eip_response.addresses.empty?
|
|
client.allocate_address(tag_specifications: Util.aws_tag_specifications("elastic-ip", nic.nic_aws_resource.network_interface_id)).allocation_id
|
|
else
|
|
eip_response.addresses[0].allocation_id
|
|
end
|
|
|
|
nic.nic_aws_resource.update(eip_allocation_id:)
|
|
hop_attach_eip_network_interface
|
|
end
|
|
|
|
label def attach_eip_network_interface
|
|
eip_response = client.describe_addresses({filters: [{name: "allocation-id", values: [nic.nic_aws_resource.eip_allocation_id]}]})
|
|
if eip_response.addresses.first.network_interface_id.nil?
|
|
client.associate_address({allocation_id: nic.nic_aws_resource.eip_allocation_id, network_interface_id: nic.nic_aws_resource.network_interface_id})
|
|
end
|
|
pop "nic created"
|
|
end
|
|
|
|
label def destroy
|
|
ignore_invalid_nic do
|
|
client.delete_network_interface({network_interface_id: nic.nic_aws_resource.network_interface_id})
|
|
end
|
|
hop_release_eip
|
|
end
|
|
|
|
label def release_eip
|
|
ignore_invalid_nic do
|
|
allocation_id = nic.nic_aws_resource&.eip_allocation_id
|
|
client.release_address({allocation_id: allocation_id}) if allocation_id
|
|
end
|
|
hop_delete_subnet
|
|
end
|
|
|
|
label def delete_subnet
|
|
ignore_invalid_nic do
|
|
client.delete_subnet({subnet_id: nic.nic_aws_resource.subnet_id})
|
|
rescue Aws::EC2::Errors::DependencyViolation => e
|
|
raise e if private_subnet.nics.count == 1
|
|
Clog.emit("dependency violation for aws nic") { {ignored_aws_nic_failure: {exception: Util.exception_to_hash(e, backtrace: nil)}} }
|
|
end
|
|
pop "nic destroyed"
|
|
end
|
|
|
|
def client
|
|
@client ||= nic.private_subnet.location.location_credential.client
|
|
end
|
|
|
|
def private_subnet
|
|
@private_subnet ||= nic.private_subnet
|
|
end
|
|
|
|
def az_to_provision_subnet
|
|
frame["availability_zone"] || (["a", "b", "c"] - (frame["exclude_availability_zones"] || [])).sample || "a"
|
|
end
|
|
|
|
def get_network_interface
|
|
client.describe_network_interfaces({filters: [{name: "network-interface-id", values: [nic.nic_aws_resource.network_interface_id]}, {name: "tag:Ubicloud", values: ["true"]}]}).network_interfaces[0]
|
|
end
|
|
|
|
def is_runner?
|
|
nic.vm&.unix_user == "runneradmin"
|
|
end
|
|
|
|
private
|
|
|
|
def ignore_invalid_nic
|
|
yield
|
|
rescue ArgumentError,
|
|
Aws::EC2::Errors::InvalidNetworkInterfaceIDNotFound,
|
|
Aws::EC2::Errors::InvalidAllocationIDNotFound,
|
|
Aws::EC2::Errors::InvalidAddressIDNotFound,
|
|
Aws::EC2::Errors::InvalidSubnetIDNotFound => e
|
|
Clog.emit("ID not found for aws nic") { {ignored_aws_nic_failure: {exception: Util.exception_to_hash(e, backtrace: nil)}} }
|
|
end
|
|
end
|