class Chef::Provider::AwsRouteTable

Attributes

vpc[RW]

Public Instance Methods

action_create() click to toggle source
Calls superclass method
# File lib/chef/provider/aws_route_table.rb, line 9
def action_create
  route_table = super

  unless new_resource.routes.nil?
    update_routes(vpc, route_table, new_resource.ignore_route_targets)
  end

  update_virtual_private_gateways(route_table, new_resource.virtual_private_gateways)
end

Protected Instance Methods

create_aws_object() click to toggle source
# File lib/chef/provider/aws_route_table.rb, line 21
def create_aws_object
  options = {}
  options[:vpc_id] = new_resource.vpc
  options = AWSResource.lookup_options(options, resource: new_resource)

  ec2_resource = new_resource.driver.ec2_resource
  self.vpc = ec2_resource.vpc(options[:vpc_id])

  converge_by "create route table #{new_resource.name} in VPC #{new_resource.vpc} (#{vpc.id}) and region #{region}" do
    route_table = vpc.create_route_table
    retry_with_backoff(::Aws::EC2::Errors::ServiceError) do
      route_table.create_tags(
        tags: [
          {
            key: "Name",
            value: new_resource.name
          }
        ]
      )
    end
    route_table
  end
end
destroy_aws_object(route_table) click to toggle source
# File lib/chef/provider/aws_route_table.rb, line 56
def destroy_aws_object(route_table)
  converge_by "delete #{new_resource} in #{region}" do
    begin
      route_table.delete
    rescue ::Aws::EC2::Errors::DependencyViolation
      raise "#{new_resource} could not be deleted because it is the main route table for #{route_table.vpc.id} or it is being used by a subnet"
    end
  end
end
update_aws_object(route_table) click to toggle source
# File lib/chef/provider/aws_route_table.rb, line 45
def update_aws_object(route_table)
  self.vpc = route_table.vpc

  if new_resource.vpc
    desired_vpc_id = Chef::Resource::AwsVpc.get_aws_object_id(new_resource.vpc, resource: new_resource)
    if vpc.id != desired_vpc_id
      raise "VPC of route table #{new_resource} is #{vpc.id}, but desired VPC is #{desired_vpc_id}!  The AWS SDK does not support updating the main route table except by creating a new route table."
    end
  end
end

Private Instance Methods

get_route_target(vpc, route_target) click to toggle source
# File lib/chef/provider/aws_route_table.rb, line 134
def get_route_target(vpc, route_target)
  case route_target
  when :internet_gateway
    if vpc.internet_gateways.first.nil?
      raise "VPC #{new_resource.vpc} (#{vpc.id}) does not have an internet gateway to route to! Use `internet_gateway true` on the VPC itself to create one."
    end
    route_target = { internet_gateway: vpc.internet_gateways.first.id }
  when /^igw-[A-Fa-f0-9]+$/, Chef::Resource::AwsInternetGateway, ::Aws::EC2::InternetGateway
    route_target = { internet_gateway: route_target }
  when /^nat-[A-Fa-f0-9]+$/, Chef::Resource::AwsNatGateway, ::Aws::EC2::NatGateway
    route_target = { nat_gateway: route_target }
  when /^eni-[A-Fa-f0-9]+$/, Chef::Resource::AwsNetworkInterface, ::Aws::EC2::NetworkInterface
    route_target = { network_interface: route_target }
  when /^pcx-[A-Fa-f0-9]+$/, Chef::Resource::AwsVpcPeeringConnection, ::Aws::EC2::VpcPeeringConnection
    route_target = { vpc_peering_connection: route_target }
  when /^vgw-[A-Fa-f0-9]+$/
    route_target = { virtual_private_gateway: route_target }
  when String, Chef::Resource::AwsInstance
    route_target = { instance: route_target }
  when Chef::Resource::Machine
    route_target = { instance: route_target.name }
  when ::Aws::EC2::Instance, ::Aws::EC2::Instance
    route_target = { instance: route_target.id }
  when Hash
    if route_target.size != 1
      raise "Route target #{route_target} must have exactly one key, either :internet_gateway, :instance or :network_interface!"
    end
    route_target = route_target.dup
  else
    raise "Unrecognized route destination #{route_target.inspect}"
  end
  updated_route_target = {}
  route_target.each do |name, value|
    case name
    when :instance
      updated_route_target[:instance_id] = Chef::Resource::AwsInstance.get_aws_object_id(value, resource: new_resource)
    when :network_interface
      updated_route_target[:network_interface_id] = Chef::Resource::AwsNetworkInterface.get_aws_object_id(value, resource: new_resource)
    when :internet_gateway
      updated_route_target[:gateway_id] = Chef::Resource::AwsInternetGateway.get_aws_object_id(value, resource: new_resource)
    when :nat_gateway
      updated_route_target[:nat_gateway_id] = Chef::Resource::AwsNatGateway.get_aws_object_id(value, resource: new_resource)
    when :vpc_peering_connection
      updated_route_target[:vpc_peering_connection_id] = Chef::Resource::AwsVpcPeeringConnection.get_aws_object_id(value, resource: new_resource)
    when :virtual_private_gateway
      updated_route_target[:gateway_id] = value
    end
  end
  updated_route_target
