add Plugin POD and knock back version to beta release

This commit is contained in:
Oliver Gorwits
2013-02-09 21:56:32 +00:00
parent 6756e3ff6e
commit 76c32e1669
8 changed files with 741 additions and 52 deletions

431
DEVELOPING.txt Normal file
View File

@@ -0,0 +1,431 @@
DEVELOPER NOTES
This document aims to help developers understand the intent and design
of the code within Netdisco. Patches and feedback are always welcome :-)
Introduction
This release of Netdisco is built as a Dancer application, and uses many
modern technologies and techniques. Hopefully this will make the code
easier to manage and maintain in the long term.
Although Dancer is a web application framework, it provides very useful
tools for command line applications as well, namely configuration file
management and database connection management. We make use of these
features in the daemon and deployment scripts.
Overall the application tries to be as self-contained as possible
without also needing an excessive number of CPAN modules to be
installed. However, Modern Perl techniques have made dependency
management almost a non-issue, and Netdisco can be installed by and run
completely within an unprivileged user's account, apart from the
PostgreSQL database setup.
Finally the other core component of Netdisco is now a DBIx::Class layer
for database access. This means there is no SQL anywhere in the code,
but more important, we can re-use the same complex queries in different
parts of Netdisco.
The rest of this document discusses each "interesting" area of the
Netdisco codebase, hopefully in enough detail that you can get hacking
yourself :-)
Versioning
This is Netdisco major version 2. The minor version has six digits,
which are split into two components of three digits each. It's unlikely
that the major version number (2) will increment. Each "feature" release
to CPAN will increment the first three digits of the minor version. Each
"bug fix" release will increment the second three digits of the minor
version.
Stable releases will have an even "feature" number. Beta releases will
have an odd "feature" number and also a suffix with an underscore, to
prevent CPAN indexing the distribution. Some examples:
2.002002 - "feature" release 2, "bug fix" release 2
2.002003 - another bug was found and fixed, hence "bug fix" release 3
2.003000_001 - first beta for the next "feature" release
2.003000_002 - second beta
2.004001 - the next "feature" release
Global Configuration
Dancer uses YAML as its standard configuration file format, which is
flexible enough for our needs, yet still simple to edit for the user. We
no longer need a parser as in the old version of Netdisco.
At the top of scripts you'll usually see something like:
use App::Netdisco;
use Dancer ':script';
First, this uses "App::Netdisco", which is almost nothing more than a
placeholder module (contains no actual application code). What it does
is set several environment variables in order to locate the
configuration files.
Then, when we call ""use Dancer"" these environment variables are used
to load two YAML files: "config.yml" and "<environment>.yml" where
"<environment>" is typically either "production" or "development".
The concept of "environments" allows us to have some shared "master"
config between all instances of the application ("config.yml"), and then
settings for specific circumstances. Typically this might be logging
levels, for example. The default file which "App::Netdisco" loads is
"development.yml" but you can override it by setting the
""DANCER_ENVIRONMENT"" environment variable.
Dancer loads the config using YAML, merging data from the two files.
Config is made available via Dancer's "setting('foo')" subroutine, which
is exported. So now the "foo" setting in either config file is easily
accessed.
Another line commonly seen in scripts is this:
use Dancer::Plugin::DBIC 'schema';
This plugin saves a lot of effort by taking some database connection
parameters from the configuration file, and instantiating DBIx::Class
database connections with them. The connections are managed
transparently so all we need to do to access the Netdisco database, with
no additional setup, is:
schema('netdisco')->resultset(...)->search({...});
DBIx::Class Layer
DBIx::Class, or DBIC for short, is an Object-Relational Mapper. This
means it abstracts away the SQL of database calls, presenting a Perl
object for each table, set of results from a query, table row, etc. The
advantage is that it can generate really smart SQL queries, and these
queries can be re-used throughout the application.
The DBIC layer for Netdisco is based at App::Netdisco::DB. This is the
global schema class and below that, under App::Netdisco::DB::Result is a
class for each table in the database. These contain metadata on the
columns but also several handy "helper" queries which can be called.
There are also "ResultSet" classes which provide additional "pre-canned"
queries.
Netdisco's DBIx::Class layer has excellent documentation which you are
encouraged to read, particularly if you find it difficult to sleep.
Results and ResultSets
In DBIC a "Result" is a table and a "ResultSet" is a set of rows
retrieved from the table as a result of a query (which might be all the
rows, of course). This is why we have two types of DBIC class. Items in
the "Result" generally relate to the single table directly, and simply.
In the "ResultSet" class are more complex search modifiers which might
synthesize new "columns" of data (e.g. formatting a timestamp) or
subroutines which accept parameters to customize the query.
However, regardless of the actual class name, you access them in the
same way. For example the "device" table has an
App::Netdisco::DB::Result::Device class and also an
App::Netdisco::DB::ResultSet::Device class. DBIC merges the two:
schema('netdisco')->resultset('Device')->get_models;
Virtual Tables (VIEWs)
Where we want to simplify our application code even further we can
either install a VIEW in PostgreSQL, or use DBIx::Class to synthesize
the view on-the-fly. Put simply, it uses the VIEW definition as the
basis of an SQL query, yet in the application we treat it as a real
table like any other.
Some good examples are a fake table of only the active Nodes (as opposed
to all nodes), or the more complex list of all ports which are connected
together ("DeviceLink").
All these tables live under the App::Netdisco::DB::Result::Virtual
namespace, and so you access them like so (for the "ActiveNode"
example):
schema('netdisco')->resultset('Virtual::ActiveNode')->count;
Versioning and Deployment
To manage the Netdisco schema in PostgreSQL we use DBIx::Class's
deployment feature. This attaches a version to the schema and provides
all the code to check the current version and do whatever is necessary
to upgrade. The schema version is stored in a new table called
"dbix_class_schema_versions", although you should never touch it.
The "netdisco-db-deploy" script included in the distribution performs
the following services:
* Installs the dbix_class_schema_versions table
* Upgrades the schema to the current distribtion's version
This works both on an empty, new database, and a legacy database from
the existing Netdisco release, in a non-destructive way. For further
information see DBIx::Class::Schema::Versioned and the
"netdisco-db-deploy" script.
The files used for the upgrades are shipped with this distribution and
stored in the ".../App/Netdisco/DB/schema_versions" directory. They are
generated using the "nd-dbic-versions" script which also ships with the
distribution.
Foreign Key Constraints
We have not yet deployed any FK constraints into the Netdisco schema.
This is partly because the current poller inserts and deletes entries
from the database in an order which would violate such constraints, but
also because some of the archiving features of Netdisco might not be
compatible anyway.
Regardless, a lack of FK constraints doesn't upset DBIx::Class. The
constraints can easily be deployed in a future release of Netdisco.
Web Application
The Netdisco web app is a "classic" Dancer app, using most of the
bundled features which make development really easy. Dancer is based on
Ruby's Sinatra framework. Its style is for many "helper" subroutines to
be exported into the application namespace, to do things such as access
request parameters, navigate around the "handler" subroutines, manage
response headers, and so on.
Pretty much anything you want to do in a web application has been
wrapped up by Dancer into a neat helper routine that does the heavy
lifting. This includes configuration and database connection management,
as was discussed above. Also, templates can be executed and Netdisco
uses the venerable Template::Toolkit engine for this.
Like most web frameworks Dancer has a concept of "handlers" which are
subroutines to which a specific web request is routed. For example if
the user asks for ""/device"" with some parameters, the request ends up
at the App::Netdisco::Web::Device package's ""get '/device'"" handler.
All this is done automatically by Dancer according to some simple rules.
There are also "wrapper" subroutines which we use to do tasks such as
setting up data lookup tables, and handling authentication.
Dancer also supports AJAX very well, and it is used to retrieve most of
the data in the Netdisco web application in a dynamic way, to respond to
search queries and avoid lengthy page reloads. You will see the handlers
for AJAX look similar to those for GET requests but do not use
Template::Toolkit templates.
Compared to the current Netdisco, the handler routines are very small.
This is because (a) they don't include any HTML - this is delegated to a
template, and (b) they don't include an SQL - this is delegated to
DBIx::Class. Small routines are more manageable, and easier to maintain.
You'll also notice use of modules such as Net::MAC and NetAddr::IP::Lite
to simplify and make more robust the handling of data.
Running the Web App
Dancer apps conform to the "PSGI" standard interface for web
applications, which makes for easy deployment under many stacks such as
Apache, FCGI, etc. See Dancer::Deployment for more detail.
At a minimum Netdisco can run from within its own user area as an
unprivileged user, and ships with a simple web server engine (see the
user docs for instructions). The "netdisco-web" script uses
Daemon::Control to daemonize this simple web server so you can
fire-and-forget the Netdisco web app without much trouble at all. This
script in turn calls "netdisco-web-fg" which is the real Dancer
application, that runs in the foreground if called on its own.
All web app code lives below App::Netdisco::Web, but there are also some
helper routines in App::Netdisco::Util::Web (for example sorting device
port names).
Authentication
Dancer includes (of course) good session management using cookies and a
memory database. You should change this to a disk database if using a
proper forking web server installation so that sessions are available to
all instances.
Session and authentication code lives in App::Netdisco::Web::AuthN. It
is fully backwards compatible with the existing Netdisco user
management, making use of the database users and their MD5 passwords.
There is also support for unauthenticated access to the web app (for
instance if you have some kind of external authentication, or simply
trust everyone).
Templates
In the "share/views" folder of this distribution you'll find all the
Template::Toolkit template files, with ".tt" extensions. Dancer first
loads "share/views/layouts/main.tt" which is the main page wrapper, that
has the HTML header and so on. It then loads other templates for
sections of the page body. This is a typical Template::Toolkit "wrapper"
configuration, as noted by the "[% content %]" call within "main.tt"
that loads the template you actually specified in your Dancer handler.
All templates (and Javascript and Stylesheets) are shipped in the
App::Netdisco distribution and located automatically by the application
(using the environment variables which App::Netdisco set up). The user
doesn't have to copy or install any files.
There's a template for the homepage called "index.tt", then separate
templates for searching, displaying device details, and showing
inventory. These are, pretty much, all that Netdisco ever does.
Each of these pages is designed in a deliberately similar way, with
re-used features. They each can have a "sidebar" with a search form (or
additional search parameters). They also can have a tabbed interface for
sub-topics.
Here's where it gets interesting. Up till now the page content has been
your typical synchronous page load (a single page comprised of many
templates) in response to a GET request. However the content of the tabs
is not within this. Each tab has its content dynamically retrieved via
an AJAX request back to the web application. Javscript triggers this
automatically on page load.
This feature allows the user to search and search again, each time
refreshing the data they see in the tab but without reloading the
complete page with all its static furniture. AJAX can, of course, return
any MIME type, not only JSON but also HTML content as in this case. The
templates for the tabs are organised below "share/views/ajax/..." in the
distribution.
Stylesheets
The main style for Netdisco uses Twitter Bootstrap, which is a modern
library of CSS and javascript used on many websites. It does a lot of
heavy lifting, providing simple CSS classes for all of the standard web
page furniture (forms, tables, etc). Check out the documetation at the
Twitter Bootstrap web site for more information.
These stylesheets are of course customised with our own "netdisco.css".
We try to name all CSS classes with a prefix ""nd_"" so as to be
distinct from Twitter Bootstrap and any other active styles.
All stylesheets are located in the "share/public/css" folder of the
distribution and, like the templates, are automatically located and
served by the Netdisco application. You can also choose to serve this
content statically via Apache/etc for high traffic sites.
Although Twitter Bootstrap ships with its own set of icons, we use an
alternative library called Fontawesome. This plugs in easily to
Bootstrap and provides a wider range of scaleable vectored icons which
are easy to use.
Javascript
Of course many parts of the Netdisco site use Javascript, beginning with
retrieving the page tab content itself. The standard library in use is
jQuery, and the latest version is shipped with this distribution.
Many parts of the Netdisco site have small Javscript routines. The code
for these, using jQuery as mentioned, lives in two places. The main
"netdisco.js" file is loaded once in the page HTML header, and lives in
"share/public/javascripts/netdisco.js". There's also a
"netdisco_portcontrol.js" which is included only if the current user has
Port Control rights.
Netdisco also has Javascript routines specific to the device search or
device details pages, and these files are located in
"share/views/js/..." because they're loaded within the page body by the
templates. These files contain a function "inner_view_processing" which
is called each time AJAX delivers new content into a tab in the page
(think of it like a callback, perhaps).
Also in the "share/public/javascripts/..." folder are the other public
libraries loaded by the Netdisco application:
The Toastr library is used for "Growl"-like notifications which appear
in the corner of the web browser and then fade away. These notify the
user of successful background job submission, and jos results.
The d3 library is a graphics toolkit used to display the NetMap feature.
This works differently from the old Netdisco in that everything is
generated on-the-fly using SQL queries ("DeviceLinks" resultset) and
this d3 library for rendering.
Finally Twitter Bootstrap also ships with a toolkit of helpful
Javascript driven features such as the tooltips and collapsers.
Job Daemon
The old Netdisco has a job control daemon which processes "port control"
actions and also manual requests for device polling. The new Netdisco
also has a daemon, although it is a true separate process and set of
libraries from the web application. However, it still makes use of the
Dancer configuration and database connection management features
mentioned above.
The job daemon is backwards compatible with the old Netdisco database
job requests table, although it doesn't yet log results in the same way.
Most important, it cannot yet poll any devices for discovery or
macsuck/arpnip, although that's next on the list!
All code for the job daemon lives under the App::Netdisco::Daemon
namespace and like the rest of Netdisco is broken down into manageable
chunks.
Running the Job Daemon
Like the web application, the job daemon is fully self contained and
runs via two simple scripts shipped with the distribution - one for
foreground and one for background execution (see the user docs for
instructions).
The "netdisco-daemon" script uses Daemon::Control to daemonize so you
can fire-and-forget the Netdisco job daemon without much trouble at all.
This script in turn calls "netdisco-daemon-fg" which is the real
application, that runs in the foreground if called on its own.
Daemon Engineering
The job daemon is based on the MCE library, which handles the forking
and management of child processes doing the actual work. This actually
runs in the foreground unless wrapped with Daemon::Control, as mentioned
above. MCE handles three flavours of "worker" for different tasks.
One goal that we had designing the daemon was that sites should be able
to run many instances on different servers, with different processing
capacities. This is both to take advantage of more processor capability,
but also to deal with security zones where you might only be able to
manage a subset of devices from certain locations. Netdisco has always
coped well with this via its "discover_*" and similar configuration, and
the separate poller process.
So, the single Manager "worker" in the daemon is responsible for
contacting the central Netdisco database and booking out jobs which it's
able to service according to the local configuration settings. Jobs are
"locked" in the central queue and then copied to a local job queue
within the daemon.
Along with the Manager we start zero or more of two other types of
worker. Some jobs such as port control are "interactive" and the user
typically wants quick feedback on the results. Others such as polling
are background tasks which can take more time and are less schedule
sensitive. So as not to starve the "interactive" jobs of workers we have
two types of worker.
The Interactive worker picks jobs from the local job queue relating to
device and port reconfiguration only. It submits results directly back
to the central Netdisco database.
The Poller worker (is not yet written!) and similarly picks job from the
local queue, this time relating to device discovery and polling.
There is support in the daemon for the workers to pick more than one job
at a time from the local queue, in case we decide this is worth doing.
However the Manager won't ever book out more jobs from the central
Netdisco job queue than it has workers available (so as not to hog jobs
for itself against other daemons on other servers). The user is free to
configure the number of Interactive and Poller workers in their
"config.yml" file (zero or more of each).
SNMP::Info
The daemon obviously needs to use SNMP::Info for device control. All the
code for this has been factored out into the App::Netdisco::Util
namespace.
The App::Netdisco::Util::Connect package provides for the creation of
SNMP::Info objects along with connection tests. So far, SNMPv3 is not
supported. To enable trace logging of the SNMP::Info object simply set
the "INFO_TRACE" environment variable to a true value. The Connect
library also provides routines to map interface and PoE IDs.
Configuration for SNMP::Info comes from the YAML files, of course. This
means that our "mibhome" and "mibdirs" settings are now in YAML format.
In particular, the "mibdirs" list is a real list within the
configuration.
Other libraries will be added to this namespace in due course, as we add
more functionality to the Job Daemon.
DBIx::Class Layer
The local job queue for each Job Daemon is actually an SQLite database
running in memory. This makes the queue management code a little more
elegant. The schema for this is of course DBIx::Class using Dancer
connection management, and lives in App::Netdisco::Daemon::DB.
There is currently only one table, the port control job queue, in
App::Netdisco::Daemon::DB::Result::Admin. It's likely this name will
change in the future.

