1
0
mirror of https://github.com/cmur2/openvpn-status-web.git synced 2025-09-28 21:52:05 +02:00

26 Commits

Author SHA1 Message Date
cn
cdc20e8042 Bump version 2018-11-05 09:12:20 +01:00
cn
998f9e683c spec: use new rspec expect syntax 2018-11-02 10:16:28 +01:00
cn
cf69d6417d gem: upgrade to Rack 2.0, loosen version constraints by dropping old rubies 2018-11-02 10:16:18 +01:00
cn
cb1d029326 travis: update rubies 2018-11-02 10:11:26 +01:00
cn
563fb5743b Bump version 2013-10-08 13:23:22 +02:00
cn
a852aa4b4d React to SIGTERM 2013-10-08 13:23:02 +02:00
cn
d5f8d66422 Bump version 2013-10-07 22:27:18 +02:00
cn
f873d8176e Update README 2013-07-19 09:32:37 +02:00
cn
c14d59e0bf Require better_errors only in development 2013-07-18 23:39:59 +02:00
cn
a78a178150 Bump version 2013-05-03 22:26:53 +02:00
cn
e0c3073d82 Allow dropping privs 2013-05-03 22:26:07 +02:00
cn
c885e875ad Use date formatting in UI 2013-05-03 22:23:56 +02:00
cn
f2794ccea4 Add tests and bug fixed parser 2013-05-03 22:23:45 +02:00
cn
457aec64db Add some parser tests 2013-05-03 21:38:10 +02:00
cn
468e002162 Update README 2013-05-03 21:27:13 +02:00
cn
35b5be15a4 Don't use 1.8.7 2013-05-03 21:17:27 +02:00
cn
c51968618d Show multiple vpns 2013-05-03 21:12:06 +02:00
cn
a1a6b33902 Refactor V2 and V3 parser into one 2013-05-03 20:16:17 +02:00
cn
33013c56f3 Add support for multiple status-versions 2013-05-03 20:09:46 +02:00
cn
ed42fc9f30 Use better_errors 2013-05-03 19:49:09 +02:00
cn
635e562a3d First step towards multiple status files 2013-05-03 18:47:32 +02:00
cn
438931f8a6 Use a status object 2013-05-03 18:30:34 +02:00
cn
cd6e41fcfa Refactoring 2013-05-03 18:20:07 +02:00
cn
87d9ea302f Update README 2013-05-03 16:12:11 +02:00
cn
d6a7b8c0ee Use config file 2013-05-03 16:06:30 +02:00
cn
addc1cf45a Update desc 2013-05-03 15:39:50 +02:00
16 changed files with 493 additions and 162 deletions

View File

@@ -1,9 +1,7 @@
---
sudo: false
language: ruby language: ruby
rvm: rvm:
- 2.0.0 - 2.5
- 1.9.3 - 2.4
- 1.8.7 - 2.3
gemfile:
- Gemfile

View File