end
update_routes(vpc, route_table, ignore_route_targets = []) click to toggle source
# File lib/chef/provider/aws_route_table.rb, line 70
def update_routes(vpc, route_table, ignore_route_targets = [])
  # Collect current routes
  current_routes = {}
  route_table.routes.each do |route|
    # Ignore the automatic local route
    next if route.nil?
    route_target = route.gateway_id || route.nat_gateway_id || route.instance_id || route.network_interface_id || route.vpc_peering_connection_id
    next if route_target == "local"
    next if ignore_route_targets.find { |target| route_target.match(/#{target}/) }
    current_routes[route.destination_cidr_block] = route
  end

  # Add or replace routes from `routes`
  new_resource.routes.each do |destination_cidr_block, route_target|
    options = get_route_target(vpc, route_target)
    target = options.values.first
    # If we already have a route to that CIDR block, replace it.
    if current_routes[destination_cidr_block]
      current_route = current_routes.delete(destination_cidr_block)
      current_target = current_route.gateway_id || current_route.nat_gateway_id || current_route.instance_id || current_route.network_interface_id || current_route.vpc_peering_connection_id
      if current_target != target
        action_handler.perform_action "reroute #{destination_cidr_block} to #{route_target} (#{target}) instead of #{current_target}" do
          current_route.replace(options)
        end
      end
    else
      action_handler.perform_action "route #{destination_cidr_block} to #{route_target} (#{target})" do
        route_table.create_route({ destination_cidr_block: destination_cidr_block }.merge(options))
      end
    end
  end

  # Delete anything that's left (that wasn't replaced)
  current_routes.values.each do |current_route|
    current_target = current_route.gateway_id || current_route.nat_gateway_id || current_route.instance_id || current_route.network_interface_id || current_route.vpc_peering_connection_id
    action_handler.perform_action "remove route sending #{current_route.destination_cidr_block} to #{current_target}" do
      current_route.delete
    end
  end
end
update_virtual_private_gateways(route_table, gateway_ids) click to toggle source
# File lib/chef/provider/aws_route_table.rb, line 111
def update_virtual_private_gateways(route_table, gateway_ids)
  current_propagating_vgw_set = route_table.propagating_vgws

  # Add propagated routes
  if gateway_ids
    gateway_ids.each do |gateway_id|
      next if current_propagating_vgw_set.reject! { |vgw_set| vgw_set[:gateway_id] == gateway_id }
      action_handler.perform_action "enable route propagation for route table #{route_table.id} to virtual private gateway #{gateway_id}" do
        route_table.client.enable_vgw_route_propagation(route_table_id: route_table.id, gateway_id: gateway_id)
      end
    end
  end

  # Delete anything that's left
  if current_propagating_vgw_set
    current_propagating_vgw_set.each do |vgw_set|
      action_handler.perform_action "disabling route propagation for route table #{route_table.id} from virtual private gateway #{vgw_set[:gateway_id]}" do
        route_table.client.disable_vgw_route_propagation(route_table_id: route_table.id, gateway_id: vgw_set[:gateway_id])
      end
    end
  end
end