From 76c32e1669d27490b60bd7944b2922d008efdbac Mon Sep 17 00:00:00 2001 From: Oliver Gorwits Date: Sat, 9 Feb 2013 21:56:32 +0000 Subject: [PATCH] add Plugin POD and knock back version to beta release --- DEVELOPING.txt | 431 ++++++++++++++++++ Netdisco/Changes | 2 +- Netdisco/MANIFEST | 2 +- Netdisco/META.yml | 2 +- Netdisco/lib/App/Netdisco.pm | 46 +- .../App/Netdisco/Developing.pod} | 18 +- Netdisco/lib/App/Netdisco/Web/Plugin.pm | 234 ++++++++++ README.txt | 58 ++- 8 files changed, 741 insertions(+), 52 deletions(-) create mode 100644 DEVELOPING.txt rename Netdisco/{DEVELOPING.pod => lib/App/Netdisco/Developing.pod} (97%) diff --git a/DEVELOPING.txt b/DEVELOPING.txt new file mode 100644 index 00000000..e3f06d90 --- /dev/null +++ b/DEVELOPING.txt @@ -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 ".yml" where + "" 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. + diff --git a/Netdisco/Changes b/Netdisco/Changes index 398e7c18..0866ed7f 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -1,4 +1,4 @@ -2.006000 - +2.005000_001 - 2013-02-09 [NEW FEATURES] diff --git a/Netdisco/MANIFEST b/Netdisco/MANIFEST index c116e330..730ea754 100644 --- a/Netdisco/MANIFEST +++ b/Netdisco/MANIFEST @@ -6,7 +6,6 @@ bin/netdisco-deploy bin/netdisco-web bin/netdisco-web-fg Changes -DEVELOPING.pod inc/Module/Install.pm inc/Module/Install/Base.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-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/DeviceProperties.pm lib/App/Netdisco/Util/Permissions.pm diff --git a/Netdisco/META.yml b/Netdisco/META.yml index ee8a2287..6d35a059 100644 --- a/Netdisco/META.yml +++ b/Netdisco/META.yml @@ -51,4 +51,4 @@ resources: homepage: http://netdisco.org/ license: http://opensource.org/licenses/bsd-license.php repository: git://netdisco.git.sourceforge.net/gitroot/netdisco/netdisco-ng -version: 2.006000 +version: 2.005000_001 diff --git a/Netdisco/lib/App/Netdisco.pm b/Netdisco/lib/App/Netdisco.pm index 369fa883..1faa25b2 100644 --- a/Netdisco/lib/App/Netdisco.pm +++ b/Netdisco/lib/App/Netdisco.pm @@ -7,7 +7,7 @@ use 5.010_000; use File::ShareDir 'dist_dir'; use Path::Class; -our $VERSION = '2.006000'; +our $VERSION = '2.005000_001'; BEGIN { 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 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 +=head2 Searching + 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 or MAC addreses, VLAN numbers, and so on. +=head2 SQL and HTTP Trace + For SQL debugging try the following commands: 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 \ DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-daemon-fg +=head2 Deployment + Other ways to run and host the web application can be found in the L page. See also the L documentation. +=head2 User Rights + With the default configuration user authentication is disabled and the default "guest" user has no special privilege. To grant port and device control rights to this user, create a row in the C table of the Netdisco database with @@ -169,32 +184,33 @@ a username of C and the C flag set to 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 layer for the Netdisco +database. This abstracts away all the SQL into an elegant, re-usable OO +interface. See the L documentation for further +information. - ~/bin/localenv cpanm --quiet --notest App::Netdisco - DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-deploy +=head2 Plugins -=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 for further information. -Bundled with this app is a L layer for the Netdisco database. -This could be a starting point for an "official" DBIC layer. Helper functions -and canned searches have been added to support the web interface. +=head2 Developing -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. +Lots of information about the architecture of this application is contained +within the L documentation. =head1 Caveats Some sections are not yet implemented, e.g. the I 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 -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. diff --git a/Netdisco/DEVELOPING.pod b/Netdisco/lib/App/Netdisco/Developing.pod similarity index 97% rename from Netdisco/DEVELOPING.pod rename to Netdisco/lib/App/Netdisco/Developing.pod index c3f11bab..9bf20491 100644 --- a/Netdisco/DEVELOPING.pod +++ b/Netdisco/lib/App/Netdisco/Developing.pod @@ -248,10 +248,10 @@ This is a typical Template::Toolkit "wrapper" configuration, as noted by the C<[% content %]> call within C that loads the template you actually specified in your Dancer handler. -All templates (and Javascript and Stylesheets) are shipped in the Dancer -distribution and located automatically by the application (using the -environment variables which L set up). The user doesn't have to -copy or install any files. +All templates (and Javascript and Stylesheets) are shipped in the +L 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 C, then separate templates for searching, displaying device details, and showing inventory. @@ -275,11 +275,11 @@ organised below C in the distribution. =head2 Stylesheets -The main style for Netdisco uses Twitter Bootstrap, which is a stylish modern -library of styles 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. +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 C. We try to name all CSS classes with a prefix "C" so as to be distinct from diff --git a/Netdisco/lib/App/Netdisco/Web/Plugin.pm b/Netdisco/lib/App/Netdisco/Web/Plugin.pm index 5a7efe8c..e8bbf64a 100644 --- a/Netdisco/lib/App/Netdisco/Web/Plugin.pm +++ b/Netdisco/lib/App/Netdisco/Web/Plugin.pm @@ -57,3 +57,237 @@ register 'register_device_tab' => sub { register_plugin; true; + +=head1 NAME + +App::Netdisco::Web::Plugin - Plugin subsystem for App::Netdisco Web UI components + +=head1 Introduction + +L'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 file for App::Netdisco (located in C) +you'll find the C 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" to the name. This makes, for example, +L. 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 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 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 setting. In fact, we +recommend adding this setting to your C<< .yml >> file and +leaving the C file alone. Your Environment's version will take +prescedence. + +Finally, if you want to add components without completely overriding the +C setting, use the C setting instead in your +Environment configuration. Any Navigation Bar items or Page Tabs are added +after those in C. + +=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 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 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 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 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 documentation says, tab content is retrieved by +an AJAX call back to the web server. This uses a predictable URL path format: + + /ajax/content// + +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 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 + +A base url which links to the Node tab of the Search page, together with the +correct default search options set. + +=item C + +A base url which links to the Device tab of the Search page, together with the +correct default search options set. + +=item C + +A base url which links to the Ports tab of the Device page, together with +the correct default column view options set. + +=item C + +Used for linking to static content within App::Netdisco safely if the base of +the app is relocated, for example: + + + +=item C + +Simply the Dancer C method. Allows you to do things like this in the +template safely if the base of the app is relocated: + + + +=item C + +Available in the Device tabs, use this if you need to refer back to the +current page with some additional parameters, for example: + + + +=back + +=cut + diff --git a/README.txt b/README.txt index ef0f1f84..9b170d37 100644 --- a/README.txt +++ b/README.txt @@ -40,12 +40,12 @@ Dependencies new database and PostgreSQL user for the Netdisco application: root:~# su - postgres - - postgres:~$ createuser -DRSP netdisco + + postgres:~$ createuser -DRSP netdisco Enter password for new role: Enter it again: - - postgres:~$ createdb -O netdisco netdisco + + postgres:~$ createdb -O netdisco netdisco Installation To avoid muddying your system, use the following script to download and @@ -109,22 +109,32 @@ Startup You should (of course) avoid running this Netdisco daemon and the legacy 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 + Searching 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 or MAC addreses, VLAN numbers, and so on. + SQL and HTTP Trace For SQL debugging try the following commands: DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \ DANCER_ENVDIR=~/environments ~/bin/localenv plackup ~/bin/netdisco-web-fg - - DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \ + + DBIC_TRACE_PROFILE=console DBIC_TRACE=1 \ DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-daemon-fg + Deployment Other ways to run and host the web application can be found in the Dancer::Deployment page. See also the plackup documentation. + User Rights With the default configuration user authentication is disabled and the 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 @@ -133,31 +143,29 @@ Tips and Tricks netdisco=> insert into users (username, port_control) values ('guest', true); -Upgrading - Simply install this module again, then upgrade the database schema: + Database API + 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 - DANCER_ENVDIR=~/environments ~/bin/localenv netdisco-deploy + Plugins + 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 - Bundled with this app is a DBIx::Class layer for the Netdisco database. - 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 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. + Developing + Lots of information about the architecture of this application is + contained within the App::Netdisco::Developing documentation. Caveats 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 - 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. @@ -177,8 +185,8 @@ COPYRIGHT AND LICENSE * Neither the name of the Netdisco Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE NETDISCO DEVELOPER TEAM BE LIABLE FOR ANY