@@ -1,17 +1,66 @@
# openvpn-status-web # openvpn-status-web
Small (another word for naive in this case, it's simple and serves my needs) [rack](http://rack.github.com/) app [![Build Status](https://travis-ci.org/cmur2/openvpn-status-web.png)](https://travis-ci.org/cmur2/openvpn-status-web)
providing the information the [OpenVPN](http://openvpn.net/index.php/open-source.html) server collects in it's status file
especially including a list of currently connected clients (common name, remote address, traffic, ...). ## Description
It comes with a Debian 6 compatible init.d file.
Small (another word for naive in this case, it's simple and serves my needs) [Rack](http://rack.github.com/) application providing the information an [OpenVPN](http://openvpn.net/index.php/open-source.html) server collects in it's status file especially including a list of currently connected clients (common name, remote address, traffic, ...).
It lacks: It lacks:
* authentication * caching (parses file on each request, page does auto-refresh every minute as OpenVPN updates the status file these often by default)
* caching (parses file on each request, page does auto-refresh every minute as OpenVPN updates the status file these often)
* management interface support * management interface support
* *possibly more...* * *possibly more...*
## Usage
Install the gem:
gem install openvpn-status-web
Create a configuration file in YAML format somewhere:
```yaml
# listen address and port
host: "0.0.0.0"
port: "8080"
# optional: drop priviliges in case you want to but you should give this user at least read access on the log files
user: "nobody"
group: "nogroup"
# logfile is optional, logs to STDOUT else
logfile: "openvpn-status-web.log"
# hash with each VPNs display name for humans as key and further config as value
vpns:
My Small VPN:
# the status file path and status file format version are required
version: 1
status_file: "/var/log/openvpn-status.log"
My Other VPN:
version: 3
status_file: "/var/log/other-openvpn-status.log"
```
Your OpenVPN configuration should contain something like this:
```
# ...snip...
status /var/log/openvpn-status.log
status-version 1
# ...snip...
```
For more information about OpenVPN status file and version, see their [man page](https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage). openvpn-status-web is able to parse all versions from 1 to 3.
## Advanced topics
### Authentication
If the information exposed is important to you serve it via the VPN or use a webserver as a proxy to handle SSL and/or HTTP authentication.
### Init scripts
The [Debian 6 init.d script](init.d/debian-6-openvpn-status-web) assumes that openvpn-status-web is installed into the system ruby (no RVM support) and the config.yaml is at /opt/openvpn-status-web/config.yaml. Modify to your needs.
## License ## License
openvpn-statsu-web is licensed under the Apache License, Version 2.0. See LICENSE for more information. openvpn-statsu-web is licensed under the Apache License, Version 2.0. See LICENSE for more information.

View File

@@ -0,0 +1,40 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: openvpn-status-web
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Handle openvpn-status-web gem
### END INIT INFO
# using the system ruby's gem binaries directory
DAEMON="/var/lib/gems/1.8/bin/openvpn-status-web"
CONFIG_FILE="/opt/openvpn-status-web/config.yaml"
DAEMON_OPTS="$CONFIG_FILE"
test -x $DAEMON || exit 0
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting openvpn-web-status" "openvpn-web-status"
start-stop-daemon --start --quiet --oknodo --make-pidfile --pidfile "/var/run/openvpn-web-status.pid" --background --exec $DAEMON -- $DAEMON_OPTS
;;
stop)
log_daemon_msg "Stopping openvpn-web-status" "openvpn-web-status"
start-stop-daemon --stop --quiet --oknodo --pidfile "/var/run/openvpn-web-status.pid"
;;
restart|force-reload)
log_daemon_msg "Restarting openvpn-web-status" "openvpn-web-status"
start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile "/var/run/openvpn-web-status.pid"
start-stop-daemon --start --quiet --oknodo --make-pidfile --pidfile "/var/run/openvpn-web-status.pid" --background --exec $DAEMON -- $DAEMON_OPTS
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload}" >&2
exit 1
;;
esac

View File

@@ -1,48 +0,0 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: openvpn-status-web
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Handle openvpn-status-web
### END INIT INFO
# your ruby interpreter
DAEMON="/usr/bin/ruby"
# some unique name identifying your VPN
VPN_NAME="vpn.example.org"
# path to the OpenVPN status log file
STATUS_PATH="/var/log/openvpn-status.log"
# host and port for this daemon to listen on
HOST="127.0.0.1"
PORT="3000"
DAEMON_OPTS="/opt/openvpn-status-web/status.rb $VPN_NAME $STATUS_PATH $HOST $PORT"
test -x $DAEMON || exit 0
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting openvpn-web-status for $VPN_NAME" "openvpn-web-status"
start-stop-daemon --start --quiet --oknodo --make-pidfile --pidfile "/var/run/$VPN_NAME.pid" --background --exec $DAEMON -- $DAEMON_OPTS
;;
stop)
log_daemon_msg "Stopping openvpn-web-status for $VPN_NAME" "openvpn-web-status"
start-stop-daemon --stop --quiet --oknodo --pidfile "/var/run/$VPN_NAME.pid"
;;
restart|force-reload)
log_daemon_msg "Restarting openvpn-web-status for $VPN_NAME" "openvpn-web-status"
start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile "/var/run/$VPN_NAME.pid"
start-stop-daemon --start --quiet --oknodo --make-pidfile --pidfile "/var/run/$VPN_NAME.pid" --background --exec $DAEMON -- $DAEMON_OPTS
;;
*)
echo "Usage: $0 {start|stop|restart|force-reload}" >&2
exit 1
;;
esac

