Extension:Farmer

About
Farmer is a tool that allows you to manage a MediaWiki farm as well as make configuration changes to a wiki via a web interface.

Changelog

 * 0.0.2 : Manage default skin and extensions via web interface. Farmer admin can select available extensions for whole site.  Individual wiki admins can select which extensions they want to be active.
 * 0.0.1 : Initial release. Ability to create a new wiki via web interface.  Ability to modify wiki permissions via web interface.

Table Prefix
Farmer requires that all MediaWiki tables have a prefix, including the tables for the default wiki. If your tables do not have a prefix, you will need to rename them. To rename a table, use the following SQL syntax:

RENAME TABLE `oldtablename` TO `newtablename`;

Writable Directory for Wiki Config Files
Farmer writes per-wiki configurations to files on disk. At run-time, the file corresponding to the accessed wiki is included and executed. We store files on disk to negate the need for a database look-up on static content. However, this means that there needs to be a directory writable by the web server in which to place these files.

Sanitize LocalSettings.php
Think of Farmer as an extension to LocalSettings.php. At the very end of the customization process, Farmer looks at the environment and adjusts variables accordingly. In other words, Farmer is now handling some of the intended functionality of LocalSettings.php.

Farmer reduces LocalSettings.php to the role of providing global settings for your MediaWiki farm. This means that the code in LocalSettings.php will be applied to every wiki in your farm. You can continue to use LocalSettings.php for extension inclusion and global variables, such as the database user, etc, but per-wiki configuration variables should not be set in LocalSettings.php.

The following is a list of variables which should NOT be set in your new LocalSettings.php.
 * $wgSitename
 * $wgDBprefix
 * $wgLogo
 * $wgGroupPermissions

In reality, it doesn't matter if some variables are defined in LocalSettings.php because they will be overwritten by Farmer. However, it is good programming practice to not define per-wiki variables in LocalSettings.php. Also, in the event that a variable is not overwritten, per-wiki settings in LocalSettings.php will be inherited by all wikis in a farm.

Decide on a Hosting Strategy
The hosting strategy refers to how wikis will be accessed via a URL. Some example strategies are outlined below.

Wildcard DNS
Wildcard DNS refers to using virtual hosts and a Wildcard DNS entry to map all sub-domains of a host to a unique wiki. For example, if your wiki site is  http://farm.mydomain , then wikis would be addressable via  http:// wiki1.farm.mydomain,  http:// wiki2.farm.mydomain, etc.

URL Prefix
URL prefix refers to identifying a wiki by a URL component, most likely a URL prefix. If you have a site  http:// farm.mydomain, wikis would be addressable via  http:// farm.mydomain/wiki1/,  http:// farm.mydomain/wiki2/, etc. If you do not have the ability to create a wildcard DNS entry, then you will be forced to use this method.

Other
Because Farmer allows you to define your own function to map a request to a wiki, it is possible to create a map that does whatever you want. For example, you could map completely different top-level domains to wikis all powered by one MediaWiki install. You could even map to a different wiki depending on the browser, etc. It is all up to you.

Patches
Farmer requires some patches to MediaWiki for it to work correctly. These patches will eventually be part of MediaWiki, so don't worry too much about hacking MediaWiki's source code too bad.

Shared Tables
Bug #2396 contains a patch for shared tables among multiple wikis. Farmer currently requires my patch to work correctly.

Once you have the patch installed, put the following in LocalSettings.php

$wgSharedTables = array(   'user'          => $sharedPrefix . 'user',    'user_groups'   => $sharedPrefix . 'user_groups',    'interwiki'     => $sharedPrefix . 'interwiki',    'math'          => $sharedPrefix . 'math', );

This will share the 'user', 'user_groups', 'interwiki', and 'math' tables among all wikis in your farm.

It is possible that one day Farmer will support non-shared user and user_groups databases, but for right now, they must be shared. It seems to make more sense for them to be shared anyway, as it is inconvenient to manage multiple accounts on the same site.

mysql_errno fix
If you are running MediaWiki trunk, don't read any further, you already have this patch. If you are running MediaWiki 1.7.1 or earlier, you don't. In Database.php, the fetchObject, fetchRow, and numRows functions all call mysql_errno directly. You need to change this to read:

if ( $this->lastErrno ) {

Obtain Source Code
The source code is available on the official Subversion repository. It is under the extensions/Farmer.

Copy Source to Extensions Directory
Copy the downloaded source code to /extensions/farmer/ in your MediaWiki directory.

Install in LocalSettings.php
At the very bottom of LocalSettings.php, add

require_once('farmer/Farmer.php');

$wgFarmer = new MediaWikiFarmer($wgFarmerSettings); $wgFarmer->run;

Configure Farmer
Farmer must be configured before it will work. Until it is configured, your wiki will be broken.

Farmer's behavior is affected by the settings in the global $wgFarmerSettings variable, which is created when Farmer.php is included.

To set a setting, alter the values in $wgFarmerSettings between the require_once('farmer/Farmer.php') and $wgFarmer = new MediaWikiFarmer($wgFarmerSettings); lines in LocalSettings.php.

You will have something like the following:

require_once('farmer/Farmer.php');

/* We use the internal _matchByURLHostname function to find the wiki name */ $wgFarmerSettings['wikiIdentifierFunction'] = array('MediaWikiFarmer', '_matchByServerName'); $wgFarmerSettings['dbAdminUser'] = 'wiki'; $wgFarmerSettings['dbAdminPassword'] = 'wiki'; $wgFarmerSettings['dbTablePrefixSeparator'] = '_-_'; $wgFarmerSettings['newDbSourceFile'] = realpath(dirname(__FILE__)). '/extensions/farmer/daughterwiki.sql';

$wgFarmer = new MediaWikiFarmer($wgFarmerSettings);

$wgFarmer->run;

$wgFarmerSettings variables and definitions
The follow are the possible configuration parameters that affect Farmer's behavior.


 * defaultWiki : The name of the default wiki. This corresponds to the table prefix of the default wiki.  The default wiki is also the main wiki on your site.  It is the only wiki whose Special:Farmer page can be used to create wikis.  This master wiki also contains messages in the Mediawiki namespace which are used to affect new farms.  When a wiki cannot be identified by wikiIdentifierFunction (see below), the accessed wiki will be the value of this variable. This value must also be in lower case. This variable must be set.


 * configDirectory : Directory where Farmer will place and read per-wiki configuration files. This directory must be writable by the web server.  It defaults to the /configs/ directory under the directory where Farmer.php resides.  For security considerations, this directory should not be accessible via the web.  It is a good idea for this directory to reside outside of your document root.


 * wikiIdentifierFunction : When Farmer runs, it calls a function that attempts to figure out the accessed wiki from environment variables. This parameter defines which function is called to do this.  The value of this configuration option is actually the first parameter to PHP's call_user_func.  The MediaWikiFarmer class has a few built-in methods which you can use:  _matchByServerName, _matchByURLRegExp.  If you require more sophisticated behavior than the provided function for determining the name of a wiki that was accessed, you can write your own function to do the mapping and set this parameter to be the name of that function.  The default value is array('MediaWikiFarmer', '_matchByURLHostname')


 * matchServerNameSuffix : When using _matchByServerName as the wikiIdentifierFunction, this parameter sets the suffix of any hostname that represents a wiki. For example, if you are using wildcard DNS to identify individual wikis (wiki1.mydomain.com, wiki2.mydomain.com, etc), then the suffix will be mydomain.com.  In other words, _matchByServerName will return every character up until the period before matchServerNameSuffix


 * onUnknownWiki : Function to call when an unknown wiki has been accessed. The value of this configuration option is the first parameter to PHP's call_user_func.  The function identified by this variable is called when the wikiIdentifierFunction has identified a wiki from the environment, but Farmer is unable to verify that this wiki exists.  The default value is array('MediaWikiFarmer', '_redirectTo').  When this function is called, the first parameter will be the name of the wiki, as identified by wikiIdentifierFunction.


 * redirectToURL : When onUnknownWiki is set to array('MediaWikiFarmer', '_redirectTo'), this option sets the URL that will be sent in a Location HTTP header. $1 in this URL will be replaced with the wiki name, as passed to the function set by onUnknownWiki.  It is a good idea for this URL to point to the Special:Farmer page on your main wiki or to instructions on how to create a wiki in case normal users don't have permission to create wikis.


 * dbAdminUser : Database user that has access to create tables on $wgDBname


 * dbAdminPassword : Password for dbAdminUser


 * newDbSourceFile : SQL source file that will be used to create a new wiki's database tables. The file must be formatted like the tables.sql files in /maintenance/ (table names must be prefixed with /*$wgDBprefix*/.  This variable defaults to daughterwiki.sql, which is is distributed with Farmer.  This SQL file is /maintenance/mysql5/tables.sql without the user, user_groups, math, and interwiki tables.  If you have installed custom extensions that require their own tables, you will want to create a new .sql import file and change this setting to link to it.


 * dbTablePrefix : Prefix for all tables in your database. This is normally not needed.  This would be needed if you only have permission to create tables with a specific prefix, etc.


 * dbTablePrefixSeparator : String to place between the wiki name and the MediaWiki table name. This is used to make table names easier to read, process, etc.  If not set to anything, a table name will just be the wiki's identifier plus table name.


 * defaultMessagesFunction : Function to call that returns an array of the messages to put in the Mediawiki namespace of newly created wikis. The value of this parameter is the first argument to PHP's call_user_func.  The returned array should have the message name as the key and the message as the key value.  If not defined, will use $wgAllMessagesEn to populate the message namespace.
 * perWikiStorageRoot : Parent directory where per-wiki documents (images, uploads, etc) will be stored. This directory everytually finds its way into the $wgUploadDirectory variable.  This directory needs to be writable by your web server.


 * defaultSkin : The skin to use for newly-created wikis. Takes same values as $wgDefaultSkin.  Defaults to monobook.

Running Farmer the First Time
After Farmer is installed in LocalSettings.php, Farmer should be usable. The first request to hit your wiki after Farmer is installed will do some special things. When your default wiki is accessed, Farmer will automatically create its configuration file and other files necessary for Farmer to work. If the directory defined in configDirectory isn't writable, Farmer will throw an exception and your wiki will not be usable. If you don't get any error messages and you can access your wiki, then everything appears to be configured properly!

Customizing Farmer Messages
Before you do anything with Farmer, you will need to customize some default system messages. Go to Special:Allmessages on your wiki. All of Farmer's messages are prefixed with farmer to keep them organized. As is the case with all extensions, it is important that you protect the pages corresponding to all of Farmer's messages to prevent any user from editing them. This is especially important with Farmer, as some of the system messages have a critical impact on Farmer's operations.

Two system messages that you will want to configure will be farmerinterwikiurl and farmerwikiurl.

farmerwikiurl
farmerwikiurl is the template for the URL of a wiki in your farm. $1 represents the wiki name. Customize the URL to match your wiki hosting strategy.

farmerinterwikiurl
farmerinterwikirul is the template for the URL used for interwiki links. $1 represents the wiki name. $2 represents the article title. Chances are this variable looks very similar to farmerwikiurl.

Setting Options for Default Wiki
Since the default wiki's configuration file is generated automatically when Farmer loads the first time, its settings are incomplete. You will need to visit Special::Farmer on your site to set them! Bad things happen unless you do this. In order to set the appropriate settings, you will need to be logged on as someone with the farmeradmin privilege. This privilege is automatically given to members of the sysop group. If you have this privilege, on Special:Farmer of your wiki, you should see a link to Administer this Wiki. Follow it.

Setting Title
On Special:Farmer/admin, it is imperative you set your wiki's title. The title can only be set once, so make sure it is correct! The title is actually an alias for $wgSitename. Therefore, it is also the name of the project namespace.

Description
Description is a text description of your wiki. You can change it at any time. It is used in the wiki farm directory.

Permissions
Set the permissions for your default wiki. All permissions default to closed. You will probably want to open up your wiki so people can actually edit it.

Using Farmer
One interfaces with Farmer via Special:Farmer. From there, one can perform many tasks.



Creating Wikis
Wikis can be created by following a link on Special:Farmer. This link is only available if the following conditions are met


 * 1) You are currently on the default wiki
 * 2) The current user has the createwiki privilege (by default assigned to the sysop group)

