hrr_rb_netconf 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.rspec +3 -0
- data/.travis.yml +32 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE +201 -0
- data/README.md +220 -0
- data/Rakefile +6 -0
- data/demo/server.rb +54 -0
- data/demo/server_over_ssh.rb +97 -0
- data/demo/server_with_session-oriented-database.rb +134 -0
- data/demo/server_with_sessionless-database.rb +81 -0
- data/hrr_rb_netconf.gemspec +28 -0
- data/lib/hrr_rb_netconf.rb +10 -0
- data/lib/hrr_rb_netconf/logger.rb +56 -0
- data/lib/hrr_rb_netconf/server.rb +109 -0
- data/lib/hrr_rb_netconf/server/capabilities.rb +75 -0
- data/lib/hrr_rb_netconf/server/capability.rb +206 -0
- data/lib/hrr_rb_netconf/server/capability/base_1_0.rb +183 -0
- data/lib/hrr_rb_netconf/server/capability/base_1_1.rb +247 -0
- data/lib/hrr_rb_netconf/server/capability/candidate_1_0.rb +34 -0
- data/lib/hrr_rb_netconf/server/capability/confirmed_commit_1_0.rb +24 -0
- data/lib/hrr_rb_netconf/server/capability/confirmed_commit_1_1.rb +24 -0
- data/lib/hrr_rb_netconf/server/capability/rollback_on_error_1_0.rb +16 -0
- data/lib/hrr_rb_netconf/server/capability/startup_1_0.rb +22 -0
- data/lib/hrr_rb_netconf/server/capability/url_1_0.rb +23 -0
- data/lib/hrr_rb_netconf/server/capability/validate_1_0.rb +25 -0
- data/lib/hrr_rb_netconf/server/capability/validate_1_1.rb +25 -0
- data/lib/hrr_rb_netconf/server/capability/writable_running_1_0.rb +17 -0
- data/lib/hrr_rb_netconf/server/capability/xpath_1_0.rb +14 -0
- data/lib/hrr_rb_netconf/server/datastore.rb +30 -0
- data/lib/hrr_rb_netconf/server/datastore/oper_handler.rb +29 -0
- data/lib/hrr_rb_netconf/server/datastore/session.rb +52 -0
- data/lib/hrr_rb_netconf/server/error.rb +52 -0
- data/lib/hrr_rb_netconf/server/error/access_denied.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/bad_attribute.rb +20 -0
- data/lib/hrr_rb_netconf/server/error/bad_element.rb +20 -0
- data/lib/hrr_rb_netconf/server/error/data_exists.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/data_missing.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/in_use.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/invalid_value.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/lock_denied.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/malformed_message.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/missing_attribute.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/missing_element.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/operation_failed.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/operation_not_supported.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/partial_operation.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/resource_denied.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/rollback_failed.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/rpc_errorable.rb +138 -0
- data/lib/hrr_rb_netconf/server/error/too_big.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/unknown_attribute.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/unknown_element.rb +19 -0
- data/lib/hrr_rb_netconf/server/error/unknown_namespace.rb +19 -0
- data/lib/hrr_rb_netconf/server/errors.rb +28 -0
- data/lib/hrr_rb_netconf/server/filter.rb +48 -0
- data/lib/hrr_rb_netconf/server/filter/subtree.rb +135 -0
- data/lib/hrr_rb_netconf/server/filter/xpath.rb +59 -0
- data/lib/hrr_rb_netconf/server/model.rb +123 -0
- data/lib/hrr_rb_netconf/server/model/node.rb +19 -0
- data/lib/hrr_rb_netconf/server/operation.rb +92 -0
- data/lib/hrr_rb_netconf/server/session.rb +177 -0
- data/lib/hrr_rb_netconf/version.rb +6 -0
- metadata +149 -0
data/Rakefile
ADDED
data/demo/server.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'socket'
|
5
|
+
require 'logger'
|
6
|
+
|
7
|
+
begin
|
8
|
+
require 'hrr_rb_netconf'
|
9
|
+
rescue LoadError
|
10
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
11
|
+
require 'hrr_rb_netconf'
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
logger = Logger.new STDOUT
|
16
|
+
logger.level = Logger::DEBUG
|
17
|
+
HrrRbNetconf::Logger.initialize logger
|
18
|
+
|
19
|
+
datastore = HrrRbNetconf::Server::Datastore.new('dummy'){ |db, session, oper_handler|
|
20
|
+
begin
|
21
|
+
logger.debug { "begin DB session" }
|
22
|
+
oper_handler.start db
|
23
|
+
ensure
|
24
|
+
logger.debug { "close DB in ensure" }
|
25
|
+
end
|
26
|
+
}
|
27
|
+
datastore.oper_proc('get'){ |datastore, input_e|
|
28
|
+
'<a xmlns="dummy"><b/></a>'
|
29
|
+
}
|
30
|
+
datastore.oper_proc('close-session'){ |datastore, input_e|
|
31
|
+
'<ok/>'
|
32
|
+
}
|
33
|
+
datastore.oper_proc('kill-session'){ |datastore, input_e|
|
34
|
+
'<ok/>'
|
35
|
+
}
|
36
|
+
|
37
|
+
netconf_server = HrrRbNetconf::Server.new datastore
|
38
|
+
|
39
|
+
server = TCPServer.new 10830
|
40
|
+
loop do
|
41
|
+
Thread.new(server.accept) do |io|
|
42
|
+
begin
|
43
|
+
netconf_server.start_session io
|
44
|
+
rescue => e
|
45
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
46
|
+
ensure
|
47
|
+
begin
|
48
|
+
io.close
|
49
|
+
rescue => e
|
50
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'socket'
|
5
|
+
require 'logger'
|
6
|
+
require 'rexml/document'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'hrr_rb_ssh'
|
10
|
+
rescue LoadError
|
11
|
+
STDERR.puts "Faild require 'hrr_rb_ssh' gem. Please install it with 'gem install hrr_rb_ssh'."
|
12
|
+
exit(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'hrr_rb_netconf'
|
17
|
+
rescue LoadError
|
18
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
19
|
+
require 'hrr_rb_netconf'
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
logger = Logger.new STDOUT
|
24
|
+
logger.level = Logger::INFO
|
25
|
+
logger.level = Logger::DEBUG
|
26
|
+
HrrRbNetconf::Logger.initialize logger
|
27
|
+
|
28
|
+
|
29
|
+
db = '<root />'
|
30
|
+
|
31
|
+
datastore = HrrRbNetconf::Server::Datastore.new(db)
|
32
|
+
datastore.oper_proc('get'){ |db, input_e|
|
33
|
+
db
|
34
|
+
}
|
35
|
+
datastore.oper_proc('get-config'){ |db, input_e|
|
36
|
+
db
|
37
|
+
}
|
38
|
+
datastore.oper_proc('edit-config'){ |db, input_e|
|
39
|
+
config_e = input_e.elements['config'].elements[1].to_s
|
40
|
+
db = config_e
|
41
|
+
}
|
42
|
+
datastore.oper_proc('close-session'){ |db, input_e|
|
43
|
+
# pass
|
44
|
+
}
|
45
|
+
datastore.oper_proc('lock'){ |db, input_e|
|
46
|
+
# pass
|
47
|
+
}
|
48
|
+
datastore.oper_proc('unlock'){ |db, input_e|
|
49
|
+
# pass
|
50
|
+
}
|
51
|
+
|
52
|
+
netconf_server = HrrRbNetconf::Server.new datastore
|
53
|
+
|
54
|
+
|
55
|
+
auth_password = HrrRbSsh::Authentication::Authenticator.new { |context|
|
56
|
+
true # accept any user and password
|
57
|
+
}
|
58
|
+
conn_subsys = HrrRbSsh::Connection::RequestHandler.new { |context|
|
59
|
+
context.chain_proc { |chain|
|
60
|
+
case context.subsystem_name
|
61
|
+
when 'netconf'
|
62
|
+
begin
|
63
|
+
netconf_server.start_session context.io
|
64
|
+
exitstatus = 0
|
65
|
+
rescue => e
|
66
|
+
logger.error([e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join)
|
67
|
+
exitstatus = 1
|
68
|
+
end
|
69
|
+
else
|
70
|
+
exitstatus = 0
|
71
|
+
end
|
72
|
+
exitstatus
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
options = {}
|
77
|
+
options['authentication_password_authenticator'] = auth_password
|
78
|
+
options['connection_channel_request_subsystem'] = conn_subsys
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
server = TCPServer.new 10830
|
83
|
+
loop do
|
84
|
+
Thread.new(server.accept) do |io|
|
85
|
+
begin
|
86
|
+
ssh_server = HrrRbSsh::Server.new io, options
|
87
|
+
ssh_server.start
|
88
|
+
rescue => e
|
89
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
90
|
+
ensure
|
91
|
+
begin
|
92
|
+
io.close
|
93
|
+
rescue
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'socket'
|
5
|
+
require 'logger'
|
6
|
+
require 'rexml/document'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'hrr_rb_netconf'
|
10
|
+
rescue LoadError
|
11
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
12
|
+
require 'hrr_rb_netconf'
|
13
|
+
end
|
14
|
+
|
15
|
+
class SessionOrientedDatabase
|
16
|
+
class DatabaseSession
|
17
|
+
def initialize db, session_id
|
18
|
+
@db = db
|
19
|
+
@session_id = session_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def lock
|
23
|
+
# Dummy method
|
24
|
+
end
|
25
|
+
|
26
|
+
def unlock
|
27
|
+
# Dummy method
|
28
|
+
end
|
29
|
+
|
30
|
+
def close
|
31
|
+
# Dummy method
|
32
|
+
end
|
33
|
+
|
34
|
+
def get
|
35
|
+
@db.get
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_config
|
39
|
+
@db.get_config
|
40
|
+
end
|
41
|
+
|
42
|
+
def edit input_e
|
43
|
+
@db.edit input_e
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@xml_doc = REXML::Document.new('<original />')
|
49
|
+
@content = ''
|
50
|
+
end
|
51
|
+
|
52
|
+
def new_session session_id
|
53
|
+
DatabaseSession.new self, session_id
|
54
|
+
end
|
55
|
+
|
56
|
+
def get
|
57
|
+
@xml_doc.root.deep_clone
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_config
|
61
|
+
@xml_doc.root.deep_clone
|
62
|
+
end
|
63
|
+
|
64
|
+
def edit input_e
|
65
|
+
@xml_doc = REXML::Document.new
|
66
|
+
@xml_doc.add input_e
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
logger = Logger.new STDOUT
|
72
|
+
logger.level = Logger::INFO
|
73
|
+
logger.level = Logger::DEBUG
|
74
|
+
HrrRbNetconf::Logger.initialize logger
|
75
|
+
|
76
|
+
|
77
|
+
db = SessionOrientedDatabase.new
|
78
|
+
|
79
|
+
datastore = HrrRbNetconf::Server::Datastore.new(db){ |db, session, oper_handler|
|
80
|
+
begin
|
81
|
+
logger.debug { "begin DB session" }
|
82
|
+
db_session = db.new_session session.session_id
|
83
|
+
dummy_arg = 'dummy_arg'
|
84
|
+
oper_handler.start db_session, dummy_arg
|
85
|
+
ensure
|
86
|
+
logger.debug { "close DB in ensure" }
|
87
|
+
db_session.close rescue nil
|
88
|
+
end
|
89
|
+
}
|
90
|
+
datastore.oper_proc('get'){ |db_session, dummy_arg, input_e|
|
91
|
+
db_session.get
|
92
|
+
}
|
93
|
+
datastore.oper_proc('get-config'){ |db_session, dummy_arg, input_e|
|
94
|
+
db_session.get_config
|
95
|
+
}
|
96
|
+
datastore.oper_proc('edit-config'){ |db_session, dummy_arg, input_e|
|
97
|
+
config_e = input_e.elements['config'].elements[1]
|
98
|
+
db_session.edit config_e
|
99
|
+
}
|
100
|
+
datastore.oper_proc('close-session'){ |db_session, dummy_arg, input_e|
|
101
|
+
begin
|
102
|
+
db_session.close
|
103
|
+
rescue => e
|
104
|
+
raise HrrRbNetconf::Server::Error['operation-failed'].new('application', 'error', message: e.message)
|
105
|
+
end
|
106
|
+
}
|
107
|
+
datastore.oper_proc('lock'){ |db_session, dummy_arg, input_e|
|
108
|
+
begin
|
109
|
+
db_session.lock
|
110
|
+
rescue => e
|
111
|
+
raise HrrRbNetconf::Server::Error['resource-denied'].new('application', 'error', message: e.message)
|
112
|
+
end
|
113
|
+
}
|
114
|
+
datastore.oper_proc('unlock'){ |db_session, dummy_arg, input_e|
|
115
|
+
db_session.unlock rescue nil
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
server = TCPServer.new 10830
|
120
|
+
netconf_server = HrrRbNetconf::Server.new datastore
|
121
|
+
loop do
|
122
|
+
Thread.new(server.accept) do |io|
|
123
|
+
begin
|
124
|
+
netconf_server.start_session io
|
125
|
+
rescue => e
|
126
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
127
|
+
ensure
|
128
|
+
begin
|
129
|
+
io.close
|
130
|
+
rescue
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
require 'socket'
|
5
|
+
require 'logger'
|
6
|
+
require 'rexml/document'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'hrr_rb_netconf'
|
10
|
+
rescue LoadError
|
11
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
12
|
+
require 'hrr_rb_netconf'
|
13
|
+
end
|
14
|
+
|
15
|
+
class SessionlessDatabase
|
16
|
+
def initialize
|
17
|
+
@xml_doc = REXML::Document.new('<original />')
|
18
|
+
@content = ''
|
19
|
+
end
|
20
|
+
|
21
|
+
def get
|
22
|
+
@xml_doc.root.deep_clone
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_config
|
26
|
+
@xml_doc.root.deep_clone
|
27
|
+
end
|
28
|
+
|
29
|
+
def edit input_e
|
30
|
+
@xml_doc = REXML::Document.new
|
31
|
+
@xml_doc.add input_e
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
logger = Logger.new STDOUT
|
37
|
+
logger.level = Logger::INFO
|
38
|
+
logger.level = Logger::DEBUG
|
39
|
+
HrrRbNetconf::Logger.initialize logger
|
40
|
+
|
41
|
+
|
42
|
+
db = SessionlessDatabase.new
|
43
|
+
|
44
|
+
datastore = HrrRbNetconf::Server::Datastore.new(db)
|
45
|
+
datastore.oper_proc('get'){ |db, input_e|
|
46
|
+
db.get
|
47
|
+
}
|
48
|
+
datastore.oper_proc('get-config'){ |db, input_e|
|
49
|
+
db.get_config
|
50
|
+
}
|
51
|
+
datastore.oper_proc('edit-config'){ |db, input_e|
|
52
|
+
config_e = input_e.elements['config'].elements[1]
|
53
|
+
db.edit config_e
|
54
|
+
}
|
55
|
+
datastore.oper_proc('close-session'){ |db, input_e|
|
56
|
+
# pass
|
57
|
+
}
|
58
|
+
datastore.oper_proc('lock'){ |db, input_e|
|
59
|
+
# pass
|
60
|
+
}
|
61
|
+
datastore.oper_proc('unlock'){ |db, input_e|
|
62
|
+
# pass
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
server = TCPServer.new 10830
|
67
|
+
netconf_server = HrrRbNetconf::Server.new datastore
|
68
|
+
loop do
|
69
|
+
Thread.new(server.accept) do |io|
|
70
|
+
begin
|
71
|
+
netconf_server.start_session io
|
72
|
+
rescue => e
|
73
|
+
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
74
|
+
ensure
|
75
|
+
begin
|
76
|
+
io.close
|
77
|
+
rescue
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
lib = File.expand_path("../lib", __FILE__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require "hrr_rb_netconf/version"
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = "hrr_rb_netconf"
|
10
|
+
spec.version = HrrRbNetconf::VERSION
|
11
|
+
spec.license = 'Apache-2.0'
|
12
|
+
spec.summary = %q{Pure Ruby NETCONF server implementation}
|
13
|
+
spec.description = %q{Pure Ruby NETCONF server implementation}
|
14
|
+
spec.authors = ["hirura"]
|
15
|
+
spec.email = ["hirura@gmail.com"]
|
16
|
+
spec.homepage = "https://github.com/hirura/hrr_rb_netconf"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{^(test|spec|features)/})
|
20
|
+
end
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.required_ruby_version = '>= 2.0.0'
|
24
|
+
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
spec.add_development_dependency "simplecov", "~> 0.16"
|
28
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbNetconf
|
5
|
+
class Logger
|
6
|
+
@@logger = nil
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def initialize logger
|
10
|
+
@@logger = logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def uninitialize
|
14
|
+
@@logger = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialized?
|
18
|
+
@@logger != nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize name
|
23
|
+
@name = name
|
24
|
+
end
|
25
|
+
|
26
|
+
def fatal
|
27
|
+
if @@logger
|
28
|
+
@@logger.fatal { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def error
|
33
|
+
if @@logger
|
34
|
+
@@logger.error { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def warn
|
39
|
+
if @@logger
|
40
|
+
@@logger.warn { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def info
|
45
|
+
if @@logger
|
46
|
+
@@logger.info { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def debug
|
51
|
+
if @@logger
|
52
|
+
@@logger.debug { "p#{Process.pid}.t#{Thread.current.object_id}: #{@name}: #{yield}" }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|