View File

@@ -1,12 +1,19 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
require 'date'
require 'etc' require 'etc'
require 'logger' require 'logger'
require 'ipaddr' require 'ipaddr'
require 'yaml' require 'yaml'
require 'rack' require 'rack'
require 'erb'
require 'metriks' require 'metriks'
require 'better_errors' if ENV['RACK_ENV'] == "development"
require 'openvpn-status-web/status'
require 'openvpn-status-web/parser/v1'
require 'openvpn-status-web/parser/v2'
require 'openvpn-status-web/parser/v3'
require 'openvpn-status-web/int_patch' require 'openvpn-status-web/int_patch'
require 'openvpn-status-web/version' require 'openvpn-status-web/version'
@@ -26,18 +33,25 @@ module OpenVPNStatusWeb
end end
class Daemon class Daemon
def initialize(name, file) def initialize(vpns)
@name = name @vpns = vpns
@file = file
@main_tmpl = read_template(File.join(File.dirname(__FILE__), 'openvpn-status-web/main.html.erb'))
end end
def call(env) def call(env)
main_tmpl = read_template(File.join(File.dirname(__FILE__), 'openvpn-status-web/main.html.erb')) return [405, {"Content-Type" => "text/plain"}, ["Method Not Allowed"]] if env["REQUEST_METHOD"] != "GET"
return [404, {"Content-Type" => "text/plain"}, ["Not Found"]] if env["PATH_INFO"] != "/"
# variables for template # variables for template
name = @name vpns = @vpns
client_list, routing_table, global_stats = read_status_log(@file) stati = {}
@vpns.each do |name,config|
html = main_tmpl.result(binding) stati[name] = parse_status_log(config)
end
# eval
html = @main_tmpl.result(binding)
[200, {"Content-Type" => "text/html"}, [html]] [200, {"Content-Type" => "text/html"}, [html]]
end end
@@ -47,50 +61,71 @@ module OpenVPNStatusWeb
ERB.new(text) ERB.new(text)
end end
def read_status_log(file) def parse_status_log(vpn)
text = File.open(file, 'rb') do |f| f.read end text = File.open(vpn['status_file'], 'rb') do |f| f.read end
current_section = :none case vpn['version']
client_list = [] when 1
routing_table = [] OpenVPNStatusWeb::Parser::V1.new.parse_status_log(text)
global_stats = [] when 2
OpenVPNStatusWeb::Parser::V2.new.parse_status_log(text)
text.lines.each do |line| when 3
(current_section = :cl; next) if line == "OpenVPN CLIENT LIST\n" OpenVPNStatusWeb::Parser::V3.new.parse_status_log(text)
(current_section = :rt; next) if line == "ROUTING TABLE\n" else
(current_section = :gs; next) if line == "GLOBAL STATS\n" raise "No suitable parser for status-version #{vpn['version']}"
(current_section = :end; next) if line == "END\n"
case current_section
when :cl then client_list << line.strip.split(',')
when :rt then routing_table << line.strip.split(',')
when :gs then global_stats << line.strip.split(',')
end
end end
[client_list[2..-1], routing_table[1..-1], global_stats]
end end
def self.run! def self.run!
if ARGV.length != 4 if ARGV.length != 1
puts "Usage: openvpn-status-web vpn-name status-log listen-host listen-port" puts "Usage: openvpn-status-web config_file"
exit 1 exit 1
end end
OpenVPNStatusWeb.logger = Logger.new(STDOUT) config_file = ARGV[0]
if not File.file?(config_file)
puts "Config file not found!"
exit 1
end
puts "openvpn-status-web version #{OpenVPNStatusWeb::VERSION}"
puts "Using config file #{config_file}"
config = YAML::load(File.open(config_file, 'r') { |f| f.read })
if config['logfile']
OpenVPNStatusWeb.logger = Logger.new(config['logfile'])
else
OpenVPNStatusWeb.logger = Logger.new(STDOUT)
end
OpenVPNStatusWeb.logger.progname = "openvpn-status-web" OpenVPNStatusWeb.logger.progname = "openvpn-status-web"
OpenVPNStatusWeb.logger.formatter = LogFormatter.new OpenVPNStatusWeb.logger.formatter = LogFormatter.new
OpenVPNStatusWeb.logger.info "Starting..." OpenVPNStatusWeb.logger.info "Starting..."
# drop privs (first change group than user)
Process::Sys.setgid(Etc.getgrnam(config['group']).gid) if config['group']
Process::Sys.setuid(Etc.getpwnam(config['user']).uid) if config['user']
# configure rack
app = Daemon.new(config['vpns'])
if ENV['RACK_ENV'] == "development"
app = BetterErrors::Middleware.new(app)
BetterErrors.application_root = File.expand_path("..", __FILE__)
end
Signal.trap('INT') do Signal.trap('INT') do
OpenVPNStatusWeb.logger.info "Quitting..." OpenVPNStatusWeb.logger.info "Quitting..."
Rack::Handler::WEBrick.shutdown Rack::Handler::WEBrick.shutdown
end end
Signal.trap('TERM') do
app = Daemon.new(ARGV[0], ARGV[1]) OpenVPNStatusWeb.logger.info "Quitting..."
Rack::Handler::WEBrick.run app, :Host => ARGV[2], :Port => ARGV[3] Rack::Handler::WEBrick.shutdown
end
Rack::Handler::WEBrick.run app, :Host => config['host'], :Port => config['port']
end end
end end
end end

