class Chef::Provider::Route

Constants

MASK

Attributes

is_running[RW]

Public Instance Methods

config_file_contents(action, options = {}) click to toggle source
# File lib/chef/provider/route.rb, line 231
def config_file_contents(action, options = {})
  content = ""
  case action
  when :add
    content << "# #{options[:comment]}\n" if options[:comment]
    content << (options[:target]).to_s
    content << "/#{MASK[options[:netmask].to_s]}" if options[:netmask]
    content << " via #{options[:gateway]}" if options[:gateway]
    content << " dev #{options[:device]}" if options[:device]
    content << " metric #{options[:metric]}" if options[:metric]
    content << "\n"
  end

  content
end
generate_command(action) click to toggle source
# File lib/chef/provider/route.rb, line 213
def generate_command(action)
  target = new_resource.target
  target = "#{target}/#{MASK[new_resource.netmask.to_s]}" if new_resource.netmask

  case action
  when :add
    command = [ "ip", "route", "replace", target ]
    command += [ "via", new_resource.gateway ] if new_resource.gateway
    command += [ "dev", new_resource.device ] if new_resource.device
    command += [ "metric", new_resource.metric ] if new_resource.metric
  when :delete
    command = [ "ip", "route", "delete", target ]
    command += [ "via", new_resource.gateway ] if new_resource.gateway
  end

  command
end
generate_config() click to toggle source
# File lib/chef/provider/route.rb, line 162
def generate_config
  if platform_family?("rhel", "amazon", "fedora")
    conf = {}
    # FIXME FIXME FIXME FIXME: whatever this walking-the-run-context API is, it needs to be removed.
    # walk the collection
    rc = run_context.parent_run_context || run_context
    rc.resource_collection.each do |resource|
      next unless resource.is_a? Chef::Resource::Route

      # default to eth0
      dev = resource.device || "eth0"

      conf[dev] = "" if conf[dev].nil?
      case @action
      when :add
        conf[dev] << config_file_contents(:add, comment: resource.comment, device: resource.device, target: resource.target, metric: resource.metric, netmask: resource.netmask, gateway: resource.gateway) if resource.action == [:add]
      when :delete
        # need to do this for the case when the last route on an int
        # is removed
        conf[dev] << config_file_contents(:delete)
      end
    end
    conf.each_key do |k|
      if new_resource.target == "default"
        network_file_name = "/etc/sysconfig/network"
        converge_by("write route default route to #{network_file_name}") do
          logger.trace("#{new_resource} writing default route #{new_resource.gateway} to #{network_file_name}")
          if ::File.exist?(network_file_name)
            network_file = ::Chef::Util::FileEdit.new(network_file_name)
            network_file.search_file_replace_line(/^GATEWAY=/, "GATEWAY=#{new_resource.gateway}")
            network_file.insert_line_if_no_match(/^GATEWAY=/, "GATEWAY=#{new_resource.gateway}")
            network_file.write_file
          else
            network_file = ::File.new(network_file_name, "w")
            network_file.puts("GATEWAY=#{new_resource.gateway}")
            network_file.close
          end
        end
      else
        network_file_name = "/etc/sysconfig/network-scripts/route-#{k}"
        converge_by("write route route.#{k}\n#{conf[k]} to #{network_file_name}") do
          network_file = ::File.new(network_file_name, "w")
          network_file.puts(conf[k])
          logger.trace("#{new_resource} writing route.#{k}\n#{conf[k]}")
          network_file.close
        end
      end
    end
  end
end
hex2ip(hex_data) click to toggle source
# File lib/chef/provider/route.rb, line 66
def hex2ip(hex_data)
  # Cleanup hex data
  hex_ip = hex_data.to_s.downcase.gsub(/[^0-9a-f]/, "")

  # Check hex data format (IP is a 32bit integer, so should be 8 chars long)
  return nil if hex_ip.length != hex_data.length || hex_ip.length != 8

  # Extract octets from hex data
  octets = hex_ip.scan(/../).reverse.collect { |octet| [octet].pack("H2").unpack("C").first }

  # Validate IP
  ip = octets.join(".")
  begin
    IPAddr.new(ip, Socket::AF_INET).to_s
  rescue ArgumentError
    logger.trace("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}")
    nil
  end
end
load_current_resource() click to toggle source
# File lib/chef/provider/route.rb, line 86
def load_current_resource
  self.is_running = false

  # cidr or quad dot mask
  new_ip = if new_resource.target == "default"
             IPAddr.new(new_resource.gateway)
           elsif new_resource.netmask
             IPAddr.new("#{new_resource.target}/#{new_resource.netmask}")
           else
             IPAddr.new(new_resource.target)
           end

  # For linux, we use /proc/net/route file to read proc table info
  return unless linux?

  route_file = ::File.open("/proc/net/route", "r")

  # Read all routes
  while (line = route_file.gets)
    # Get all the fields for a route
    _, destination, gateway, _, _, _, _, mask = line.split

    # Convert hex-encoded values to quad-dotted notation (e.g. 0064A8C0 => 192.168.100.0)
    destination = hex2ip(destination)
    gateway = hex2ip(gateway)
    mask = hex2ip(mask)

    # Skip formatting lines (header, etc)
    next unless destination && gateway && mask

    logger.trace("#{new_resource} system has route: dest=#{destination} mask=#{mask} gw=#{gateway}")

    # check if what were trying to configure is already there
    # use an ipaddr object with ip/mask this way we can have
    # a new resource be in cidr format (i don't feel like
    # expanding bitmask by hand.
    #
    running_ip = IPAddr.new("#{destination}/#{mask}")
    logger.trace("#{new_resource} new ip: #{new_ip.inspect} running ip: #{running_ip.inspect}")
    self.is_running = true if running_ip == new_ip && gateway == new_resource.gateway
  end

  route_file.close
end