When you click on the link, you will see a web form with three elements.


 * Wiki Name : The name of your wiki. This will be used as part of the URL.  The name is reduced to lowercase and all non-alphanumeric characters are removed.
 * Wiki Title : The title of your wiki. This is effectively $wgSitename.  Spaces are removed for interwiki prefix compatibility.
 * Description : Description of your wiki to appear in wiki farm directory

Once you have filled out these form elements, press the button to verify them. The next page will show you what the values were modified to (if necessary). It will also give you some basic information about how your wiki will work (what the URL is, project links, etc).

To confirm that these settings are correct, press the Confirm button.

When you press the button, the following happens:


 * 1) Your wiki's basic config file is generated with the information you supplied
 * 2) The SQL in the file specified by Farmer's newDbSourceFile configuration setting is executed, creating the necessary tables
 * 3) The wiki's main page is set to the content defined in the farmernewwikimainpage system message
 * 4) The new wiki's system messages are populated
 * 5) The interwiki table is updated with a reference to this wiki
 * 6) The person who created this wiki is added to a group of the name  [farmer][wikiname][admin] , where wikiname is the name of the wiki.

If everything works, you should see a message saying your wiki was created. This message will contain a link to your new wiki.

Managing Wikis
Farmer allows system operators as well as per-wiki admins to have control over some aspects of individual wikis. These controls can be found at Special:Farmer/admin. Currently, these controls just allow you to set the wiki description and define permissions for your wiki. In the future, it is hoped to provide a much more verbose interface to other variables.

Manage Extensions
Farmer allows farmer administrators to define extensions which can be selected for loading by member wikis.

Defining Loadable Extensions
Users with the farmeradmin privilege may access Special:Farmer/manageExtensions to define extensions which can be used by wikis in the farm.

On this page, you will see a list of extensions which are already loaded, a list of PHP's include peth, and a form to define a new extension.

Unfortunately, MediaWiki does not have a good interface to abstract loading extensions. So, we have to give Farmer the filenames of extensions we wish to load. If the filename is incorrect, don't worry. Farmer verifies that the file exists and is includable before adding an extenion to its list. If there was a problem adding an extension, Farmer will say so.

Per-Wiki Extension Management
Child wiki administrators may go to Special:Farmer/admin to select which loadable extensions to activate on a particular wiki.