View File

@@ -42,67 +42,70 @@ thead {
</head> </head>
<body> <body>
<h1>OpenVPN Status for <%= name %></h1> <% vpns.each do |name,config| %>
<% status = stati[name] %>
<h1>OpenVPN Status for <%= name %></h1>
<h2>Client List</h2> <h2>Client List</h2>
<div> <div>
<table> <table>
<thead> <thead>
<td class="first">Common Name</td> <td class="first">Common Name</td>
<td class="middle">Real Address</td> <td class="middle">Real Address</td>
<td class="middle">Data Received</td> <td class="middle">Data Received</td>
<td class="middle">Data Sent</td> <td class="middle">Data Sent</td>
<td class="last">Connected Since</td> <td class="last">Connected Since</td>
</thead> </thead>
<tbody> <tbody>
<% client_list.each do |client| %> <% status.client_list.each do |client| %>
<tr> <tr>
<td class="first"><%= client[0] %></td> <td class="first"><%= client[0] %></td>
<td class="middle"><%= client[1] %></td> <td class="middle"><%= client[1] %></td>
<td class="middle"><%= client[2].to_i.as_bytes %></td> <td class="middle"><%= client[2].to_i.as_bytes %></td>
<td class="middle"><%= client[3].to_i.as_bytes %></td> <td class="middle"><%= client[3].to_i.as_bytes %></td>
<td class="last"><%= client[4] %></td> <td class="last"><%= client[4].strftime('%-d.%-m.%Y %H:%M:%S') %></td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>
</table> </table>
</div> </div>
<h2>Routing Table</h2> <h2>Routing Table</h2>
<div> <div>
<table> <table>
<thead> <thead>
<td class="first">Virtual Address</td> <td class="first">Virtual Address</td>
<td class="middle">Common Name</td> <td class="middle">Common Name</td>
<td class="middle">Real Address</td> <td class="middle">Real Address</td>
<td class="last">Last Ref</td> <td class="last">Last Ref</td>
</thead> </thead>
<tbody> <tbody>
<% routing_table.each do |e| %> <% status.routing_table.each do |route| %>
<tr> <tr>
<td class="first"><%= e[0] %></td> <td class="first"><%= route[0] %></td>
<td class="middle"><%= e[1] %></td> <td class="middle"><%= route[1] %></td>
<td class="middle"><%= e[2] %></td> <td class="middle"><%= route[2] %></td>
<td class="last"><%= e[3] %></td> <td class="last"><%= route[3].strftime('%-d.%-m.%Y %H:%M:%S') %></td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>
</table> </table>
</div> </div>
<h2>Global Stats</h2> <h2>Global Stats</h2>
<div> <div>
<table> <table>
<tbody> <tbody>
<% global_stats.each do |e| %> <% status.global_stats.each do |global| %>
<tr> <tr>
<td><%= e[0] %>:</td> <td><%= global[0] %>:</td>
<td><%= e[1] %></td> <td><%= global[1] %></td>
</tr> </tr>
<% end %>
</tbody>
</table>
</div>
<% end %> <% end %>
</tbody>
</table>
</div>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,41 @@
module OpenVPNStatusWeb
module Parser
class ModernStateless
def self.parse_status_log(text, sep)
status = Status.new
status.client_list = []
status.routing_table = []
status.global_stats = []
text.lines.each do |line|
parts = line.strip.split(sep)
status.client_list << parse_client(parts[1..5]) if parts[0] == "CLIENT_LIST"
status.routing_table << parse_route(parts[1..4]) if parts[0] == "ROUTING_TABLE"
status.global_stats << parse_global(parts[1..2]) if parts[0] == "GLOBAL_STATS"
end
status
end
private
def self.parse_client(client)
client[2] = client[2].to_i
client[3] = client[3].to_i
client[4] = DateTime.strptime(client[4], '%a %b %d %k:%M:%S %Y')
client
end
def self.parse_route(route)
route[3] = DateTime.strptime(route[3], '%a %b %d %k:%M:%S %Y')
route
end
def self.parse_global(global)
global[1] = global[1].to_i
global
end
end
end
end

View File

@@ -0,0 +1,54 @@
module OpenVPNStatusWeb
module Parser
class V1
def parse_status_log(text)
current_section = :none
client_list = []
routing_table = []
global_stats = []
text.lines.each do |line|
(current_section = :cl; next) if line == "OpenVPN CLIENT LIST\n"
(current_section = :rt; next) if line == "ROUTING TABLE\n"
(current_section = :gs; next) if line == "GLOBAL STATS\n"
(current_section = :end; next) if line == "END\n"
case current_section
when :cl
client_list << line.strip.split(',')
when :rt
routing_table << line.strip.split(',')
when :gs
global_stats << line.strip.split(',')
end
end
status = Status.new
status.client_list = client_list[2..-1].map { |client| parse_client(client) }
status.routing_table = routing_table[1..-1].map { |route| parse_route(route) }
status.global_stats = global_stats.map { |global| parse_global(global) }
status
end
private
def parse_client(client)
client[2] = client[2].to_i
client[3] = client[3].to_i
client[4] = DateTime.strptime(client[4], '%a %b %d %k:%M:%S %Y')
client
end
def parse_route(route)
route[3] = DateTime.strptime(route[3], '%a %b %d %k:%M:%S %Y')
route
end
def parse_global(global)
global[1] = global[1].to_i
global
end
end
end
end

View File

@@ -0,0 +1,12 @@
require 'openvpn-status-web/parser/modern_stateless'
module OpenVPNStatusWeb
module Parser
class V2
def parse_status_log(text)
OpenVPNStatusWeb::Parser::ModernStateless.parse_status_log(text, ',')
end
end
end
end

View File

@@ -0,0 +1,12 @@
require 'openvpn-status-web/parser/modern_stateless'
module OpenVPNStatusWeb
module Parser
class V3
def parse_status_log(text)
OpenVPNStatusWeb::Parser::ModernStateless.parse_status_log(text, "\t")
end
end
end
end

View File

@@ -0,0 +1,8 @@
module OpenVPNStatusWeb
class Status
attr_accessor :client_list
attr_accessor :routing_table
attr_accessor :global_stats
end
end

View File

@@ -1,4 +1,4 @@
module OpenVPNStatusWeb module OpenVPNStatusWeb
VERSION = "0.0.1" VERSION = "2.0.0"
end end

View File

@@ -1,5 +1,5 @@
$:.push File.expand_path("../lib", __FILE__) $LOAD_PATH.push File.expand_path('lib', __dir__)
require 'openvpn-status-web/version' require 'openvpn-status-web/version'
@@ -7,25 +7,26 @@ Gem::Specification.new do |s|
s.name = 'openvpn-status-web' s.name = 'openvpn-status-web'
s.version = OpenVPNStatusWeb::VERSION s.version = OpenVPNStatusWeb::VERSION
s.summary = 'openvpn-status-web' s.summary = 'openvpn-status-web'
s.description = 'Small Rack application that parses and serves the OpenVPN status file.' s.description = 'Small Rack (Ruby) application serving OpenVPN status file.'
s.author = 'Christian Nicolai' s.author = 'Christian Nicolai'
s.email = 'chrnicolai@gmail.com' s.email = 'chrnicolai@gmail.com'
s.license = 'Apache License Version 2.0' s.homepage = 'https://github.com/cmur2/dyndnsd'
s.homepage = 'https://github.com/cmur2/openvpn-status-web' s.license = 'Apache-2.0'
s.files = `git ls-files`.split($/) s.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
s.test_files = s.files.grep(%r{^(test|spec|features)/}) s.test_files = s.files.grep(%r{^(test|spec|features)/})
s.require_paths = ['lib'] s.require_paths = ['lib']
s.executables = ['openvpn-status-web'] s.executables = ['openvpn-status-web']
s.add_runtime_dependency 'rack' s.required_ruby_version = '>= 2.3'
s.add_runtime_dependency 'json'
s.add_runtime_dependency 'rack', '~> 2.0'
s.add_runtime_dependency 'metriks' s.add_runtime_dependency 'metriks'
s.add_development_dependency 'bundler', '~> 1.3' s.add_development_dependency 'bundler'
s.add_development_dependency 'rake' s.add_development_dependency 'rake'
s.add_development_dependency 'rspec' s.add_development_dependency 'rspec'
s.add_development_dependency 'rack-test' s.add_development_dependency 'rack-test'
s.add_development_dependency 'better_errors'
s.add_development_dependency 'binding_of_caller'
end end

View File

@@ -0,0 +1,55 @@
require 'spec_helper'
describe OpenVPNStatusWeb::Parser::ModernStateless do
{
2 => status_v2,
3 => status_v3
}.each do |version, status|
context "for status-version #{version}" do
context 'for client list' do
it 'parses common names' do
expect(status.client_list.map { |client| client[0] }).to eq(["foo", "bar"])
end
it 'parses real addresses' do
expect(status.client_list.map { |client| client[1] }).to eq(["1.2.3.4:1234", "1.2.3.5:1235"])
end
it 'parses received bytes' do
expect(status.client_list.map { |client| client[2] }).to eq([11811160064, 512])
end
it 'parses sent bytes' do
expect(status.client_list.map { |client| client[3] }).to eq([4194304, 2048])
end
it 'parses connected since date' do
expect(status.client_list.map { |client| client[4] }).to eq([DateTime.new(2012,1,1,23,42,0), DateTime.new(2012,1,1,23,42,0)])
end
end
context 'for routing table' do
it 'parses virtual addresses' do
expect(status.routing_table.map { |route| route[0] }).to eq(["192.168.0.0/24", "192.168.66.2", "192.168.66.3", "2001:db8:0:0::1000"])
end
it 'parses common names' do
expect(status.routing_table.map { |route| route[1] }).to eq(["foo", "bar", "foo", "bar"])
end
it 'parses real addresses' do
expect(status.routing_table.map { |route| route[2] }).to eq(["1.2.3.4:1234", "1.2.3.5:1235", "1.2.3.4:1234", "1.2.3.5:1235"])
end
it 'parses last ref date' do
expect(status.routing_table.map { |route| route[3] }).to eq([DateTime.new(2012,1,1,23,42,0), DateTime.new(2012,1,1,23,42,0), DateTime.new(2012,1,1,23,42,0), DateTime.new(2012,1,1,23,42,0)])
end
end
it 'parses global stats' do
expect(status.global_stats.size).to eq(1)
expect(status.global_stats.first).to eq(["Max bcast/mcast queue length", 42])
end
end
end
end

50
spec/parser/v1_spec.rb Normal file
View File

@@ -0,0 +1,50 @@
require 'spec_helper'
describe OpenVPNStatusWeb::Parser::V1 do
def status; status_v1; end
context 'for client list' do
it 'parses common names' do
expect(status.client_list.map { |client| client[0] }).to eq(["foo", "bar"])
end
it 'parses real addresses' do
expect(status.client_list.map { |client| client[1] }).to eq(["1.2.3.4:1234", "1.2.3.5:1235"])
end
it 'parses received bytes' do
expect(status.client_list.map { |client| client[2] }).to eq([11811160064, 512])
end
it 'parses sent bytes' do
expect(status.client_list.map { |client| client[3] }).to eq([4194304, 2048])
end
it 'parses connected since date' do
expect(status.client_list.map { |client| client[4] }).to eq([DateTime.new(2012,1,1,23,42,0), DateTime.new(2012,1,1,23,42,0)])
end
end
context 'for routing table' do
it 'parses virtual addresses' do
expect(status.routing_table.map { |route| route[0] }).to eq(["192.168.0.0/24", "192.168.66.2", "192.168.66.3", "2001:db8:0:0::1000"])
end
it 'parses common names' do
expect(status.routing_table.map { |route| route[1] }).to eq(["foo", "bar", "foo", "bar"])
end
it 'parses real addresses' do
expect(status.routing_table.map { |route| route[2] }).to eq(["1.2.3.4:1234", "1.2.3.5:1235", "1.2.3.4:1234", "1.2.3.5:1235"])
end
it 'parses last ref date' do
expect(status.routing_table.map { |route| route[3] }).to eq([DateTime.new(2012,1,1,23,42,0), DateTime.new(2012,1,1,23,42,0), DateTime.new(2012,1,1,23,42,0), DateTime.new(2012,1,1,23,42,0)])
end
end
it 'parses global stats' do
expect(status.global_stats.size).to eq(1)
expect(status.global_stats.first).to eq(["Max bcast/mcast queue length", 42])
end
end

21
spec/spec_helper.rb Normal file
View File

@@ -0,0 +1,21 @@
require 'rubygems'
require 'bundler/setup'
require 'rack/test'
require 'openvpn-status-web'
def status_v1
text = File.open('examples/status.v1', 'rb') do |f| f.read end
OpenVPNStatusWeb::Parser::V1.new.parse_status_log text
end
def status_v2
text = File.open('examples/status.v2', 'rb') do |f| f.read end
OpenVPNStatusWeb::Parser::V2.new.parse_status_log text
end
def status_v3
text = File.open('examples/status.v3', 'rb') do |f| f.read end
OpenVPNStatusWeb::Parser::V3.new.parse_status_log text
end