Commit 5df20601 authored by Luc Didry's avatar Luc Didry

first commit

parents
local/*
erco.conf
*.swp
exa.pid
ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
EXTRACT_FILES=utilities/locales_files.txt
EXTRACT_TO_EN=lib/Erco/I18N/en.po
EXTRACT_TO_FR=lib/Erco/I18N/fr.po
XGETTEXT=carton exec local/bin/xgettext.pl
AGLIO=aglio --full-width
AGLIO_THEME=$(ROOT_DIR)/public/api/jade/erco.jade
API_MD=public/api/api.md
API_HTML=public/api/index.html
locales:
$(XGETTEXT) -f $(EXTRACT_FILES) -o $(EXTRACT_TO_EN) 2>/dev/null
$(XGETTEXT) -f $(EXTRACT_FILES) -o $(EXTRACT_TO_FR) 2>/dev/null
doc:
$(AGLIO) -t $(AGLIO_THEME) -i $(API_MD) -o $(API_HTML)
requires "Mojolicious";
requires "Mojolicious::Plugin::I18N";
requires "Mojolicious::Plugin::DebugDumperHelper";
requires "Mojolicious::Plugin::RemoteAddr";
requires "Locale::Maketext";
requires "Locale::Maketext::Extract";
requires "NetAddr::IP";
requires "Unix::PID";
requires "Term::ReadLine";
requires "Time::HiRes";
# carton snapshot format: version 1.0
DISTRIBUTIONS
CPAN-Meta-2.150005
pathname: D/DA/DAGOLDEN/CPAN-Meta-2.150005.tar.gz
provides:
CPAN::Meta 2.150005
CPAN::Meta::Converter 2.150005
CPAN::Meta::Feature 2.150005
CPAN::Meta::History 2.150005
CPAN::Meta::Merge 2.150005
CPAN::Meta::Prereqs 2.150005
CPAN::Meta::Spec 2.150005
CPAN::Meta::Validator 2.150005
requirements:
CPAN::Meta::Requirements 2.121
CPAN::Meta::YAML 0.008
Carp 0
ExtUtils::MakeMaker 6.17
JSON::PP 2.27200
Parse::CPAN::Meta 1.4414
Scalar::Util 0
perl 5.008
strict 0
version 0.88
warnings 0
List-Cycle-1.02
pathname: P/PE/PETDANCE/List-Cycle-1.02.tar.gz
provides:
List::Cycle 1.02
requirements:
Carp 0
ExtUtils::MakeMaker 0
Test::More 0
Locale-Maketext-Lexicon-1.00
pathname: D/DR/DRTECH/Locale-Maketext-Lexicon-1.00.tar.gz
provides:
Locale::Maketext::Extract 1.00
Locale::Maketext::Extract::Plugin::Base 1.00
Locale::Maketext::Extract::Plugin::FormFu 1.00
Locale::Maketext::Extract::Plugin::FormFu::Extractor 1.00
Locale::Maketext::Extract::Plugin::Generic 1.00
Locale::Maketext::Extract::Plugin::Haml 1.00
Locale::Maketext::Extract::Plugin::Mason 1.00
Locale::Maketext::Extract::Plugin::PPI 1.00
Locale::Maketext::Extract::Plugin::Perl 1.00
Locale::Maketext::Extract::Plugin::TT2 1.00
Locale::Maketext::Extract::Plugin::TT2::Directive 1.00
Locale::Maketext::Extract::Plugin::TT2::Parser 1.00
Locale::Maketext::Extract::Plugin::TextTemplate 1.00
Locale::Maketext::Extract::Plugin::TextTemplate::Parser 1.00
Locale::Maketext::Extract::Plugin::YAML 1.00
Locale::Maketext::Extract::Plugin::YAML::Extractor 1.00
Locale::Maketext::Extract::Run 1.00
Locale::Maketext::Lexicon 1.00
Locale::Maketext::Lexicon::Auto 1.00
Locale::Maketext::Lexicon::Gettext 1.00
Locale::Maketext::Lexicon::Msgcat 1.00
Locale::Maketext::Lexicon::Tie 1.00
requirements:
ExtUtils::MakeMaker 6.30
Locale::Maketext 1.17
Math-Fibonacci-1.5
pathname: V/VI/VIPUL/Math-Fibonacci-1.5.tar.gz
provides:
Math::Fibonacci 1.5
requirements:
ExtUtils::MakeMaker 0
Math-Fibonacci-Phi-0.02
pathname: D/DM/DMUEY/Math-Fibonacci-Phi-0.02.tar.gz
provides:
Math::Fibonacci::Phi 0.02
requirements:
ExtUtils::MakeMaker 0
Math::Fibonacci 0
Module-Build-0.4214
pathname: L/LE/LEONT/Module-Build-0.4214.tar.gz
provides:
Module::Build 0.4214
Module::Build::Base 0.4214
Module::Build::Compat 0.4214
Module::Build::Config 0.4214
Module::Build::Cookbook 0.4214
Module::Build::Dumper 0.4214
Module::Build::Notes 0.4214
Module::Build::PPMMaker 0.4214
Module::Build::Platform::Default 0.4214
Module::Build::Platform::MacOS 0.4214
Module::Build::Platform::Unix 0.4214
Module::Build::Platform::VMS 0.4214
Module::Build::Platform::VOS 0.4214
Module::Build::Platform::Windows 0.4214
Module::Build::Platform::aix 0.4214
Module::Build::Platform::cygwin 0.4214
Module::Build::Platform::darwin 0.4214
Module::Build::Platform::os2 0.4214
Module::Build::PodParser 0.4214
requirements:
CPAN::Meta 2.142060
CPAN::Meta::YAML 0.003
Cwd 0
Data::Dumper 0
ExtUtils::CBuilder 0.27
ExtUtils::Install 0
ExtUtils::Manifest 0
ExtUtils::Mkbootstrap 0
ExtUtils::ParseXS 2.21
File::Basename 0
File::Compare 0
File::Copy 0
File::Find 0
File::Path 0
File::Spec 0.82
File::Temp 0.15
Getopt::Long 0
Module::Metadata 1.000002
Parse::CPAN::Meta 1.4401
Perl::OSType 1
Pod::Man 2.17
Test::Harness 3.16
Test::More 0.49
Text::Abbrev 0
Text::ParseWords 0
perl 5.008000
version 0.87
Mojolicious-6.12
pathname: D/DB/DBOOK/Mojolicious-6.12.tar.gz
provides:
Mojo undef
Mojo::Asset undef
Mojo::Asset::File undef
Mojo::Asset::Memory undef
Mojo::Base undef
Mojo::ByteStream undef
Mojo::Cache undef
Mojo::Collection undef
Mojo::Content undef
Mojo::Content::MultiPart undef
Mojo::Content::Single undef
Mojo::Cookie undef
Mojo::Cookie::Request undef
Mojo::Cookie::Response undef
Mojo::DOM undef
Mojo::DOM::CSS undef
Mojo::DOM::HTML undef
Mojo::Date undef
Mojo::EventEmitter undef
Mojo::Exception undef
Mojo::Headers undef
Mojo::HelloWorld undef
Mojo::Home undef
Mojo::IOLoop undef
Mojo::IOLoop::Client undef
Mojo::IOLoop::Delay undef
Mojo::IOLoop::Server undef
Mojo::IOLoop::Stream undef
Mojo::JSON undef
Mojo::JSON::Pointer undef
Mojo::JSON::_Bool undef
Mojo::Loader undef
Mojo::Log undef
Mojo::Message undef
Mojo::Message::Request undef
Mojo::Message::Response undef
Mojo::Parameters undef
Mojo::Path undef
Mojo::Reactor undef
Mojo::Reactor::EV undef
Mojo::Reactor::Poll undef
Mojo::Server undef
Mojo::Server::CGI undef
Mojo::Server::Daemon undef
Mojo::Server::Hypnotoad undef
Mojo::Server::Morbo undef
Mojo::Server::PSGI undef
Mojo::Server::PSGI::_IO undef
Mojo::Server::Prefork undef
Mojo::Template undef
Mojo::Transaction undef
Mojo::Transaction::HTTP undef
Mojo::Transaction::WebSocket undef
Mojo::URL undef
Mojo::Upload undef
Mojo::UserAgent undef
Mojo::UserAgent::CookieJar undef
Mojo::UserAgent::Proxy undef
Mojo::UserAgent::Server undef
Mojo::UserAgent::Transactor undef
Mojo::Util undef
Mojolicious 6.12
Mojolicious::Command undef
Mojolicious::Command::cgi undef
Mojolicious::Command::cpanify undef
Mojolicious::Command::daemon undef
Mojolicious::Command::eval undef
Mojolicious::Command::generate undef
Mojolicious::Command::generate::app undef
Mojolicious::Command::generate::lite_app undef
Mojolicious::Command::generate::makefile undef
Mojolicious::Command::generate::plugin undef
Mojolicious::Command::get undef
Mojolicious::Command::inflate undef
Mojolicious::Command::prefork undef
Mojolicious::Command::psgi undef
Mojolicious::Command::routes undef
Mojolicious::Command::test undef
Mojolicious::Command::version undef
Mojolicious::Commands undef
Mojolicious::Controller undef
Mojolicious::Lite undef
Mojolicious::Plugin undef
Mojolicious::Plugin::Charset undef
Mojolicious::Plugin::Config undef
Mojolicious::Plugin::Config::Sandbox undef
Mojolicious::Plugin::DefaultHelpers undef
Mojolicious::Plugin::EPLRenderer undef
Mojolicious::Plugin::EPRenderer undef
Mojolicious::Plugin::HeaderCondition undef
Mojolicious::Plugin::JSONConfig undef
Mojolicious::Plugin::Mount undef
Mojolicious::Plugin::PODRenderer undef
Mojolicious::Plugin::TagHelpers undef
Mojolicious::Plugins undef
Mojolicious::Renderer undef
Mojolicious::Routes undef
Mojolicious::Routes::Match undef
Mojolicious::Routes::Pattern undef
Mojolicious::Routes::Route undef
Mojolicious::Sessions undef
Mojolicious::Static undef
Mojolicious::Types undef
Mojolicious::Validator undef
Mojolicious::Validator::Validation undef
Test::Mojo undef
ojo undef
requirements:
ExtUtils::MakeMaker 0
IO::Socket::IP 0.26
Pod::Simple 3.09
Time::Local 1.2
Mojolicious-Plugin-DebugDumperHelper-0.02
pathname: L/LD/LDIDRY/Mojolicious-Plugin-DebugDumperHelper-0.02.tar.gz
provides:
Mojolicious::Plugin::DebugDumperHelper 0.02
requirements:
ExtUtils::MakeMaker 0
Mojolicious 6.11
Mojolicious-Plugin-I18N-1.5
pathname: S/SH/SHARIFULN/Mojolicious-Plugin-I18N-1.5.tar.gz
provides:
Mojolicious::Plugin::I18N 1.5
requirements:
I18N::LangTags 0.35
Module::Build 0.42
Mojolicious 5
Test::More 0
perl 5.010001
Mojolicious-Plugin-RemoteAddr-0.03
pathname: K/KO/KOORCHIK/Mojolicious-Plugin-RemoteAddr-0.03.tar.gz
provides:
Mojolicious::Plugin::RemoteAddr 0.03
requirements:
ExtUtils::MakeMaker 0
Mojolicious 3.90
NetAddr-IP-4.075
pathname: M/MI/MIKER/NetAddr-IP-4.075.tar.gz
provides:
NetAddr::IP 4.075
NetAddr::IP::InetBase 0.08
NetAddr::IP::Lite 1.54
NetAddr::IP::Util 1.51
NetAddr::IP::UtilPP 1.09
NetAddr::IP::UtilPolluted 1.51
NetAddr::IP::Util_IS 1
requirements:
ExtUtils::MakeMaker 0
Test::More 0
Unix-PID-0.23
pathname: D/DM/DMUEY/Unix-PID-0.23.tar.gz
provides:
Unix::PID 0.23
requirements:
ExtUtils::MakeMaker 0
Fcntl 0
List::Cycle 0
Math::Fibonacci::Phi 0
Time::HiRes 0
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
{
####################
# Hypnotoad settings
####################
# see http://mojolicio.us/perldoc/Mojo/Server/Hypnotoad for a full list of settings
hypnotoad => {
# array of IP addresses and ports you want to listen to
listen => ['http://127.0.0.1:8080'],
# user and group you want for Lstu to run with
# be sure that this user/group have rights on the lstu directory
# if you launch lstu from a different user, be sure that this user have the right to su this user/group
# => if current_user is not the user that you sets here and is not root, there's chances that it will fail (see https://github.com/ldidry/lstu/issues/25)
user => 'www-data',
group => 'www-data'
},
# array of random strings used to encrypt cookies
# MANDOTORY, UNCOMMENT AND CHANGE IT!
#secrets => ['fdjsofjoihrei'],
# path to the exabgp configuration file to handle
# MANDATORY, UNCOMMENT AND SET IT!
#exabgp_conf_file => '/etc/exabgp/bgp-conf.txt',
# Exabgp PID file
# MANDATORY, UNCOMMENT AND SET IT!
#exabgp_pid_file => '/var/run/exabgp/exabgp.pid',
# hash of available next-hops with a human-friendly name
# MANDATORY
#next_hops => {
# '198.51.100.42' => 'zoidberg.example.org',
# '203.0.113.42' => 'bender.example.org',
#},
# hash of available communities with a human-friendly name
# MANDATORY
#communities => {
# '1337:1984' => 'Planet express community',
#},
# array of commands you want to allow
# optional, please note that 'reload' will always be allowed
commands => [
#'version',
'reload',
#'restart',
#'shutdown',
#'show neighbors',
#'show routes',
],
# URL sub-directory in which you want Lstu to be accessible
# example: you want to have Eco under https://example.org/eco/
# => set url_sub_dir to '/eco' or to '/eco/', it doesn't matter
# optional, defaut is /
#prefix => '/',
}
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Erco;
use Mojo::Base 'Mojolicious';
use Erco::ExaConf;
use Unix::PID;
$ENV{MOJO_PROXY} = 1;
sub startup {
my $self = shift;
$self->plugin('Config' => {
default => {
secret => ['fdjsofjoihrei'],
commands => ['reload']
}
});
my $commands = $self->config('commands');
push @{$commands}, 'reload' unless (scalar(grep(/^reload$/, @{$commands})));
$self->config->{commands} = $commands;
# Check config needs
my @needs;
for my $key ('secrets', 'exabgp_conf_file', 'exabgp_pid_file', 'next_hops', 'communities') {
push @needs, $key unless (defined($self->config($key)));
}
if (scalar(@needs)) {
$self->app->log->error('The following configuration items are mandatory and not setted: '.join(', ', @needs));
die "\n".'The following configuration items are mandatory and not setted: '.join(', ', @needs);
}
unless (-r $self->config('exabgp_conf_file')) {
$self->app->log->error('The exabgp configuration file ('.$self->config('exabgp_conf_file').') is missing or not readable!');
die "\n".'The exabgp configuration file ('.$self->config('exabgp_conf_file').') is missing or not readable!';
}
# Set secrets
$self->secrets($self->config('secrets'));
# Internationalization plugin
$self->plugin('I18N');
# Remote address plugin
$self->plugin('RemoteAddr');
# Debug plugin
$self->plugin('DebugDumperHelper');
$self->helper(
exaconf => sub {
my $c = shift;
state $conf = Erco::ExaConf->new(file => $c->config('exabgp_conf_file'), app => $c->app);
return $conf;
}
);
$self->helper(
pid => sub {
my $c = shift;
state $pid = Unix::PID->new();
return $pid;
}
);
$self->helper(
is_exa_running => sub {
my $c = shift;
return $c->pid->is_pidfile_running($c->config('exabgp_pid_file'));
}
);
# Default layout
$self->defaults(layout => 'default');
# Router
my $r = $self->routes;
# Normal route to controller
$r->get('/' => sub {
my $c = shift;
$c->render(
layout => 'default',
template => 'index'
);
})->name('index');
$r->get('/42' => sub {
shift->render(
layout => 'default',
template => 'e'
);
})->name('easter');
$r->get('/js/app.js' => sub {
shift->render(
layout => undef,
template => 'js/app',
format => 'js'
);
})->name('appjs');
## API
my $api = $r->under('/api');
$api->get('/' => sub {
shift->redirect_to('/api/index.html');
})->name('api');
# API: subnets
$api->get('/subnet')
->to('API::Subnet#get')
->name('get_subnet');
$api->post('/subnet')
->to('API::Subnet#post')
->name('add_subnet');
$api->put('/subnet')
->to('API::Subnet#put')
->name('mod_subnet');
$api->delete('/subnet')
->to('API::Subnet#delete')
->name('del_subnet');
# API: misc
$api->get('/communities')
->to('API::Communities#get')
->name('get_communities');
$api->get('/next_hops')
->to('API::NextHops#get')
->name('get_next_hops');
# API: exabgp
my $exa = $r->under('/api/exabgp');
$exa->get('/commands')
->to('API::Exabgp#commands')
->name('exabgp_commands');
$exa->get('/command')
->to('API::Exabgp#command')
->name('exabgp_command');
$exa->websocket('/status')
->to('API::Exabgp#status')
->name('exabgp_status');
$exa->get('/status')
->to('API::Exabgp#status')
->name('exabgp_status');
}
1;
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Erco::Controller::API::Communities;
use Mojo::Base 'Mojolicious::Controller';
# Send the list of configured communities, JSON format
sub get {
my $c = shift;
$c->render(
json => $c->config('communities')
);
}
1;
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Erco::Controller::API::Exabgp;
use Mojo::Base 'Mojolicious::Controller';
use Mojo::JSON qw(true false encode_json);
use Mojo::IOLoop;
use Mojo::UserAgent;
# Gives the list of available commands
sub commands {
my $c = shift;
$c->render(
json => $c->config('commands')
);
}
# Exec exabgp commands
sub command {
my $c = shift;
my $a = $c->param('action');
my $msg = {
success => false,
msg => ''
};
# Special case: this one doesn't have to be configured
if ($a eq 'reload') {
my $delay = Mojo::IOLoop->delay;
$delay->on(finish => sub {
my $delay = shift;
my $result = $_[0];
if ($result->{success}) {
my $running = $c->is_exa_running;
# Give time to exabgp to reload, just in case
unless ($running) {
sleep 1;
$running = $c->is_exa_running;
}
if ($running) {
$msg->{success} = true;
$msg->{msg} = $c->l('Exabgp has been successfully reloaded.');
} else {
$msg->{msg} = $c->l('Exabgp has been reloaded but is not running.');
}
} else {
$msg->{msg} = $result->{msg};
}
$c->render(
json => $msg
);
});
$c->exaconf->reload_exabgp($delay->begin(0));
$delay->wait;
} else {
chomp $a;
# Is the command authorized?
if (grep (/^$a$/, @{$c->config('commands')})) {
my @msgs;
$c->render_later;
my $ua = $c->ua;
$ua->inactivity_timeout(300);
$ua->websocket('ws://127.0.0.1:3005/' => sub {
my ($ua, $ws) = @_;
unless ($ws->is_websocket) {
$msg->{msg} = $c->l('WebSocket handshake failed!');
return $c->render(
json => $msg
);
}
$ws->send($a);
$ws->on(
message => sub {
my ($ws, $msg) = @_;
push @msgs, $msg;
}
);
$ws->on(
finish => sub {
$msg->{success} = true;
$msg->{msg} = join("\n", @msgs);
$c->render(
json => $msg
);
}
);
});
} else {
$c->app->log->info(sprintf('IP %s tried to launch the following unauthorized command: %s', $c->remote_addr, $a));
$msg->{msg} = $c->l('You tried to launch an unauthorized command. Contact an administrator.');
}
}
}
# Gives Exabgp status (running or not?)
sub status {
my $c = shift;
# Websocket part
if ($c->tx->is_websocket) {
$c->debug('Client connected');
# Let's start a loop to keep client up to date
my $loop = Mojo::IOLoop->singleton;
$loop->stream($c->tx->connection)->timeout(10);
$loop->recurring(1 => sub {
if (defined($c->tx)) {
$c->app->log->info('PID file ('.$c->config('exabgp_pid_file').') is missing or not readable!') unless (-r $c->config('exabgp_pid_file'));
$c->tx->send(
{
json => {
file_missing => (-r $c->config('exabgp_pid_file')) ? false : true,
running => ($c->is_exa_running) ? true : false
}
}
);
}
});
$c->on(
finish => sub {
$c->debug('Client disconnected');
}
);
} else { # Ajax fallback part (the client is polling)
$c->app->log->info('PID file ('.$c->config('exabgp_pid_file').') is missing or not readable!') unless (-r $c->config('exabgp_pid_file'));
$c->render(
json => {
file_missing => (-r $c->config('exabgp_pid_file')) ? false : true,
running => ($c->is_exa_running) ? true : false
}
);
}
}
1;
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Erco::Controller::API::NextHops;
use Mojo::Base 'Mojolicious::Controller';
# Send the list of configured next hops, JSON format
sub get {
my $c = shift;
$c->render(
json => $c->config('next_hops')
);
}
1;
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Erco::Controller::API::Subnet;
use Mojo::Base 'Mojolicious::Controller';
use Mojo::JSON qw(true false);
use NetAddr::IP;
# Gives a list of entries
sub get {
my $c = shift;
$c->render(
json => $c->exaconf->entries->to_array,
);