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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc382a39772eb64eb2b49d6b2d2361f9f699b015f8905c48cff4ac04b06cb41a
|
4
|
+
data.tar.gz: 45196289a679e2a4ba86c08f721f01a538d6eeafa4741512bc1f97a3278b8173
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 80d4339932ed79b121315f6cdcd1ee7b0c88cdc19f4eca8d682d9667fa4c0f4d163c282e6c73d63eb3cb895f8e1a9b2d189e79f4b398b0f7e3267ffe5e48c491
|
7
|
+
data.tar.gz: 8b9a3ae249db4bd51b93b84804aee99ad7fd64e827ff5146fc6d6ae04258c9173dd32a004b985a0de899ac0909837aef9a4a3b183d3764a92aceef3676e79b9c
|
data/demo/server.rb
CHANGED
@@ -14,9 +14,8 @@ end
|
|
14
14
|
|
15
15
|
logger = Logger.new STDOUT
|
16
16
|
logger.level = Logger::DEBUG
|
17
|
-
HrrRbNetconf::Logger.initialize logger
|
18
17
|
|
19
|
-
datastore = HrrRbNetconf::Server::Datastore.new('dummy'){ |db, session, oper_handler|
|
18
|
+
datastore = HrrRbNetconf::Server::Datastore.new('dummy', logger: logger){ |db, session, oper_handler|
|
20
19
|
begin
|
21
20
|
logger.debug { "begin DB session" }
|
22
21
|
oper_handler.start db
|
@@ -34,7 +33,7 @@ datastore.oper_proc('kill-session'){ |datastore, input_e|
|
|
34
33
|
'<ok/>'
|
35
34
|
}
|
36
35
|
|
37
|
-
netconf_server = HrrRbNetconf::Server.new datastore
|
36
|
+
netconf_server = HrrRbNetconf::Server.new datastore, logger: logger
|
38
37
|
|
39
38
|
server = TCPServer.new 10830
|
40
39
|
loop do
|
data/demo/server_over_ssh.rb
CHANGED
@@ -21,14 +21,12 @@ end
|
|
21
21
|
|
22
22
|
|
23
23
|
logger = Logger.new STDOUT
|
24
|
-
logger.level = Logger::INFO
|
25
24
|
logger.level = Logger::DEBUG
|
26
|
-
HrrRbNetconf::Logger.initialize logger
|
27
25
|
|
28
26
|
|
29
27
|
db = '<root />'
|
30
28
|
|
31
|
-
datastore = HrrRbNetconf::Server::Datastore.new(db)
|
29
|
+
datastore = HrrRbNetconf::Server::Datastore.new(db, logger: logger)
|
32
30
|
datastore.oper_proc('get'){ |db, input_e|
|
33
31
|
db
|
34
32
|
}
|
@@ -49,7 +47,7 @@ datastore.oper_proc('unlock'){ |db, input_e|
|
|
49
47
|
# pass
|
50
48
|
}
|
51
49
|
|
52
|
-
netconf_server = HrrRbNetconf::Server.new datastore
|
50
|
+
netconf_server = HrrRbNetconf::Server.new datastore, logger: logger
|
53
51
|
|
54
52
|
|
55
53
|
auth_password = HrrRbSsh::Authentication::Authenticator.new { |context|
|
@@ -83,8 +81,8 @@ server = TCPServer.new 10830
|
|
83
81
|
loop do
|
84
82
|
Thread.new(server.accept) do |io|
|
85
83
|
begin
|
86
|
-
ssh_server = HrrRbSsh::Server.new
|
87
|
-
ssh_server.start
|
84
|
+
ssh_server = HrrRbSsh::Server.new options
|
85
|
+
ssh_server.start io
|
88
86
|
rescue => e
|
89
87
|
logger.error { [e.backtrace[0], ": ", e.message, " (", e.class.to_s, ")\n\t", e.backtrace[1..-1].join("\n\t")].join }
|
90
88
|
ensure
|
@@ -69,14 +69,12 @@ end
|
|
69
69
|
|
70
70
|
|
71
71
|
logger = Logger.new STDOUT
|
72
|
-
logger.level = Logger::INFO
|
73
72
|
logger.level = Logger::DEBUG
|
74
|
-
HrrRbNetconf::Logger.initialize logger
|
75
73
|
|
76
74
|
|
77
75
|
db = SessionOrientedDatabase.new
|
78
76
|
|
79
|
-
datastore = HrrRbNetconf::Server::Datastore.new(db){ |db, session, oper_handler|
|
77
|
+
datastore = HrrRbNetconf::Server::Datastore.new(db, logger: logger){ |db, session, oper_handler|
|
80
78
|
begin
|
81
79
|
logger.debug { "begin DB session" }
|
82
80
|
db_session = db.new_session session.session_id
|
@@ -101,14 +99,14 @@ datastore.oper_proc('close-session'){ |db_session, dummy_arg, input_e|
|
|
101
99
|
begin
|
102
100
|
db_session.close
|
103
101
|
rescue => e
|
104
|
-
raise HrrRbNetconf::Server::Error['operation-failed'].new('application', 'error', message: e.message)
|
102
|
+
raise HrrRbNetconf::Server::Error['operation-failed'].new('application', 'error', message: e.message, logger: logger)
|
105
103
|
end
|
106
104
|
}
|
107
105
|
datastore.oper_proc('lock'){ |db_session, dummy_arg, input_e|
|
108
106
|
begin
|
109
107
|
db_session.lock
|
110
108
|
rescue => e
|
111
|
-
raise HrrRbNetconf::Server::Error['resource-denied'].new('application', 'error', message: e.message)
|
109
|
+
raise HrrRbNetconf::Server::Error['resource-denied'].new('application', 'error', message: e.message, logger: logger)
|
112
110
|
end
|
113
111
|
}
|
114
112
|
datastore.oper_proc('unlock'){ |db_session, dummy_arg, input_e|
|
@@ -117,7 +115,7 @@ datastore.oper_proc('unlock'){ |db_session, dummy_arg, input_e|
|
|
117
115
|
|
118
116
|
|
119
117
|
server = TCPServer.new 10830
|
120
|
-
netconf_server = HrrRbNetconf::Server.new datastore
|
118
|
+
netconf_server = HrrRbNetconf::Server.new datastore, logger: logger
|
121
119
|
loop do
|
122
120
|
Thread.new(server.accept) do |io|
|
123
121
|
begin
|
@@ -34,14 +34,12 @@ end
|
|
34
34
|
|
35
35
|
|
36
36
|
logger = Logger.new STDOUT
|
37
|
-
logger.level = Logger::INFO
|
38
37
|
logger.level = Logger::DEBUG
|
39
|
-
HrrRbNetconf::Logger.initialize logger
|
40
38
|
|
41
39
|
|
42
40
|
db = SessionlessDatabase.new
|
43
41
|
|
44
|
-
datastore = HrrRbNetconf::Server::Datastore.new(db)
|
42
|
+
datastore = HrrRbNetconf::Server::Datastore.new(db, logger: logger)
|
45
43
|
datastore.oper_proc('get'){ |db, input_e|
|
46
44
|
db.get
|
47
45
|
}
|
@@ -64,7 +62,7 @@ datastore.oper_proc('unlock'){ |db, input_e|
|
|
64
62
|
|
65
63
|
|
66
64
|
server = TCPServer.new 10830
|
67
|
-
netconf_server = HrrRbNetconf::Server.new datastore
|
65
|
+
netconf_server = HrrRbNetconf::Server.new datastore, logger: logger
|
68
66
|
loop do
|
69
67
|
Thread.new(server.accept) do |io|
|
70
68
|
begin
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# vim: et ts=2 sw=2
|
3
|
+
|
4
|
+
module HrrRbNetconf
|
5
|
+
module Loggable
|
6
|
+
attr_accessor :logger, :log_key
|
7
|
+
|
8
|
+
def log_fatal
|
9
|
+
if logger
|
10
|
+
logger.fatal(log_key){ yield }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def log_error
|
15
|
+
if logger
|
16
|
+
logger.error(log_key){ yield }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def log_warn
|
21
|
+
if logger
|
22
|
+
logger.warn(log_key){ yield }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def log_info
|
27
|
+
if logger
|
28
|
+
logger.info(log_key){ yield }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def log_debug
|
33
|
+
if logger
|
34
|
+
logger.debug(log_key){ yield }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def log_key
|
39
|
+
@log_key ||= self.class.to_s + "[%x]" % object_id
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -2,15 +2,19 @@
|
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
4
|
require 'tsort'
|
5
|
+
require 'hrr_rb_netconf/loggable'
|
5
6
|
require 'hrr_rb_netconf/server/capability'
|
6
7
|
|
7
8
|
module HrrRbNetconf
|
8
9
|
class Server
|
9
10
|
class Capabilities
|
10
|
-
|
11
|
+
include Loggable
|
12
|
+
|
13
|
+
def initialize features=nil, capabilities_h=nil, logger: nil
|
14
|
+
self.logger = logger
|
11
15
|
@features = features
|
12
16
|
unless capabilities_h
|
13
|
-
@caps = Capability.list.inject({}){ |a, b| a.merge({b => Capability[b].new}) }
|
17
|
+
@caps = Capability.list.inject({}){ |a, b| a.merge({b => Capability[b].new(logger: logger)}) }
|
14
18
|
else
|
15
19
|
@caps = capabilities_h
|
16
20
|
end
|
@@ -26,11 +30,11 @@ module HrrRbNetconf
|
|
26
30
|
a.merge({c.uri => c})
|
27
31
|
}
|
28
32
|
features = if @features.nil? then nil else @features.dup end
|
29
|
-
Capabilities.new features, capabilities_h
|
33
|
+
Capabilities.new features, capabilities_h, logger: logger
|
30
34
|
end
|
31
35
|
|
32
36
|
def register_capability name, &blk
|
33
|
-
cap = Capability.new
|
37
|
+
cap = Capability.new name, logger: logger
|
34
38
|
blk.call cap
|
35
39
|
@caps[name] = cap
|
36
40
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
# vim: et ts=2 sw=2
|
3
3
|
|
4
4
|
require 'rexml/document'
|
5
|
-
require 'hrr_rb_netconf/
|
5
|
+
require 'hrr_rb_netconf/loggable'
|
6
6
|
|
7
7
|
module HrrRbNetconf
|
8
8
|
class Server
|
@@ -12,90 +12,94 @@ module HrrRbNetconf
|
|
12
12
|
DEPENDENCIES = []
|
13
13
|
IF_FEATURES = []
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
}
|
37
|
-
|
38
|
-
oper_proc('lock'){ |session, datastore, input_e|
|
39
|
-
target = input_e.elements['target'].elements[1].name
|
40
|
-
session.lock target
|
41
|
-
begin
|
42
|
-
datastore.run 'lock', input_e
|
15
|
+
def define_capability
|
16
|
+
oper_proc('get'){ |session, datastore, input_e|
|
17
|
+
datastore.run 'get', input_e
|
18
|
+
}
|
19
|
+
|
20
|
+
oper_proc('get-config'){ |session, datastore, input_e|
|
21
|
+
datastore.run 'get-config', input_e
|
22
|
+
}
|
23
|
+
|
24
|
+
oper_proc('edit-config'){ |session, datastore, input_e|
|
25
|
+
datastore.run 'edit-config', input_e
|
26
|
+
'<ok />'
|
27
|
+
}
|
28
|
+
|
29
|
+
oper_proc('copy-config'){ |session, datastore, input_e|
|
30
|
+
datastore.run 'copy-config', input_e
|
31
|
+
'<ok />'
|
32
|
+
}
|
33
|
+
|
34
|
+
oper_proc('delete-config'){ |session, datastore, input_e|
|
35
|
+
datastore.run 'delete-config', input_e
|
43
36
|
'<ok />'
|
44
|
-
|
37
|
+
}
|
38
|
+
|
39
|
+
oper_proc('lock'){ |session, datastore, input_e|
|
40
|
+
target = input_e.elements['target'].elements[1].name
|
41
|
+
session.lock target
|
42
|
+
begin
|
43
|
+
datastore.run 'lock', input_e
|
44
|
+
'<ok />'
|
45
|
+
rescue
|
46
|
+
session.unlock target
|
47
|
+
raise
|
48
|
+
end
|
49
|
+
}
|
50
|
+
|
51
|
+
oper_proc('unlock'){ |session, datastore, input_e|
|
52
|
+
datastore.run 'unlock', input_e
|
53
|
+
target = input_e.elements['target'].elements[1].name
|
45
54
|
session.unlock target
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
'
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
model 'lock', ['target', 'config-target'], 'choice', 'mandatory' => true
|
89
|
-
model 'lock', ['target', 'config-target', 'running'], 'leaf', 'type' => 'empty'
|
90
|
-
model 'unlock', ['target'], 'container'
|
91
|
-
model 'unlock', ['target', 'config-target'], 'choice', 'mandatory' => true
|
92
|
-
model 'unlock', ['target', 'config-target', 'running'], 'leaf', 'type' => 'empty'
|
93
|
-
model 'close-session', []
|
94
|
-
model 'kill-session', ['session-id'], 'leaf', 'type' => 'integer', 'range' => [1, 2**32-1]
|
55
|
+
'<ok />'
|
56
|
+
}
|
57
|
+
|
58
|
+
oper_proc('close-session'){ |session, datastore, input_e|
|
59
|
+
datastore.run 'close-session', input_e
|
60
|
+
session.close
|
61
|
+
'<ok />'
|
62
|
+
}
|
63
|
+
|
64
|
+
oper_proc('kill-session'){ |session, datastore, input_e|
|
65
|
+
session.close_other Integer(input_e.elements['session-id'].text)
|
66
|
+
'<ok />'
|
67
|
+
}
|
68
|
+
|
69
|
+
model 'get', ['filter'], 'leaf', 'type' => 'anyxml'
|
70
|
+
model 'get-config', ['source'], 'container'
|
71
|
+
model 'get-config', ['source', 'config-source'], 'choice', 'mandatory' => true
|
72
|
+
model 'get-config', ['source', 'config-source', 'running'], 'leaf', 'type' => 'empty'
|
73
|
+
model 'get-config', ['filter'], 'leaf', 'type' => 'anyxml'
|
74
|
+
model 'edit-config', ['target'], 'container'
|
75
|
+
model 'edit-config', ['target', 'config-target'], 'choice', 'mandatory' => true
|
76
|
+
model 'edit-config', ['default-operation'], 'leaf', 'type' => 'enumeration', 'enum' => ['merge', 'replace', 'none'], 'default' => 'merge'
|
77
|
+
model 'edit-config', ['error-option'], 'leaf', 'type' => 'enumeration', 'enum' => ['stop-on-error', 'continue-on-error', 'rollback-on-error'], 'default' => 'stop-on-error'
|
78
|
+
model 'edit-config', ['edit-content'], 'choice', 'mandatory' => true
|
79
|
+
model 'edit-config', ['edit-content', 'config'], 'leaf', 'type' => 'anyxml'
|
80
|
+
model 'copy-config', ['target'], 'container'
|
81
|
+
model 'copy-config', ['target', 'config-target'], 'choice', 'mandatory' => true
|
82
|
+
model 'copy-config', ['source'], 'container'
|
83
|
+
model 'copy-config', ['source', 'config-source'], 'choice', 'mandatory' => true
|
84
|
+
model 'copy-config', ['source', 'config-source', 'running'], 'leaf', 'type' => 'empty'
|
85
|
+
model 'copy-config', ['source', 'config-source', 'config'], 'leaf', 'type' => 'anyxml'
|
86
|
+
model 'delete-config', ['target'], 'container'
|
87
|
+
model 'delete-config', ['target', 'config-target'], 'choice', 'mandatory' => true
|
88
|
+
model 'lock', ['target'], 'container'
|
89
|
+
model 'lock', ['target', 'config-target'], 'choice', 'mandatory' => true
|
90
|
+
model 'lock', ['target', 'config-target', 'running'], 'leaf', 'type' => 'empty'
|
91
|
+
model 'unlock', ['target'], 'container'
|
92
|
+
model 'unlock', ['target', 'config-target'], 'choice', 'mandatory' => true
|
93
|
+
model 'unlock', ['target', 'config-target', 'running'], 'leaf', 'type' => 'empty'
|
94
|
+
model 'close-session', []
|
95
|
+
model 'kill-session', ['session-id'], 'leaf', 'type' => 'integer', 'range' => [1, 2**32-1]
|
96
|
+
end
|
95
97
|
|
96
98
|
class Sender
|
97
|
-
|
98
|
-
|
99
|
+
include Loggable
|
100
|
+
|
101
|
+
def initialize io_w, logger: nil
|
102
|
+
self.logger = logger
|
99
103
|
@io_w = io_w
|
100
104
|
@formatter = REXML::Formatters::Pretty.new(2)
|
101
105
|
@formatter.compact = true
|
@@ -108,7 +112,7 @@ module HrrRbNetconf
|
|
108
112
|
begin
|
109
113
|
@formatter.write(REXML::Document.new(msg, {:ignore_whitespace_nodes => :all}).root, buf)
|
110
114
|
rescue => e
|
111
|
-
|
115
|
+
log_error { "Invalid sending message: #{msg.inspect}: #{e.message}" }
|
112
116
|
raise "Invalid sending message: #{msg.inspect}: #{e.message}"
|
113
117
|
end
|
114
118
|
when REXML::Document
|
@@ -116,22 +120,24 @@ module HrrRbNetconf
|
|
116
120
|
when REXML::Element
|
117
121
|
@formatter.write(msg, buf)
|
118
122
|
else
|
119
|
-
|
123
|
+
log_error { "Unexpected sending message: #{msg.inspect}" }
|
120
124
|
raise ArgumentError, "Unexpected sending message: #{msg.inspect}"
|
121
125
|
end
|
122
|
-
|
126
|
+
log_debug { "Sending message: #{buf.inspect}" }
|
123
127
|
begin
|
124
128
|
@io_w.write "#{buf}\n]]>]]>"
|
125
129
|
rescue => e
|
126
|
-
|
130
|
+
log_info { "Sender IO closed: #{e.class}: #{e.message}" }
|
127
131
|
raise IOError, "Sender IO closed: #{e.class}: #{e.message}"
|
128
132
|
end
|
129
133
|
end
|
130
134
|
end
|
131
135
|
|
132
136
|
class Receiver
|
133
|
-
|
134
|
-
|
137
|
+
include Loggable
|
138
|
+
|
139
|
+
def initialize io_r, logger: nil
|
140
|
+
self.logger = logger
|
135
141
|
@io_r = io_r
|
136
142
|
end
|
137
143
|
|
@@ -141,11 +147,11 @@ module HrrRbNetconf
|
|
141
147
|
begin
|
142
148
|
tmp = @io_r.read(1)
|
143
149
|
rescue => e
|
144
|
-
|
150
|
+
log_info { "Receiver IO closed: #{e.class}: #{e.message}" }
|
145
151
|
return nil
|
146
152
|
end
|
147
153
|
if tmp.nil?
|
148
|
-
|
154
|
+
log_info { "Receiver IO closed" }
|
149
155
|
return nil
|
150
156
|
end
|
151
157
|
buf += tmp
|
@@ -153,14 +159,14 @@ module HrrRbNetconf
|
|
153
159
|
break
|
154
160
|
end
|
155
161
|
end
|
156
|
-
|
162
|
+
log_debug { "Received message: #{buf[0..-7].inspect}" }
|
157
163
|
begin
|
158
164
|
received_msg = REXML::Document.new(buf[0..-7], {:ignore_whitespace_nodes => :all}).root
|
159
165
|
validate_received_msg received_msg
|
160
166
|
received_msg
|
161
167
|
rescue => e
|
162
168
|
info = "Invalid received message: #{e.message.split("\n").first}: #{buf[0..-7].inspect}"
|
163
|
-
|
169
|
+
log_info { info }
|
164
170
|
raise info
|
165
171
|
end
|
166
172
|
end
|