View File

@@ -1,4 +1,4 @@
2.006000 - 2.005000_001 - 2013-02-09
[NEW FEATURES] [NEW FEATURES]

View File

@@ -6,7 +6,6 @@ bin/netdisco-deploy
bin/netdisco-web bin/netdisco-web
bin/netdisco-web-fg bin/netdisco-web-fg
Changes Changes
DEVELOPING.pod
inc/Module/Install.pm inc/Module/Install.pm
inc/Module/Install/Base.pm inc/Module/Install/Base.pm
inc/Module/Install/Can.pm inc/Module/Install/Can.pm
@@ -71,6 +70,7 @@ lib/App/Netdisco/DB/schema_versions/App-Netdisco-DB-2-PostgreSQL.sql
lib/App/Netdisco/DB/schema_versions/App-Netdisco-DB-3-4-PostgreSQL.sql lib/App/Netdisco/DB/schema_versions/App-Netdisco-DB-3-4-PostgreSQL.sql
lib/App/Netdisco/DB/schema_versions/App-Netdisco-DB-3-PostgreSQL.sql lib/App/Netdisco/DB/schema_versions/App-Netdisco-DB-3-PostgreSQL.sql
lib/App/Netdisco/DB/schema_versions/App-Netdisco-DB-4-PostgreSQL.sql lib/App/Netdisco/DB/schema_versions/App-Netdisco-DB-4-PostgreSQL.sql
lib/App/Netdisco/Developing.pod
lib/App/Netdisco/Util/Connect.pm lib/App/Netdisco/Util/Connect.pm
lib/App/Netdisco/Util/DeviceProperties.pm lib/App/Netdisco/Util/DeviceProperties.pm
lib/App/Netdisco/Util/Permissions.pm lib/App/Netdisco/Util/Permissions.pm

