netconf 0.2.1
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.
- data/examples/jnpr/edit-config-jnpr-set.rb +55 -0
- data/examples/jnpr/edit-config-jnpr-text.rb +64 -0
- data/examples/jnpr/edit-config-jnpr.rb +62 -0
- data/examples/jnpr/edit-config-std.rb +65 -0
- data/examples/jnpr/edit-config-text-std.rb +69 -0
- data/examples/jnpr/get-config-jnpr.rb +59 -0
- data/examples/jnpr/get-config-matching.rb +20 -0
- data/examples/jnpr/get-config-std.rb +49 -0
- data/examples/jnpr/get-inventory-serial-explicit.rb +29 -0
- data/examples/jnpr/get-inventory-serial.rb +29 -0
- data/examples/jnpr/get-inventory-telnet.rb +15 -0
- data/examples/jnpr/get-inventory.rb +19 -0
- data/examples/jnpr/scp.rb +22 -0
- data/lib/net/netconf.rb +14 -0
- data/lib/net/netconf/exception.rb +38 -0
- data/lib/net/netconf/jnpr.rb +8 -0
- data/lib/net/netconf/jnpr/rpc.rb +134 -0
- data/lib/net/netconf/jnpr/serial.rb +17 -0
- data/lib/net/netconf/jnpr/telnet.rb +23 -0
- data/lib/net/netconf/localhost.rb +9 -0
- data/lib/net/netconf/rpc.rb +71 -0
- data/lib/net/netconf/rpc_std.rb +137 -0
- data/lib/net/netconf/serial.rb +132 -0
- data/lib/net/netconf/ssh.rb +77 -0
- data/lib/net/netconf/telnet.rb +58 -0
- data/lib/net/netconf/transport.rb +113 -0
- metadata +103 -0
@@ -0,0 +1,29 @@
|
|
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
|
+
binding.pry
|
26
|
+
|
27
|
+
dev.close
|
28
|
+
|
29
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'net/netconf/jnpr/serial'
|
2
|
+
|
3
|
+
puts "NETCONF v.#{Netconf::VERSION}"
|
4
|
+
|
5
|
+
serial_port = '/dev/ttyS4'
|
6
|
+
|
7
|
+
login = {
|
8
|
+
:port => serial_port,
|
9
|
+
:username => "jeremy", :password => "jeremy1"
|
10
|
+
}
|
11
|
+
|
12
|
+
puts "Connecting to SERIAL: #{serial_port} ... please wait."
|
13
|
+
|
14
|
+
Netconf::Serial.new( login ){ |dev|
|
15
|
+
|
16
|
+
puts "Connected."
|
17
|
+
puts "Nabbing Inventory ..."
|
18
|
+
|
19
|
+
inv = dev.rpc.get_chassis_inventory
|
20
|
+
|
21
|
+
puts "Chassis: " + inv.xpath('chassis/description').text
|
22
|
+
puts "Chassis Serial-Number: " + inv.xpath('chassis/serial-number').text
|
23
|
+
|
24
|
+
binding.pry
|
25
|
+
|
26
|
+
}
|
27
|
+
|
28
|
+
|
29
|
+
|
@@ -0,0 +1,15 @@
|
|
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
|
+
binding.pry
|
13
|
+
}
|
14
|
+
|
15
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'net/netconf'
|
2
|
+
|
3
|
+
puts "NETCONF v.#{Netconf::VERSION}"
|
4
|
+
|
5
|
+
login = { :target => '192.168.10.2',
|
6
|
+
:username => "jeremy",
|
7
|
+
:password => "jeremy1" }
|
8
|
+
|
9
|
+
Netconf::SSH.new( login ){ |dev|
|
10
|
+
|
11
|
+
inv = dev.rpc.get_chassis_inventory
|
12
|
+
|
13
|
+
puts "Chassis: " + inv.xpath('chassis/description').text
|
14
|
+
puts "Chassis Serial-Number: " + inv.xpath('chassis/serial-number').text
|
15
|
+
|
16
|
+
}
|
17
|
+
|
18
|
+
|
19
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'net/netconf'
|
2
|
+
require 'net/scp'
|
3
|
+
|
4
|
+
login = { :target => 'vsrx', :username => "jeremy" }
|
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
|
+
|
data/lib/net/netconf.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
require 'nokogiri'
|
3
|
+
|
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
|
+
VERSION = "0.2.1"
|
11
|
+
DEFAULT_OS_TYPE = :JUNOS
|
12
|
+
DEFAULT_TIMEOUT = 10
|
13
|
+
DEFAULT_WAITIO = 0
|
14
|
+
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}"
|
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,134 @@
|
|
1
|
+
## -----------------------------------------------------------------------
|
2
|
+
## This file contains the Junos specific RPC methods that are generated
|
3
|
+
## specifically and different as generated by the Netconf::RPC::Builder
|
4
|
+
## module. These are specifically the following:
|
5
|
+
##
|
6
|
+
## get_configuration - alternative NETCONF: 'get-config'
|
7
|
+
## load_configuration - alternative NETCONF: 'edit-config'
|
8
|
+
## lock_configuration - alternative NETCONF: 'lock'
|
9
|
+
## commit_configuration - alternative NETCONF: 'commit'
|
10
|
+
##
|
11
|
+
## note: unlock_configuration is not included in this file since
|
12
|
+
## the Netconf::RPC::Builder works "as-is" in this case
|
13
|
+
## -----------------------------------------------------------------------
|
14
|
+
|
15
|
+
module Netconf
|
16
|
+
module RPC
|
17
|
+
module JUNOS
|
18
|
+
|
19
|
+
def lock_configuration
|
20
|
+
lock( 'candidate' )
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_configuration
|
24
|
+
validate( 'candidate' )
|
25
|
+
end
|
26
|
+
|
27
|
+
def commit_configuration( params = nil, attrs = nil )
|
28
|
+
rpc = Netconf::RPC::Builder.commit_configuration( params, attrs )
|
29
|
+
Netconf::RPC.set_exception( rpc, Netconf::CommitError )
|
30
|
+
@trans.rpc_exec( rpc )
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_configuration( *args )
|
34
|
+
|
35
|
+
filter = nil
|
36
|
+
|
37
|
+
while arg = args.shift
|
38
|
+
case arg.class.to_s
|
39
|
+
when /^Nokogiri/
|
40
|
+
filter = case arg
|
41
|
+
when Nokogiri::XML::Builder then arg.doc.root
|
42
|
+
when Nokogiri::XML::Document then arg.root
|
43
|
+
else arg
|
44
|
+
end
|
45
|
+
when 'Hash' then attrs = arg
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
rpc = Nokogiri::XML('<rpc><get-configuration/></rpc>').root
|
50
|
+
Netconf::RPC.add_attributes( rpc.first_element_child, attrs ) if attrs
|
51
|
+
|
52
|
+
if block_given?
|
53
|
+
Nokogiri::XML::Builder.with(rpc.at( 'get-configuration' )){ |xml|
|
54
|
+
xml.configuration {
|
55
|
+
yield( xml )
|
56
|
+
}}
|
57
|
+
elsif filter
|
58
|
+
f_node = Nokogiri::XML::Node.new( 'configuration', rpc )
|
59
|
+
f_node << filter.dup # *MUST* use the .dup so we don't disrupt the original filter
|
60
|
+
rpc.first_element_child << f_node
|
61
|
+
end
|
62
|
+
|
63
|
+
@trans.rpc_exec( rpc )
|
64
|
+
end
|
65
|
+
|
66
|
+
def load_configuration( *args )
|
67
|
+
|
68
|
+
config = nil
|
69
|
+
|
70
|
+
# default format is XML
|
71
|
+
attrs = { :format => 'xml' }
|
72
|
+
|
73
|
+
while arg = args.shift
|
74
|
+
case arg.class.to_s
|
75
|
+
when /^Nokogiri/
|
76
|
+
config = case arg
|
77
|
+
when Nokogiri::XML::Builder then arg.doc.root
|
78
|
+
when Nokogiri::XML::Document then arg.root
|
79
|
+
else arg
|
80
|
+
end
|
81
|
+
when 'Hash' then attrs = arg
|
82
|
+
when 'Array' then config = arg.join("\n")
|
83
|
+
when 'String' then config = arg
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
case attrs[:format]
|
88
|
+
when 'set'
|
89
|
+
toplevel = 'configuration-set'
|
90
|
+
attrs[:format] = 'text'
|
91
|
+
attrs[:action] = 'set'
|
92
|
+
when 'text'
|
93
|
+
toplevel = 'configuration-text'
|
94
|
+
when 'xml'
|
95
|
+
toplevel = 'configuration'
|
96
|
+
end
|
97
|
+
|
98
|
+
rpc = Nokogiri::XML('<rpc><load-configuration/></rpc>').root
|
99
|
+
ld_cfg = rpc.first_element_child
|
100
|
+
Netconf::RPC.add_attributes( ld_cfg, attrs ) if attrs
|
101
|
+
|
102
|
+
if block_given?
|
103
|
+
if attrs[:format] == 'xml'
|
104
|
+
Nokogiri::XML::Builder.with( ld_cfg ){ |xml|
|
105
|
+
xml.send( toplevel ) {
|
106
|
+
yield( xml )
|
107
|
+
}}
|
108
|
+
else
|
109
|
+
config = yield # returns String | Array(of stringable)
|
110
|
+
config = config.join("\n") if config.class == Array
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
if config
|
115
|
+
c_node = Nokogiri::XML::Node.new( toplevel, rpc )
|
116
|
+
if attrs[:format] == 'xml'
|
117
|
+
c_node << config.dup # duplicate the config so as to not distrupt it
|
118
|
+
else
|
119
|
+
# config is stringy, so just add it as the text node
|
120
|
+
c_node.content = config
|
121
|
+
end
|
122
|
+
ld_cfg << c_node
|
123
|
+
end
|
124
|
+
|
125
|
+
# set a specific exception class on this RPC so it can be
|
126
|
+
# properlly handled by the calling enviornment
|
127
|
+
|
128
|
+
Netconf::RPC::set_exception( rpc, Netconf::EditError )
|
129
|
+
@trans.rpc_exec( rpc )
|
130
|
+
end
|
131
|
+
|
132
|
+
end # module: JUNOS
|
133
|
+
end # module: RPC
|
134
|
+
end # module: Netconf
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'net/netconf'
|
2
|
+
require 'net/netconf/serial'
|
3
|
+
require 'net/netconf/jnpr'
|
4
|
+
|
5
|
+
module Netconf
|
6
|
+
module TransSerial
|
7
|
+
module JUNOS
|
8
|
+
|
9
|
+
def trans_start_netconf( last_console )
|
10
|
+
last_console.match(/[^%]\s+$/)
|
11
|
+
netconf_cmd = ($1 == '%') ? Netconf::JUNOS::NETCONF_SHELL : Netconf::JUNOS::NETCONF_CLI
|
12
|
+
puts netconf_cmd
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'net/netconf'
|
2
|
+
require 'net/netconf/telnet'
|
3
|
+
require 'net/netconf/jnpr'
|
4
|
+
|
5
|
+
module Netconf
|
6
|
+
module TransTelnet
|
7
|
+
module JUNOS
|
8
|
+
|
9
|
+
def trans_login
|
10
|
+
l_rsp = @trans.login( @args[:username], @args[:password] )
|
11
|
+
# @@@/JLS: need to rescue the timeout ... ???
|
12
|
+
l_rsp.match("([>%])\s+$")
|
13
|
+
@exec_netconf = ($1 == '%') ? Netconf::JUNOS::NETCONF_SHELL : Netconf::JUNOS::NETCONF_CLI
|
14
|
+
end
|
15
|
+
|
16
|
+
def trans_start_netconf
|
17
|
+
@trans.puts @exec_netconf
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'net/netconf/rpc_std'
|
2
|
+
|
3
|
+
module Netconf
|
4
|
+
module RPC
|
5
|
+
|
6
|
+
def RPC.add_attributes( ele_nx, attr_h )
|
7
|
+
attr_h.each{ |k,v| ele_nx[k] = v }
|
8
|
+
end
|
9
|
+
|
10
|
+
def RPC.set_exception( rpc_nx, exception )
|
11
|
+
rpc_nx.instance_variable_set(:@netconf_exception, exception )
|
12
|
+
end
|
13
|
+
|
14
|
+
def RPC.get_exception( rpc_nx )
|
15
|
+
rpc_nx.instance_variable_get(:@netconf_exception) || Netconf::RpcError
|
16
|
+
end
|
17
|
+
|
18
|
+
module Builder
|
19
|
+
# autogenerate an <rpc>, converting underscores (_)
|
20
|
+
# to hyphens (-) along the way ...
|
21
|
+
|
22
|
+
def Builder.method_missing( method, params = nil, attrs = nil )
|
23
|
+
|
24
|
+
rpc_name = method.to_s.tr('_','-').to_sym
|
25
|
+
|
26
|
+
if params
|
27
|
+
# build the XML starting at <rpc>, envelope the <method> toplevel element,
|
28
|
+
# and then create name/value elements for each of the additional params. An element
|
29
|
+
# without a value should simply be set to true
|
30
|
+
rpc_nx = Nokogiri::XML::Builder.new { |xml|
|
31
|
+
xml.rpc { xml.send( rpc_name ) {
|
32
|
+
params.each{ |k,v|
|
33
|
+
sym = k.to_s.tr('_','-').to_sym
|
34
|
+
xml.send(sym, (v==true) ? nil : v )
|
35
|
+
}
|
36
|
+
}}
|
37
|
+
}.doc.root
|
38
|
+
else
|
39
|
+
# -- no params
|
40
|
+
rpc_nx = Nokogiri::XML("<rpc><#{rpc_name}/></rpc>").root
|
41
|
+
end
|
42
|
+
|
43
|
+
# if a block is given it is used to set the attributes of the toplevel element
|
44
|
+
RPC.add_attributes( rpc_nx.at( rpc_name ), attrs ) if attrs
|
45
|
+
|
46
|
+
# return the rpc command
|
47
|
+
rpc_nx
|
48
|
+
end # def: method-missing?
|
49
|
+
|
50
|
+
end # module: Builder
|
51
|
+
|
52
|
+
class Executor
|
53
|
+
include Netconf::RPC::Standard
|
54
|
+
|
55
|
+
def initialize( trans, os_type )
|
56
|
+
@trans = trans
|
57
|
+
begin
|
58
|
+
extend Netconf::RPC::const_get( os_type )
|
59
|
+
rescue NameError
|
60
|
+
# no extensions available ...
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def method_missing( method, params = nil, attrs = nil )
|
65
|
+
@trans.rpc_exec( Netconf::RPC::Builder.send( method, params, attrs ))
|
66
|
+
end
|
67
|
+
end # class: Executor
|
68
|
+
|
69
|
+
end # module: RPC
|
70
|
+
end # module: Netconf
|
71
|
+
|