Trying to convert some configuration files to a different output

How you doing? I'm trying to make my life easier in translating some
configuration files from an old version to a new one, and I'm
stuck/frustrated since I'm new to Ruby. Basically i would need a script
to convert from this input:

route-map 6300-test-in permit 5
match as-path 1
set local-preference 90
set community 65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613
!
route-map 6300-test-in permit 10
match ip address prefix-list 6300-pref-low
set local-preference 90
set community 65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613
!
route-map 6300-test-in permit 5000
set local-preference 200
set community 65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613

to this output:
route-policy 6300-test-in
apply bogons
if as-path in aspath1 then
set local-preference 90
set community (65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613)
elseif destination in 6300-pref-low then
set local-preference 90
set community (65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613)
else
set local-preference 200
set community 65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613)
endif
end-policy

I tried with line.match but it doesn't really help since half the
configuration just repeats by section. Was trying to hash the input but
just
getting nowhere. Any help would be appreciated.

thanks

···

--
Posted via http://www.ruby-forum.com/.

Well you seem to have quite a few changes in there. Have you looked into
regular expressions? That might be enough to match a pattern and make
your changes.
http://rubular.com/

Without multiple examples and the rules laid out clearly it'd be
difficult to write something flexible enough to cover a repetitive task.

I'd start out with something like
output =
input.gsub("#{input.match(/[\d:\s]{60,}/).to_s.strip}","(#{input.match(/[\d:\s]{60,}/).to_s.strip})")

That'd add the parentheses where you seem to want them, assuming your
number sequence is identical in each line as in your example. You should
be able to use variations on this kind of approach for the rest of the
changes.

Maybe someone else will come up with a more efficient method :slight_smile:

···

--
Posted via http://www.ruby-forum.com/.

=begin
A note about the structure:

* a route map has a name and a list of entries
* a route map entry has a priority (in Cisco world anyway), a list
  of matches, and a list of actions

So let's make an object which holds the data for one route map entry
=end

class RouteMapEntry
  attr_accessor :priority, :conditions, :actions
  def initialize
    @priority = nil
    @conditions = []
    @actions = []
  end
end

=begin
Parsing a single route map entry is pretty simple; we can use regular
expressions to match the 'match' and 'set' lines, and convert them to
the relevant Juniper form before storing them in a RouteMapEntry.

For flexibility, we will write this parser so it assumes that the first
line (the route-map header) has already been parsed, and it returns the
first unparseable line. This allows us easily to assemble different
parsers
if we want to parse an entire Cisco config.
=end

def parse_cisco_routemap_entry(src, priority)
  rme = RouteMapEntry.new
  rme.priority = priority
  loop do
    line = src.gets
    line.strip! if line # remove leading/trailing whitespace
    case line
    when /^match as-path (\d+)$/
      rme.conditions << "as-path in aspath#{$1}"
    when /^match ip address prefix-list (\S+)$/
      rme.conditions << "destination in #{$1}"
    when /^set local-preference (\d+)$/
      rme.actions << "set local-preference #{$1}"
    when /^set community (.*)$/
      rme.actions << "set community (#{$1})"
    # add more here as required
    else
      # EOF or any unrecognised line terminates this routemap entry
      return [rme, line]
    end
  end
end

=begin
So now we parse a whole series of routemaps. In general a config
may have multiple named routemaps, so we build a hash of them.
=end

def parse_cisco_routemaps(src)
  routemaps = {} # {"name" => [RouteMapEntry, RouteMapEntry, ...]}
  line = src.gets
  while line
    line.strip! # remove leading/trailing whitespace
    case line
    when /^!/, /^\s*$/
      # skip comment or empty line
      line = src.gets
    when /^route-map (\S+) permit (\d+)$/
      name, priority = $1, $2.to_i
      rme, line = parse_cisco_routemap_entry(src, priority)
      routemaps[name] ||= []
      routemaps[name] << rme
    else
      $stderr.puts "Unrecognized line: #{line.inspect}"
      line = src.gets
    end
  end
  return routemaps
end

=begin
We need to be able to assemble a list of routemaps into Juniper form
=end

def write_juniper_routemaps(routemaps, dest=$stdout)
  routemaps.each do |name,routemap_entries|
    dest << "route-policy #{name}\n"
    dest << " apply bogons\n"
    routemap_entries = routemap_entries.sort_by { |e| e.priority }
    cond = "if"
    routemap_entries.each do |rme|
      if rme.conditions.empty?
        dest << " else\n"
      else
        dest << " #{cond} #{rme.conditions.join(" and ")} then\n"
      end
      rme.actions.each do |action|
        dest << " #{action}\n"
      end
      break if rme.conditions.empty?
      cond = "elseif"
    end
    dest << " endif\n"
    dest << "end-policy\n"
  end
end

# Testing

src = <<EOS
route-map 6300-test-in permit 5
match as-path 1
set local-preference 90
set community 65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613
!
route-map 6300-test-in permit 10
match ip address prefix-list 6300-pref-low
set local-preference 90
set community 65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613
!
route-map 6300-test-in permit 5000
set local-preference 200
set community 65000:1 65000:3 65000:1000 65000:3000 65000:3500
65000:3613
EOS

require 'stringio'
rms = parse_cisco_routemaps(StringIO.new(src))
write_juniper_routemaps(rms)

# Real main program might look like this:
# rms = parse_cisco_routemaps($stdin)
# write_juniper_routemaps(rms)

···

--
Posted via http://www.ruby-forum.com/.