summaryrefslogtreecommitdiff
path: root/lib/chef/provider/route.rb
diff options
context:
space:
mode:
authorSeth Chisamore <schisamo@opscode.com>2012-10-30 10:39:35 -0400
committerSeth Chisamore <schisamo@opscode.com>2012-10-30 10:39:35 -0400
commit24dc69a9a97e82a6e4207de68d6dcc664178249b (patch)
tree19bb289c9f88b4bbab066bc56b95d6d222fd5c35 /lib/chef/provider/route.rb
parent9348c1c9c80ee757354d624b7dc1b78ebc7605c4 (diff)
downloadchef-24dc69a9a97e82a6e4207de68d6dcc664178249b.tar.gz
[OC-3564] move core Chef to the repo root \o/ \m/
The opscode/chef repository now only contains the core Chef library code used by chef-client, knife and chef-solo!
Diffstat (limited to 'lib/chef/provider/route.rb')
-rw-r--r--lib/chef/provider/route.rb223
1 files changed, 223 insertions, 0 deletions
diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb
new file mode 100644
index 0000000000..5aedcb99ec
--- /dev/null
+++ b/lib/chef/provider/route.rb
@@ -0,0 +1,223 @@
+#
+# Author:: Bryan McLellan (btm@loftninjas.org), Jesse Nelson (spheromak@gmail.com)
+# Copyright:: Copyright (c) 2009 Bryan McLellan
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/log'
+require 'chef/mixin/command'
+require 'chef/provider'
+require 'ipaddr'
+
+class Chef::Provider::Route < Chef::Provider
+ include Chef::Mixin::Command
+
+ attr_accessor :is_running
+
+ MASK = {'0.0.0.0' => '0',
+ '128.0.0.0' => '1',
+ '192.0.0.0' => '2',
+ '224.0.0.0' => '3',
+ '240.0.0.0' => '4',
+ '248.0.0.0' => '5',
+ '252.0.0.0' => '6',
+ '254.0.0.0' => '7',
+ '255.0.0.0' => '8',
+ '255.128.0.0' => '9',
+ '255.192.0.0' => '10',
+ '255.224.0.0' => '11',
+ '255.240.0.0' => '12',
+ '255.248.0.0' => '13',
+ '255.252.0.0' => '14',
+ '255.254.0.0' => '15',
+ '255.255.0.0' => '16',
+ '255.255.128.0' => '17',
+ '255.255.192.0' => '18',
+ '255.255.224.0' => '19',
+ '255.255.240.0' => '20',
+ '255.255.248.0' => '21',
+ '255.255.252.0' => '22',
+ '255.255.254.0' => '23',
+ '255.255.255.0' => '24',
+ '255.255.255.128' => '25',
+ '255.255.255.192' => '26',
+ '255.255.255.224' => '27',
+ '255.255.255.240' => '28',
+ '255.255.255.248' => '29',
+ '255.255.255.252' => '30',
+ '255.255.255.254' => '31',
+ '255.255.255.255' => '32' }
+
+ 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
+ Chef::Log.debug("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}")
+ return nil
+ end
+ end
+
+ def whyrun_supported?
+ true
+ end
+
+ def load_current_resource
+ self.is_running = false
+
+ # cidr or quad dot mask
+ if @new_resource.netmask
+ new_ip = IPAddr.new("#{@new_resource.target}/#{@new_resource.netmask}")
+ else
+ new_ip = IPAddr.new(@new_resource.target)
+ end
+
+ # For linux, we use /proc/net/route file to read proc table info
+ if node[:os] == "linux"
+ route_file = ::File.open("/proc/net/route", "r")
+
+ # Read all routes
+ while (line = route_file.gets)
+ # Get all the fields for a route
+ iface,destination,gateway,flags,refcnt,use,metric,mask,mtu,window,irtt = 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
+ Chef::Log.debug("#{@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}")
+ Chef::Log.debug("#{@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
+ end
+
+ def action_add
+ # check to see if load_current_resource found the route
+ if is_running
+ Chef::Log.debug("#{@new_resource} route already active - nothing to do")
+ else
+ command = generate_command(:add)
+ converge_by ("run #{ command } to add route") do
+ run_command( :command => command )
+ Chef::Log.info("#{@new_resource} added")
+ end
+ end
+
+ #for now we always write the file (ugly but its what it is)
+ generate_config
+ end
+
+ def action_delete
+ if is_running
+ command = generate_command(:delete)
+ converge_by ("run #{ command } to delete route ") do
+ run_command( :command => command )
+ Chef::Log.info("#{@new_resource} removed")
+ end
+ else
+ Chef::Log.debug("#{@new_resource} route does not exist - nothing to do")
+ end
+ end
+
+ def generate_config
+ conf = Hash.new
+ case node[:platform]
+ when "centos", "redhat", "fedora"
+ # walk the collection
+ run_context.resource_collection.each do |resource|
+ if resource.is_a? Chef::Resource::Route
+ # default to eth0
+ if resource.device
+ dev = resource.device
+ else
+ dev = "eth0"
+ end
+
+ conf[dev] = String.new if conf[dev].nil?
+ if resource.action == :add
+ conf[dev] << config_file_contents(:add, :target => resource.target, :netmask => resource.netmask, :gateway => resource.gateway)
+ else
+ # need to do this for the case when the last route on an int
+ # is removed
+ conf[dev] << config_file_contents(:delete)
+ end
+ end
+ end
+ conf.each do |k, v|
+ 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])
+ Chef::Log.debug("#{@new_resource} writing route.#{k}\n#{conf[k]}")
+ network_file.close
+ end
+ end
+ end
+ end
+
+ def generate_command(action)
+ common_route_items = ''
+ common_route_items << "/#{MASK[@new_resource.netmask.to_s]}" if @new_resource.netmask
+ common_route_items << " via #{@new_resource.gateway} " if @new_resource.gateway
+
+ case action
+ when :add
+ command = "ip route replace #{@new_resource.target}"
+ command << common_route_items
+ command << " dev #{@new_resource.device} " if @new_resource.device
+ when :delete
+ command = "ip route delete #{@new_resource.target}"
+ command << common_route_items
+ end
+
+ return command
+ end
+
+ def config_file_contents(action, options={})
+ content = ''
+ case action
+ when :add
+ content << "#{options[:target]}"
+ content << "/#{options[:netmask]}" if options[:netmask]
+ content << " via #{options[:gateway]}" if options[:gateway]
+ content << "\n"
+ end
+
+ return content
+ end
+end