View File

@@ -51,4 +51,4 @@ resources:
homepage: http://netdisco.org/ homepage: http://netdisco.org/
license: http://opensource.org/licenses/bsd-license.php license: http://opensource.org/licenses/bsd-license.php
repository: git://netdisco.git.sourceforge.net/gitroot/netdisco/netdisco-ng repository: git://netdisco.git.sourceforge.net/gitroot/netdisco/netdisco-ng
version: 2.006000 version: 2.005000_001

View File

@@ -7,7 +7,7 @@ use 5.010_000;
use File::ShareDir 'dist_dir'; use File::ShareDir 'dist_dir';
use Path::Class; use Path::Class;
our $VERSION = '2.006000'; our $VERSION = '2.005000_001';
BEGIN { BEGIN {
if (not length ($ENV{DANCER_APPDIR} || '') if (not length ($ENV{DANCER_APPDIR} || '')
@@ -145,12 +145,23 @@ Run the following command to start the job control daemon (port control, etc):
You should (of course) avoid running this Netdisco daemon and the legacy You should (of course) avoid running this Netdisco daemon and the legacy
daemon at the same time. daemon at the same time.
=head1 Upgrading
Simply install this module again, then upgrade the database schema:
~/bin/localenv cpanm --quiet --notest App::Netdisco
DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-deploy
=head1 Tips and Tricks =head1 Tips and Tricks
=head2 Searching
The main black navigation bar has a search box which is smart enough to work The main black navigation bar has a search box which is smart enough to work
out what you're looking for in most cases. For example device names, node IP out what you're looking for in most cases. For example device names, node IP
or MAC addreses, VLAN numbers, and so on. or MAC addreses, VLAN numbers, and so on.
=head2 SQL and HTTP Trace
For SQL debugging try the following commands: For SQL debugging try the following commands:
DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \ DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \
@@ -159,9 +170,13 @@ For SQL debugging try the following commands:
DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \ DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \
DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-daemon-fg DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-daemon-fg
=head2 Deployment
Other ways to run and host the web application can be found in the Other ways to run and host the web application can be found in the
L<Dancer::Deployment> page. See also the L<plackup> documentation. L<Dancer::Deployment> page. See also the L<plackup> documentation.
=head2 User Rights
With the default configuration user authentication is disabled and the default With the default configuration user authentication is disabled and the default
"guest" user has no special privilege. To grant port and device control rights "guest" user has no special privilege. To grant port and device control rights
to this user, create a row in the C<users> table of the Netdisco database with to this user, create a row in the C<users> table of the Netdisco database with
@@ -169,32 +184,33 @@ a username of C<guest> and the C<port_control> flag set to true:
netdisco=> insert into users (username, port_control) values ('guest', true); netdisco=> insert into users (username, port_control) values ('guest', true);
=head1 Upgrading =head2 Database API
Simply install this module again, then upgrade the database schema: Bundled with this distribution is a L<DBIx::Class> layer for the Netdisco
database. This abstracts away all the SQL into an elegant, re-usable OO
interface. See the L<App::Netdisco::Developing> documentation for further
information.
~/bin/localenv cpanm --quiet --notest App::Netdisco =head2 Plugins
DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-deploy
=head1 Future Work App::Netdisco includes a Plugin subsystem for building the web user interface.
Items in the navigation bar and the tabs on pages are loaded as Plugins, and
you have control over their appearance and ordering. See
L<App::Netdisco::Web::Plugin> for further information.
Bundled with this app is a L<DBIx::Class> layer for the Netdisco database. =head2 Developing
This could be a starting point for an "official" DBIC layer. Helper functions
and canned searches have been added to support the web interface.
The intention is to support "plugins" for additonal features, most notably Lots of information about the architecture of this application is contained
columns in the Device Port listing, but also new menu items and tabs. The within the L<App::Netdisco::Developing> documentation.
design of this is sketched out but not implemented. The goal is to avoid
patching core code to add localizations or less widely used features.
=head1 Caveats =head1 Caveats
Some sections are not yet implemented, e.g. the I<Device Module> tab. Some sections are not yet implemented, e.g. the I<Device Module> tab.
Menu items on the main black navigation bar go nowhere, except Home. Some menu items on the main black navigation bar go nowhere.
None of the Reports yet exist (e.g. searching for wireless devices, or duplex None of the Reports yet exist (e.g. searching for wireless devices, or duplex
mismatches). These might be implemented as a plugin bundle. mismatches). These will be implemented as a plugin bundle.
The Wireless, IP Phone and NetBIOS Node properies are not yet shown. The Wireless, IP Phone and NetBIOS Node properies are not yet shown.

View File

@@ -248,10 +248,10 @@ This is a typical Template::Toolkit "wrapper" configuration, as noted by the
C<[% content %]> call within C<main.tt> that loads the template you actually C<[% content %]> call within C<main.tt> that loads the template you actually
specified in your Dancer handler. specified in your Dancer handler.
All templates (and Javascript and Stylesheets) are shipped in the Dancer All templates (and Javascript and Stylesheets) are shipped in the
distribution and located automatically by the application (using the L<App::Netdisco> distribution and located automatically by the application
environment variables which L<App::Netdisco> set up). The user doesn't have to (using the environment variables which App::Netdisco set up). The user doesn't
copy or install any files. have to copy or install any files.
There's a template for the homepage called C<index.tt>, then separate There's a template for the homepage called C<index.tt>, then separate
templates for searching, displaying device details, and showing inventory. templates for searching, displaying device details, and showing inventory.
@@ -275,11 +275,11 @@ organised below C<share/views/ajax/...> in the distribution.
=head2 Stylesheets =head2 Stylesheets
The main style for Netdisco uses Twitter Bootstrap, which is a stylish modern The main style for Netdisco uses Twitter Bootstrap, which is a modern library
library of styles and javascript used on many websites. It does a lot of heavy of CSS and javascript used on many websites. It does a lot of heavy lifting,
lifting, providing simple CSS classes for all of the standard web page providing simple CSS classes for all of the standard web page furniture
furniture (forms, tables, etc). Check out the documetation at the Twitter (forms, tables, etc). Check out the documetation at the Twitter Bootstrap web
Bootstrap web site for more information. site for more information.
These stylesheets are of course customised with our own C<netdisco.css>. We These stylesheets are of course customised with our own C<netdisco.css>. We
try to name all CSS classes with a prefix "C<nd_>" so as to be distinct from try to name all CSS classes with a prefix "C<nd_>" so as to be distinct from

View File

@@ -57,3 +57,237 @@ register 'register_device_tab' => sub {
register_plugin; register_plugin;
true; true;
=head1 NAME
App::Netdisco::Web::Plugin - Plugin subsystem for App::Netdisco Web UI components
=head1 Introduction
L<App::Netdisco>'s plugin subsystem allows developers to write and test web
user interface (UI) components without needing to patch the main Netdisco
application. It also allows the end-user more control over the UI components
displayed in their browser.
So far, the following UI compoents are implemented as plugins:
=over 4
=item *
Navigation Bar items (e.g. Inventory link)
=item *
Tabs for Search and Device pages
=back
In the future there will be other components supported, such as Reports.
This document explains first how to configure which plugins are loaded (useful
for the end-user) and then also how to write and install your own plugins.
=head1 Application Configuration
In the main C<config.yml> file for App::Netdisco (located in C<share/...>)
you'll find the C<web_plugins> configuration directive. This lists, in YAML
format, a set of Perl module names (or partial names) which are the plugins to
be loaded. For example:
web_plugins:
- Inventory
- Search::Device
- Search::Node
- Search::Port
- Device::Details
- Device::Ports
When the name is specified as above, App::Netdisco automatically prepends
"C<App::Netdisco::Web::Plugin::>" to the name. This makes, for example,
L<App::Netdisco::Web::Plugin::Inventory>. This is the module which is loaded
to add a user interface component.
Such plugin modules can either ship with the App::Netdisco distribution
itself, or be installed separately. Perl uses the standard C<@INC> path
searching mechanism to load the plugin modules.
If an entry in the C<web_plugins> list starts with a "C<+>" (plus) sign then
App::Netdisco attemps to load the module as-is, without prepending anything to
the name. This allows you to have App::Netdiso web UI plugins in other
namespaces:
web_plugins:
- Inventory
- Search::Device
- Search::Node
- Device::Details
- Device::Ports
- +My::Other::Netdisco::Web::Component
The order of the entries in C<web_plugins> is significant. Surprisingly
enough, the modules are loaded in order. Therefore Navigation Bar items appear
in the order listed, and Tabs appear on the Search and Device pages in the
order listed.
The consequence of this is that if you want to change the order (or add or
remove entries) then simply edit the C<web_plugins> setting. In fact, we
recommend adding this setting to your C<< <environment>.yml >> file and
leaving the C<config.yml> file alone. Your Environment's version will take
prescedence.
Finally, if you want to add components without completely overriding the
C<web_plugins> setting, use the C<extra_web_plugins> setting instead in your
Environment configuration. Any Navigation Bar items or Page Tabs are added
after those in C<web_plugins>.
=head1 Developing Plugins
A plugin is simply a Perl module which is loaded. Therefore it can do anything
you like, but most usefully for the App::Netdisco web application, the module
will install a L<Dancer> route handler subroutine, and link this to a web user
interface (UI) component.
Explaining how to write Dancer route handlers is beyond the scope of this
document, but by examining the source to the plugins in App::Netdisco you'll
probably get enough of an idea to begin on your own.
App::Netdisco plugins should load the L<App::Netdisco::Web::Plugin> module.
This exports a set of helper subroutines to register the new UI components.
Here's the boilerplate code for our example plugin module:
package App::Netdisco::Web::Plugin::MyNewFeature
use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use App::Netdisco::Web::Plugin;
# plugin registration code goes here, ** see below **
# your Dancer route handler, for example:
get '/mynewfeature' => sub {
# ...lorem ipsum...
};
true;
=head2 Navigation Bar items
These components appear in the black navigation bar at the top of each page,
as individual items (i.e. not in a menu). The canonical example of this is the
Inventory link.
To register an item for display in the navigation bar, use the following code:
register_navbar_item({
id => 'newfeature',
path => '/mynewfeature',
label => 'My New Feature',
});
This causes an item to appear in the Navigation Bar with a visible text of "My
New Feature" which when clicked sends the user to the C</mynewfeature> page.
Note that this won't work for any target link - the path must be an
App::Netdisco Dancer route handler. Please bug the App::Netdisco devs if you
want arbitrary links supported.
=head2 Search and Device page Tabs
These components appear as tabs in the interface when the user reaches the
Search page or Device details page. If you add a new tab, remember that the
C<package> name in the file should be C<...Plugin::Device::MyNewFeature> (i.e.
within the Device namespace).
To register an item for display as a Search page Tab, use the following code:
register_search_tab({id => 'newfeature', label => 'My New Feature'});
This causes a tab to appear with the label "My New Feature". So how does
App::Netdisco know what the link should be? Well, as the
L<App::Netdisco::Developing> documentation says, tab content is retrieved by
an AJAX call back to the web server. This uses a predictable URL path format:
/ajax/content/<search or device>/<feature ID>
For example:
/ajax/content/search/newfeature
Therefore your plugin module should look like the following:
ajax '/ajax/content/search/newfeature' => sub {
# ...lorem ipsum...
content_type('text/html');
# return some HTML content here, probably using a template
};
If this all sounds a bit daunting, take a look at the
L<App::Netdisco::Web::Plugin::Search::Port> module which is fairly
straightforward.
To register an item for display as a Device page Tab, the only difference is
the name of the registration helper sub:
register_device_tab({id => 'newfeature', label => 'My New Feature'});
=head1 Templates
All of Netdisco's web page templates are stashed away in its distribution,
probably installed in your system's or user's Perl directory. It's not
recommended that you mess about with these files.
So in order to replace a template with your own version, or to reference a
template file of your own in your plugin, you need a new path.
TODO: this bit!
=head2 Template Variables
Some useful variables are made available in your templates automatically by
App::Netdisco:
=over 4
=item C<search_node>
A base url which links to the Node tab of the Search page, together with the
correct default search options set.
=item C<search_device>
A base url which links to the Device tab of the Search page, together with the
correct default search options set.
=item C<device_ports>
A base url which links to the Ports tab of the Device page, together with
the correct default column view options set.
=item C<uri_base>
Used for linking to static content within App::Netdisco safely if the base of
the app is relocated, for example:
<link rel="stylesheet" href="[% uri_base %]/css/toastr.css"/>
=item C<uri_for>
Simply the Dancer C<uri_for> method. Allows you to do things like this in the
template safely if the base of the app is relocated:
<a href="[% uri_for('/search') %]" ...>
=item C<self_options>
Available in the Device tabs, use this if you need to refer back to the
current page with some additional parameters, for example:
<a href="[% uri_for('/device', self_options) %]&foo=bar" ...>
=back
=cut

View File

@@ -109,11 +109,19 @@ Startup
You should (of course) avoid running this Netdisco daemon and the legacy You should (of course) avoid running this Netdisco daemon and the legacy
daemon at the same time. daemon at the same time.
Upgrading
Simply install this module again, then upgrade the database schema:
~/bin/localenv cpanm --quiet --notest App::Netdisco
DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-deploy
Tips and Tricks Tips and Tricks
Searching
The main black navigation bar has a search box which is smart enough to The main black navigation bar has a search box which is smart enough to
work out what you're looking for in most cases. For example device work out what you're looking for in most cases. For example device
names, node IP or MAC addreses, VLAN numbers, and so on. names, node IP or MAC addreses, VLAN numbers, and so on.
SQL and HTTP Trace
For SQL debugging try the following commands: For SQL debugging try the following commands:
DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \ DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \
@@ -122,9 +130,11 @@ Tips and Tricks
DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \ DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \
DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-daemon-fg DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-daemon-fg
Deployment
Other ways to run and host the web application can be found in the Other ways to run and host the web application can be found in the
Dancer::Deployment page. See also the plackup documentation. Dancer::Deployment page. See also the plackup documentation.
User Rights
With the default configuration user authentication is disabled and the With the default configuration user authentication is disabled and the
default "guest" user has no special privilege. To grant port and device default "guest" user has no special privilege. To grant port and device
control rights to this user, create a row in the "users" table of the control rights to this user, create a row in the "users" table of the
@@ -133,31 +143,29 @@ Tips and Tricks
netdisco=> insert into users (username, port_control) values ('guest', true); netdisco=> insert into users (username, port_control) values ('guest', true);
Upgrading Database API
Simply install this module again, then upgrade the database schema: Bundled with this distribution is a DBIx::Class layer for the Netdisco
database. This abstracts away all the SQL into an elegant, re-usable OO
interface. See the App::Netdisco::Developing documentation for further
information.
~/bin/localenv cpanm --quiet --notest App::Netdisco Plugins
DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-deploy App::Netdisco includes a Plugin subsystem for building the web user
interface. Items in the navigation bar and the tabs on pages are loaded
as Plugins, and you have control over their appearance and ordering. See
App::Netdisco::Web::Plugin for further information.
Future Work Developing
Bundled with this app is a DBIx::Class layer for the Netdisco database. Lots of information about the architecture of this application is
This could be a starting point for an "official" DBIC layer. Helper contained within the App::Netdisco::Developing documentation.
functions and canned searches have been added to support the web
interface.
The intention is to support "plugins" for additonal features, most
notably columns in the Device Port listing, but also new menu items and
tabs. The design of this is sketched out but not implemented. The goal
is to avoid patching core code to add localizations or less widely used
features.
Caveats Caveats
Some sections are not yet implemented, e.g. the *Device Module* tab. Some sections are not yet implemented, e.g. the *Device Module* tab.
Menu items on the main black navigation bar go nowhere, except Home. Some menu items on the main black navigation bar go nowhere.
None of the Reports yet exist (e.g. searching for wireless devices, or None of the Reports yet exist (e.g. searching for wireless devices, or
duplex mismatches). These might be implemented as a plugin bundle. duplex mismatches). These will be implemented as a plugin bundle.
The Wireless, IP Phone and NetBIOS Node properies are not yet shown. The Wireless, IP Phone and NetBIOS Node properies are not yet shown.