hrr_rb_netconf 0.1.1 → 0.2.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.
- checksums.yaml +4 -4
- data/demo/server.rb +2 -3
- data/demo/server_over_ssh.rb +4 -6
- data/demo/server_with_session-oriented-database.rb +4 -6
- data/demo/server_with_sessionless-database.rb +2 -4
- data/lib/hrr_rb_netconf/loggable.rb +42 -0
- data/lib/hrr_rb_netconf/server/capabilities.rb +8 -4
- data/lib/hrr_rb_netconf/server/capability/base_1_0.rb +97 -91
- data/lib/hrr_rb_netconf/server/capability/base_1_1.rb +109 -103
- data/lib/hrr_rb_netconf/server/capability/candidate_1_0.rb +19 -17
- data/lib/hrr_rb_netconf/server/capability/confirmed_commit_1_0.rb +4 -2
- data/lib/hrr_rb_netconf/server/capability/confirmed_commit_1_1.rb +10 -8
- data/lib/hrr_rb_netconf/server/capability/notification_1_0.rb +62 -62
- data/lib/hrr_rb_netconf/server/capability/rollback_on_error_1_0.rb +3 -1
- data/lib/hrr_rb_netconf/server/capability/startup_1_0.rb +9 -7
- data/lib/hrr_rb_netconf/server/capability/url_1_0.rb +7 -5
- data/lib/hrr_rb_netconf/server/capability/validate_1_0.rb +10 -8
- data/lib/hrr_rb_netconf/server/capability/validate_1_1.rb +11 -9
- data/lib/hrr_rb_netconf/server/capability/writable_running_1_0.rb +4 -2
- data/lib/hrr_rb_netconf/server/capability.rb +16 -27
- data/lib/hrr_rb_netconf/server/datastore/oper_handler.rb +9 -7
- data/lib/hrr_rb_netconf/server/datastore/session.rb +7 -5
- data/lib/hrr_rb_netconf/server/datastore.rb +7 -5
- data/lib/hrr_rb_netconf/server/error/rpc_errorable.rb +8 -5
- data/lib/hrr_rb_netconf/server/model.rb +9 -5
- data/lib/hrr_rb_netconf/server/notification_event.rb +0 -1
- data/lib/hrr_rb_netconf/server/notification_streams.rb +0 -1
- data/lib/hrr_rb_netconf/server/operation.rb +12 -10
- data/lib/hrr_rb_netconf/server/session.rb +39 -37
- data/lib/hrr_rb_netconf/server.rb +24 -22
- data/lib/hrr_rb_netconf/version.rb +1 -1
- data/lib/hrr_rb_netconf.rb +0 -1
- metadata +3 -3
- data/lib/hrr_rb_netconf/logger.rb +0 -56
@@ -7,17 +7,19 @@ require 'thread'
|
|
7
7
|
require 'monitor'
|
8
8
|
require 'rexml/document'
|
9
9
|
require 'hrr_rb_relaxed_xml'
|
10
|
-
require 'hrr_rb_netconf/
|
10
|
+
require 'hrr_rb_netconf/loggable'
|
11
11
|
require 'hrr_rb_netconf/server/capability'
|
12
12
|
require 'hrr_rb_netconf/server/operation'
|
13
13
|
|
14
14
|
module HrrRbNetconf
|
15
15
|
class Server
|
16
16
|
class Session
|
17
|
+
include Loggable
|
18
|
+
|
17
19
|
attr_reader :session_id
|
18
20
|
|
19
|
-
def initialize server, capabilities, datastore, session_id, io, strict_capabilities
|
20
|
-
|
21
|
+
def initialize server, capabilities, datastore, session_id, io, strict_capabilities, logger: nil
|
22
|
+
self.logger = logger
|
21
23
|
@server = server
|
22
24
|
@local_capabilities = capabilities
|
23
25
|
@remote_capabilities = Array.new
|
@@ -55,12 +57,12 @@ module HrrRbNetconf
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def close
|
58
|
-
|
60
|
+
log_info { "Being closed" }
|
59
61
|
@closed = true
|
60
62
|
@io_r.close_read rescue nil
|
61
63
|
@notification_replay_thread.exit if @notification_replay_thread rescue nil
|
62
64
|
@notification_termination_thread.exit if @notification_termination_thread rescue nil
|
63
|
-
|
65
|
+
log_info { "Closed" }
|
64
66
|
end
|
65
67
|
|
66
68
|
def closed?
|
@@ -73,7 +75,7 @@ module HrrRbNetconf
|
|
73
75
|
end
|
74
76
|
|
75
77
|
def send_hello
|
76
|
-
|
78
|
+
log_info { "Local capabilities: #{@local_capabilities}" }
|
77
79
|
xml_doc = REXML::Document.new
|
78
80
|
hello_e = xml_doc.add_element 'hello'
|
79
81
|
hello_e.add_namespace('urn:ietf:params:xml:ns:netconf:base:1.0')
|
@@ -89,7 +91,7 @@ module HrrRbNetconf
|
|
89
91
|
formatter = REXML::Formatters::Pretty.new(2)
|
90
92
|
formatter.compact = true
|
91
93
|
formatter.write(xml_doc, buf)
|
92
|
-
|
94
|
+
log_debug { "Sending hello message: #{buf.inspect}" }
|
93
95
|
@io_w.write "#{buf}\n]]>]]>"
|
94
96
|
end
|
95
97
|
|
@@ -101,31 +103,31 @@ module HrrRbNetconf
|
|
101
103
|
break
|
102
104
|
end
|
103
105
|
end
|
104
|
-
|
106
|
+
log_debug { "Received hello message: #{buf[0..-7].inspect}" }
|
105
107
|
remote_capabilities_xml_doc = REXML::Document.new(buf[0..-7], {:ignore_whitespace_nodes => :all})
|
106
108
|
remote_capabilities_xml_doc.each_element('/hello/capabilities/capability'){ |c| @remote_capabilities.push c.text }
|
107
|
-
|
109
|
+
log_info { "Remote capabilities: #{@remote_capabilities}" }
|
108
110
|
end
|
109
111
|
|
110
112
|
def negotiate_capabilities
|
111
113
|
@capabilities = @local_capabilities.negotiate @remote_capabilities
|
112
|
-
|
114
|
+
log_info { "Negotiated capabilities: #{@capabilities.list_loadable}" }
|
113
115
|
unless @capabilities.list_loadable.any?{ |c| /^urn:ietf:params:netconf:base:\d+\.\d+$/ =~ c }
|
114
|
-
|
116
|
+
log_error { "No base NETCONF capability negotiated" }
|
115
117
|
raise "No base NETCONF capability negotiated"
|
116
118
|
end
|
117
119
|
end
|
118
120
|
|
119
121
|
def initialize_sender_and_receiver
|
120
122
|
base_capability = @capabilities.list_loadable.select{ |c| /^urn:ietf:params:netconf:base:\d+\.\d+$/ =~ c }.sort.last
|
121
|
-
|
122
|
-
@sender = Capability[base_capability]::Sender.new @io_w
|
123
|
-
@receiver = Capability[base_capability]::Receiver.new @io_r
|
123
|
+
log_info { "Base NETCONF capability: #{base_capability}" }
|
124
|
+
@sender = Capability[base_capability]::Sender.new @io_w, logger: logger
|
125
|
+
@receiver = Capability[base_capability]::Receiver.new @io_r, logger: logger
|
124
126
|
end
|
125
127
|
|
126
128
|
def operation_loop
|
127
129
|
datastore_session = @datastore.new_session self
|
128
|
-
operation = Operation.new self, @capabilities, datastore_session, @strict_capabilities
|
130
|
+
operation = Operation.new self, @capabilities, datastore_session, @strict_capabilities, logger: logger
|
129
131
|
|
130
132
|
begin
|
131
133
|
loop do
|
@@ -138,7 +140,7 @@ module HrrRbNetconf
|
|
138
140
|
rpc_reply_e.add_namespace("urn:ietf:params:xml:ns:netconf:base:1.0")
|
139
141
|
rpc_reply_e.add e.to_rpc_error
|
140
142
|
rescue => e
|
141
|
-
|
143
|
+
log_error { e.message }
|
142
144
|
raise
|
143
145
|
end
|
144
146
|
@monitor.synchronize do
|
@@ -149,7 +151,7 @@ module HrrRbNetconf
|
|
149
151
|
rpc_reply_e.name = "rpc-reply"
|
150
152
|
rpc_reply_e.add e.to_rpc_error
|
151
153
|
rescue => e
|
152
|
-
|
154
|
+
log_error { e.message }
|
153
155
|
raise
|
154
156
|
ensure
|
155
157
|
begin
|
@@ -164,7 +166,7 @@ module HrrRbNetconf
|
|
164
166
|
datastore_session.close rescue nil
|
165
167
|
@io_w.close_write rescue nil
|
166
168
|
end
|
167
|
-
|
169
|
+
log_info { "Exit operation_loop" }
|
168
170
|
end
|
169
171
|
|
170
172
|
def close_other session_id
|
@@ -180,38 +182,38 @@ module HrrRbNetconf
|
|
180
182
|
end
|
181
183
|
|
182
184
|
def subscription_creatable? stream
|
183
|
-
|
185
|
+
log_info { "Check subscription for stream: #{stream}" }
|
184
186
|
if ! @server.has_notification_stream? stream
|
185
|
-
|
187
|
+
log_error { "Server doesn't have notification stream: #{stream}" }
|
186
188
|
false
|
187
189
|
elsif @subscribed_streams.has_key? stream
|
188
|
-
|
190
|
+
log_error { "Session already has subscription for stream: #{stream}" }
|
189
191
|
false
|
190
192
|
else
|
191
|
-
|
193
|
+
log_info { "Subscription creatable for stream: #{stream}" }
|
192
194
|
true
|
193
195
|
end
|
194
196
|
end
|
195
197
|
|
196
198
|
def create_subscription stream, start_time, stop_time
|
197
|
-
|
199
|
+
log_info { "Create subscription for stream: #{stream}" }
|
198
200
|
@subscribed_streams[stream] = true
|
199
201
|
start_notification_termination_thread stream, start_time, stop_time if stop_time
|
200
|
-
|
202
|
+
log_info { "Create subscription done for stream: #{stream}" }
|
201
203
|
end
|
202
204
|
|
203
205
|
def terminate_subscription stream
|
204
|
-
|
206
|
+
log_info { "Terminate subscription for stream: #{stream}" }
|
205
207
|
@subscribed_streams.delete stream
|
206
|
-
|
208
|
+
log_info { "Terminate subscription done for stream: #{stream}" }
|
207
209
|
end
|
208
210
|
|
209
211
|
def notification_replay stream, start_time, stop_time, events
|
210
212
|
if @server.notification_stream_support_replay? stream
|
211
213
|
start_notification_replay_thread stream, start_time, stop_time, events
|
212
214
|
else
|
213
|
-
|
214
|
-
raise Error['operation-failed'].new('protocol', 'error')
|
215
|
+
log_error { "Notification replay is not supported by stream: #{stream}" }
|
216
|
+
raise Error['operation-failed'].new('protocol', 'error', logger: logger)
|
215
217
|
end
|
216
218
|
end
|
217
219
|
|
@@ -221,11 +223,11 @@ module HrrRbNetconf
|
|
221
223
|
|
222
224
|
def start_notification_replay_thread stream, start_time, stop_time, events
|
223
225
|
@notification_replay_thread = Thread.new do
|
224
|
-
|
226
|
+
log_info { "Notification replay start for stream: #{stream}" }
|
225
227
|
begin
|
226
228
|
@monitor.synchronize do
|
227
229
|
unless events.respond_to? :each
|
228
|
-
|
230
|
+
log_error { "Argument `events' doesn't respond to :each method: #{events}" }
|
229
231
|
else
|
230
232
|
begin
|
231
233
|
events.each{ |arg1, arg2|
|
@@ -242,29 +244,29 @@ module HrrRbNetconf
|
|
242
244
|
end
|
243
245
|
}
|
244
246
|
rescue => e
|
245
|
-
|
247
|
+
log_error { "Got an exception during processing replay: #{e.message}" }
|
246
248
|
end
|
247
249
|
end
|
248
250
|
send_replay_complete stream
|
249
251
|
end
|
250
252
|
ensure
|
251
|
-
|
253
|
+
log_info { "Notification replay completed for stream: #{stream}" }
|
252
254
|
end
|
253
255
|
end
|
254
256
|
end
|
255
257
|
|
256
258
|
def start_notification_termination_thread stream, start_time, stop_time
|
257
259
|
@notification_termination_thread = Thread.new do
|
258
|
-
|
260
|
+
log_info { "Notification termination thread start for stream: #{stream}" }
|
259
261
|
begin
|
260
262
|
loop do
|
261
263
|
now = DateTime.now
|
262
264
|
if now.to_time < stop_time.to_time
|
263
265
|
sleep_time = ((stop_time.to_time - now.to_time) / 2.0).ceil
|
264
|
-
|
266
|
+
log_debug { "Notification termination thread for stream: #{stream}: sleep [sec]: #{sleep_time}" }
|
265
267
|
sleep sleep_time
|
266
268
|
else
|
267
|
-
|
269
|
+
log_info { "Notification termination thread terminates subscription for stream: #{stream}" }
|
268
270
|
@monitor.synchronize do
|
269
271
|
terminate_subscription stream
|
270
272
|
send_notification_complete stream
|
@@ -273,7 +275,7 @@ module HrrRbNetconf
|
|
273
275
|
end
|
274
276
|
end
|
275
277
|
ensure
|
276
|
-
|
278
|
+
log_info { "Notification termination completed for stream: #{stream}" }
|
277
279
|
end
|
278
280
|
end
|
279
281
|
end
|
@@ -288,7 +290,7 @@ module HrrRbNetconf
|
|
288
290
|
begin
|
289
291
|
@sender.send_message notif_e
|
290
292
|
rescue IOError => e
|
291
|
-
|
293
|
+
log_warn { "Failed sending notification: #{e.message}" }
|
292
294
|
end
|
293
295
|
end
|
294
296
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
require 'date'
|
5
5
|
require 'thread'
|
6
6
|
require 'hrr_rb_relaxed_xml'
|
7
|
-
require 'hrr_rb_netconf/
|
7
|
+
require 'hrr_rb_netconf/loggable'
|
8
8
|
require 'hrr_rb_netconf/server/error'
|
9
9
|
require 'hrr_rb_netconf/server/errors'
|
10
10
|
require 'hrr_rb_netconf/server/datastore'
|
@@ -15,15 +15,17 @@ require 'hrr_rb_netconf/server/notification_streams'
|
|
15
15
|
|
16
16
|
module HrrRbNetconf
|
17
17
|
class Server
|
18
|
+
include Loggable
|
19
|
+
|
18
20
|
SESSION_ID_UNALLOCATED = "UNALLOCATED"
|
19
21
|
SESSION_ID_MIN = 1
|
20
22
|
SESSION_ID_MAX = 2**32 - 1
|
21
23
|
SESSION_ID_MODULO = SESSION_ID_MAX - SESSION_ID_MIN + 1
|
22
24
|
|
23
|
-
def initialize datastore, capabilities: nil, strict_capabilities: false
|
24
|
-
|
25
|
+
def initialize datastore, capabilities: nil, strict_capabilities: false, logger: nil
|
26
|
+
self.logger = logger
|
25
27
|
@datastore = datastore
|
26
|
-
@capabilities = capabilities || Capabilities.new
|
28
|
+
@capabilities = capabilities || Capabilities.new(logger: logger)
|
27
29
|
@strict_capabilities = strict_capabilities
|
28
30
|
@mutex = Mutex.new
|
29
31
|
@sessions = Hash.new
|
@@ -36,7 +38,7 @@ module HrrRbNetconf
|
|
36
38
|
def allocate_session_id
|
37
39
|
session_id = (SESSION_ID_MODULO).times.lazy.map{ |idx| (@last_session_id + 1 + idx - SESSION_ID_MIN) % SESSION_ID_MODULO + SESSION_ID_MIN }.reject{ |sid| @sessions.has_key? sid }.first
|
38
40
|
unless session_id
|
39
|
-
|
41
|
+
log_error { "Failed allocating Session ID" }
|
40
42
|
raise "Failed allocating Session ID"
|
41
43
|
end
|
42
44
|
@last_session_id = session_id
|
@@ -49,20 +51,20 @@ module HrrRbNetconf
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def start_session io
|
52
|
-
|
54
|
+
log_info { "Start session" }
|
53
55
|
session_id = SESSION_ID_UNALLOCATED
|
54
56
|
begin
|
55
57
|
@mutex.synchronize do
|
56
58
|
session_id = allocate_session_id
|
57
|
-
|
58
|
-
@sessions[session_id] = Session.new self, @capabilities, @datastore, session_id, io, @strict_capabilities
|
59
|
+
log_info { "Session ID: #{session_id}" }
|
60
|
+
@sessions[session_id] = Session.new self, @capabilities, @datastore, session_id, io, @strict_capabilities, logger: logger
|
59
61
|
end
|
60
62
|
@sessions[session_id].start
|
61
63
|
rescue => e
|
62
|
-
|
64
|
+
log_error { "Session terminated: Session ID: #{session_id}" }
|
63
65
|
raise
|
64
66
|
else
|
65
|
-
|
67
|
+
log_info { "Session closed: Session ID: #{session_id}" }
|
66
68
|
ensure
|
67
69
|
@lock_mutex.synchronize do
|
68
70
|
@locks.delete_if{ |tgt, sid| sid == session_id }
|
@@ -74,16 +76,16 @@ module HrrRbNetconf
|
|
74
76
|
end
|
75
77
|
|
76
78
|
def close_session session_id
|
77
|
-
|
79
|
+
log_info { "Close session: Session ID: #{session_id}" }
|
78
80
|
@sessions[session_id].close
|
79
81
|
end
|
80
82
|
|
81
83
|
def lock target, session_id
|
82
|
-
|
84
|
+
log_info { "Lock: Target: #{target}, Session ID: #{session_id}" }
|
83
85
|
@lock_mutex.synchronize do
|
84
86
|
if @locks.has_key? target
|
85
|
-
|
86
|
-
raise Error['lock-denied'].new('protocol', 'error', info: {'session-id' => @locks[target].to_s}, message: 'Lock failed, lock is already held')
|
87
|
+
log_info { "Lock failed, lock is already held by session-id: #{@locks[target]}" }
|
88
|
+
raise Error['lock-denied'].new('protocol', 'error', info: {'session-id' => @locks[target].to_s}, message: 'Lock failed, lock is already held', logger: logger)
|
87
89
|
else
|
88
90
|
@locks[target] = session_id
|
89
91
|
end
|
@@ -91,18 +93,18 @@ module HrrRbNetconf
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def unlock target, session_id
|
94
|
-
|
96
|
+
log_info { "Unlock: Target: #{target}, Session ID: #{session_id}" }
|
95
97
|
@lock_mutex.synchronize do
|
96
98
|
if @locks.has_key? target
|
97
99
|
if @locks[target] == session_id
|
98
100
|
@locks.delete target
|
99
101
|
else
|
100
|
-
|
101
|
-
raise Error['operation-failed'].new('protocol', 'error')
|
102
|
+
log_info { "Unlock failed, lock is held by session-id: #{@locks[target]}" }
|
103
|
+
raise Error['operation-failed'].new('protocol', 'error', logger: logger)
|
102
104
|
end
|
103
105
|
else
|
104
|
-
|
105
|
-
raise Error['operation-failed'].new('protocol', 'error')
|
106
|
+
log_info { "Unlock failed, lock is not held" }
|
107
|
+
raise Error['operation-failed'].new('protocol', 'error', logger: logger)
|
106
108
|
end
|
107
109
|
end
|
108
110
|
end
|
@@ -126,12 +128,12 @@ module HrrRbNetconf
|
|
126
128
|
def send_notification arg1, arg2=nil
|
127
129
|
event_xml = NotificationEvent.new(arg1, arg2).to_xml
|
128
130
|
matched_streams = @notification_streams.matched_streams event_xml
|
129
|
-
|
130
|
-
|
131
|
+
log_info { "Send notification" }
|
132
|
+
log_debug { "Event time: #{event_xml.elements['eventTime'].text}, Event: #{event_xml.elements.to_a}" }
|
131
133
|
@sessions.each{ |session_id, session|
|
132
134
|
session.filter_and_send_notification matched_streams, event_xml
|
133
135
|
}
|
134
|
-
|
136
|
+
log_info { "Send notification done" }
|
135
137
|
end
|
136
138
|
end
|
137
139
|
end
|
data/lib/hrr_rb_netconf.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hrr_rb_netconf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hirura
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hrr_rb_relaxed_xml
|
@@ -87,7 +87,7 @@ files:
|
|
87
87
|
- demo/server_with_sessionless-database.rb
|
88
88
|
- hrr_rb_netconf.gemspec
|
89
89
|
- lib/hrr_rb_netconf.rb
|
90
|
-
- lib/hrr_rb_netconf/
|
90
|
+
- lib/hrr_rb_netconf/loggable.rb
|
91
91
|
- lib/hrr_rb_netconf/server.rb
|
92
92
|
- lib/hrr_rb_netconf/server/capabilities.rb
|
93
93
|
- lib/hrr_rb_netconf/server/capability.rb
|
@@ -1,56 +0,0 @@
|
|
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
|