net-netconf 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ require 'net/netconf'
2
+
3
+ puts "NETCONF v.#{Netconf::VERSION}"
4
+
5
+ login = { :target => 'vsrx', :username => "jeremy", :password => "jeremy1" }
6
+
7
+ puts "Connecting to device: #{login[:target]}"
8
+
9
+ Netconf::SSH.new( login ){ |dev|
10
+ puts "Connected."
11
+
12
+ # ----------------------------------------------------------------------
13
+ # retrieve the full config. Default source is 'running'
14
+ # Alternatively you can pass the source name as a string parameter
15
+ # to #get_config
16
+
17
+ puts "Retrieving full config, please wait ... "
18
+ cfgall = dev.rpc.get_config
19
+ puts "Showing 'system' hierarchy ..."
20
+ puts cfgall.xpath('configuration/system') # JUNOS toplevel config element is <configuration>
21
+
22
+ # ----------------------------------------------------------------------
23
+ # specifying a filter as a block to get_config
24
+
25
+ cfgsvc1 = dev.rpc.get_config{ |x|
26
+ x.configuration { x.system { x.services }}
27
+ }
28
+
29
+ puts "Retrieved services as BLOCK:"
30
+ cfgsvc1.xpath('//services/*').each{|s| puts s.name }
31
+
32
+ # ----------------------------------------------------------------------
33
+ # specifying a filter as a parameter to get_config
34
+
35
+ filter = Nokogiri::XML::Builder.new{ |x|
36
+ x.configuration { x.system { x.services }}
37
+ }
38
+
39
+ cfgsvc2 = dev.rpc.get_config( filter )
40
+ puts "Retrieved services as PARAM:"
41
+ cfgsvc2.xpath('//services/*').each{|s| puts s.name }
42
+
43
+ cfgsvc3 = dev.rpc.get_config( filter )
44
+ puts "Retrieved services as PARAM, re-used filter"
45
+ cfgsvc3.xpath('//services/*').each{|s| puts s.name }
46
+ }
47
+
48
+
49
+
@@ -0,0 +1,27 @@
1
+ require 'net/netconf/jnpr/serial'
2
+
3
+ puts "NETCONF v.#{Netconf::VERSION}"
4
+
5
+ login = {
6
+ :port => '/dev/ttyS4',
7
+ :username => "root", :password => "juniper1"
8
+ }
9
+
10
+ # we want to mount the USB drive, so we need to explicity
11
+ # do something special when opening the serial console ...
12
+ # therefore, we can *NOT* pass a block directly to new()
13
+
14
+ dev = Netconf::Serial.new( login )
15
+ dev.open { |con|
16
+ # login has occurred successfully
17
+
18
+ con.puts 'mount_msdosfs /dev/da1s1 /mnt'
19
+
20
+ # netconf will be started once block completes
21
+ }
22
+
23
+ inv = dev.rpc.get_chassis_inventory
24
+
25
+ dev.close
26
+
27
+
@@ -0,0 +1,25 @@
1
+ require 'net/netconf/jnpr/serial'
2
+
3
+ puts "NETCONF v.#{Netconf::VERSION}"
4
+
5
+ serial_port = '/dev/ttyS4'
6
+
7
+ login = { :port => serial_port,
8
+ :username => "jeremy", :password => "jeremy1" }
9
+
10
+ puts "Connecting to SERIAL: #{serial_port} ... please wait."
11
+
12
+ Netconf::Serial.new( login ){ |dev|
13
+
14
+ puts "Connected."
15
+ puts "Nabbing Inventory ..."
16
+
17
+ inv = dev.rpc.get_chassis_inventory
18
+
19
+ puts "Chassis: " + inv.xpath('chassis/description').text
20
+ puts "Chassis Serial-Number: " + inv.xpath('chassis/serial-number').text
21
+
22
+ }
23
+
24
+
25
+
@@ -0,0 +1,14 @@
1
+ require 'net/netconf/jnpr/telnet'
2
+
3
+ puts "NETCONF v#{Netconf::VERSION}"
4
+
5
+ login = { :target => 'vsrx', :username => "jeremy", :password => "jeremy1" }
6
+
7
+ Netconf::Telnet.new( login ){ |dev|
8
+ inv = dev.rpc.get_chassis_inventory
9
+ puts "Chassis: " + inv.xpath('chassis/description').text
10
+ puts "Chassis Serial-Number: " + inv.xpath('chassis/serial-number').text
11
+
12
+ }
13
+
14
+
@@ -0,0 +1,16 @@
1
+ require 'net/netconf'
2
+
3
+ puts "NETCONF v#{Netconf::VERSION}"
4
+
5
+ login = { :target => 'vsrx', :username => "jeremy", :password => "jeremy1" }
6
+
7
+ Netconf::SSH.new( login ){ |dev|
8
+
9
+ inv = dev.rpc.get_chassis_inventory
10
+
11
+ puts "Chassis: " + inv.xpath('chassis/description').text
12
+ puts "Chassis Serial-Number: " + inv.xpath('chassis/serial-number').text
13
+ }
14
+
15
+
16
+
@@ -0,0 +1,22 @@
1
+ require 'net/netconf'
2
+ require 'net/scp'
3
+
4
+ login = { :target => 'vsrx', :username => "jeremy", :password => "jeremy1" }
5
+
6
+ file_name = __FILE__
7
+
8
+ Netconf::SSH.new( login ){ |dev|
9
+
10
+ inv = dev.rpc.get_chassis_inventory
11
+
12
+ puts "Chassis: " + inv.xpath('chassis/description').text
13
+ puts "Chassis Serial-Number: " + inv.xpath('chassis/serial-number').text
14
+
15
+ puts "Copying file #{file_name} to home directory ..."
16
+ dev.scp.upload! file_name, file_name
17
+
18
+ puts "Copying latest config file from target to local machine ..."
19
+
20
+ dev.scp.download! "/config/juniper.conf.gz", "/var/tmp/config.gz"
21
+ }
22
+
@@ -0,0 +1,24 @@
1
+ require 'nokogiri'
2
+
3
+ require 'net/netconf/version'
4
+ require 'net/netconf/rpc'
5
+ require 'net/netconf/exception'
6
+ require 'net/netconf/transport'
7
+ require 'net/netconf/ssh'
8
+
9
+ module Netconf
10
+ NAMESPACE = "urn:ietf:params:xml:ns:netconf:base:1.0"
11
+ DEFAULT_OS_TYPE = :Junos
12
+ DEFAULT_TIMEOUT = 10
13
+ DEFAULT_WAITIO = 0
14
+
15
+ @raise_on_warning = false # rpc-error with <error-severity> = 'warning' will not raise RpcError excption
16
+
17
+ def self.raise_on_warning=( bool )
18
+ @raise_on_warning = bool
19
+ end
20
+ def self.raise_on_warning
21
+ @raise_on_warning
22
+ end
23
+
24
+ end
@@ -0,0 +1,38 @@
1
+ module Netconf
2
+
3
+ class InitError < StandardError
4
+ end
5
+
6
+ class StateError < StandardError
7
+ end
8
+
9
+ class OpenError < StandardError
10
+ end
11
+
12
+ class RpcError < StandardError
13
+ attr_reader :trans
14
+ attr_reader :cmd, :rsp
15
+
16
+ def initialize( trans, cmd, rsp )
17
+ @trans = trans
18
+ @cmd = cmd; @rsp = rsp;
19
+ end
20
+
21
+ def to_s
22
+ "RPC command error: #{cmd.first_element_child.name}\n#{rsp.to_xml}"
23
+ end
24
+ end
25
+
26
+ class EditError < Netconf::RpcError
27
+ end
28
+
29
+ class LockError < Netconf::RpcError
30
+ end
31
+
32
+ class CommitError < Netconf::RpcError
33
+ end
34
+
35
+ class ValidateError < Netconf::RpcError
36
+ end
37
+
38
+ end
@@ -0,0 +1,88 @@
1
+ module Netconf
2
+
3
+ class IOProc < Netconf::Transport
4
+
5
+ DEFAULT_RDBLKSZ = (1024*1024)
6
+
7
+ attr_reader :args
8
+
9
+ def initialize( args_h = {}, &block )
10
+ os_type = args_h[:os_type] || Netconf::DEFAULT_OS_TYPE
11
+
12
+ @args = args_h.clone
13
+
14
+ # an OS specific implementation must exist to support this transport type
15
+ extend Netconf::const_get( os_type )::IOProc
16
+
17
+ @trans_timeout = @args[:timeout] || Netconf::DEFAULT_TIMEOUT
18
+ @trans_waitio = @args[:waitio] || Netconf::DEFAULT_WAITIO
19
+
20
+ super( &block )
21
+ end
22
+
23
+ # the OS specific transport must implement this method
24
+ def trans_open # :yield: self
25
+ raise "Unsupported IOProc"
26
+ end
27
+
28
+ def trans_receive_hello
29
+ trans_receive()
30
+ end
31
+
32
+ def trans_send_hello
33
+ nil
34
+ end
35
+
36
+ def trans_close
37
+ @trans.write Netconf::RPC::MSG_CLOSE_SESSION
38
+ @trans.close
39
+ end
40
+
41
+ def trans_send( cmd_str )
42
+ @trans.write( cmd_str )
43
+ end
44
+
45
+ def trans_receive
46
+ got = waitfor( Netconf::RPC::MSG_END_RE )
47
+ msg_end = got.rindex( Netconf::RPC::MSG_END )
48
+ got[msg_end .. -1] = ''
49
+ got
50
+ end
51
+
52
+ def puts( str = nil )
53
+ @trans.puts( str )
54
+ end
55
+
56
+ def waitfor( on_re )
57
+
58
+ time_out = @trans_timeout
59
+ wait_io = @trans_waitio
60
+
61
+ time_out = nil if time_out == false
62
+ done = false
63
+ rx_buf = ''
64
+
65
+ until( rx_buf.match( on_re ) and not IO::select( [@trans], nil, nil, wait_io ) )
66
+
67
+ unless IO::select( [@trans], nil, nil, time_out )
68
+ raise TimeoutError, "Netconf IO timed out while waiting for more data"
69
+ end
70
+
71
+ begin
72
+
73
+ rx_some = @trans.readpartial( DEFAULT_RDBLKSZ )
74
+
75
+ rx_buf += rx_some
76
+ break if rx_buf.match( on_re )
77
+
78
+ rescue EOFError # End of file reached
79
+ rx_buf = nil if rx_buf == ''
80
+ break # out of outer 'until' loop
81
+ end
82
+
83
+ end
84
+ rx_buf
85
+ end
86
+
87
+ end # class: IOProc
88
+ end # module: Netconf
@@ -0,0 +1,9 @@
1
+ require 'net/netconf'
2
+ require 'net/netconf/jnpr/rpc'
3
+ require 'net/netconf/jnpr/junos_config'
4
+
5
+ module Netconf::Junos
6
+ NETCONF_CLI = "junoscript netconf need-trailer"
7
+ NETCONF_SHELL = "exec xml-mode netconf need-trailer"
8
+ end
9
+
@@ -0,0 +1,14 @@
1
+ require 'net/netconf'
2
+ require 'net/netconf/ioproc'
3
+ require 'net/netconf/jnpr'
4
+
5
+ module Netconf
6
+ module Junos
7
+ module IOProc
8
+ def trans_open
9
+ @trans = IO.popen( "xml-mode netconf need-trailer", "r+")
10
+ self
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,104 @@
1
+ #
2
+ # Copyright (c) 2012 Juniper Networks, Inc.
3
+ # All Rights Reserved
4
+ #
5
+ # JUNIPER PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6
+
7
+ module Netconf
8
+
9
+ class JunosConfig
10
+
11
+ DELETE = { :delete => 'delete' }
12
+ REPLACE = { :replace => 'replace' }
13
+
14
+ attr_reader :doc
15
+ attr_reader :collection
16
+
17
+ def initialize( options )
18
+ @doc_ele = "configuration"
19
+
20
+ if options == :TOP
21
+ @doc = Nokogiri::XML("<#{@doc_ele}/>")
22
+ return
23
+ end
24
+
25
+ unless options[:TOP].nil?
26
+ @doc_ele = options[:TOP]
27
+ @doc = Nokogiri::XML("<#{@doc_ele}/>")
28
+ return
29
+ end
30
+
31
+ unless defined? @collection
32
+ edit = "#{@doc_ele}/#{options[:edit].strip}"
33
+ @at_name = edit[edit.rindex('/') + 1, edit.length]
34
+ @edit_path = edit
35
+ @collection = Hash.new
36
+ @to_xml = options[:build]
37
+ end
38
+ end
39
+
40
+ def <<( obj )
41
+ if defined? @collection
42
+ @collection[obj[:name]] = obj
43
+ elsif defined? @doc
44
+ obj.build_xml( @doc )
45
+ else
46
+ # TBD:error
47
+ end
48
+ end
49
+
50
+ def build_xml( ng_xml, &block )
51
+ at_ele = ng_xml.at( @edit_path )
52
+ if at_ele.nil?
53
+ # no xpath anchor point, so we need to create it
54
+ at_ele = edit_path( ng_xml, @edit_path )
55
+ end
56
+ build_proc = (block_given?) ? block : @to_xml
57
+
58
+ @collection.each do |k,v|
59
+ with( at_ele ) do |e|
60
+ build_proc.call( e, v )
61
+ end
62
+ end
63
+ end
64
+
65
+ def edit_path( ng_xml, xpath )
66
+ # junos configuration always begins with
67
+ # the 'configuration' element, so don't make
68
+ # the user enter it all the time
69
+
70
+ cfg_xpath = xpath
71
+ dot = ng_xml.at( cfg_xpath )
72
+ return dot if dot
73
+
74
+ # we need to determine how much of the xpath
75
+ # we need to create. walk down the xpath
76
+ # children to determine what exists and
77
+ # what needs to be added
78
+
79
+ xpath_a = cfg_xpath.split('/')
80
+ need_a = []
81
+ until xpath_a.empty? or dot
82
+ need_a.unshift xpath_a.pop
83
+ check_xpath = xpath_a.join('/')
84
+ dot = ng_xml.at( check_xpath )
85
+ end
86
+
87
+ # start at the deepest level of what
88
+ # actually exists and then start adding
89
+ # the children that were missing
90
+
91
+ dot = ng_xml.at(xpath_a.join('/'))
92
+ need_a.each do |ele|
93
+ dot = dot.add_child( Nokogiri::XML::Node.new( ele, ng_xml ))
94
+ end
95
+ return dot
96
+ end
97
+
98
+ def with( ng_xml, &block )
99
+ Nokogiri::XML::Builder.with( ng_xml, &block )
100
+ end
101
+ end
102
+ #-- class end
103
+ end
104
+