FacebookTwitterFlickrYoutuberss

Version 5

From Zentyal Linux Small Business Server
Jump to: navigation, search

Index || < Prev | Next >


Contents

Version 0.5: adding a second table

In this version we will add support for virtual hosts. As we have done so far, we will do it in an incremental way, starting from a version with just a few features.

Data model

We need to create a new model to store the virtual hosts. This initial version will only have one field called name which obviously will store the name of the virtual host. This field must store fully qualified domain names (FQDN) and must check that its stored data has a valid syntax. Zentyal already has a type that meets our needs: EBox::Types::DomainName.

Create the new model as src/EBox/Apache2/Model/VirtualHosts.pm whose code will look like this:


package EBox::Apache2::Model::VirtualHosts;

use base 'EBox::Model::DataTable';

use strict;
use warnings;

use EBox::Gettext;

use EBox::Types::DomainName;

sub _table
{

    my ($self) = @_;  

    my @fields = (
        new EBox::Types::DomainName(
            'fieldName' => 'name',
            'printableName' => __('name'),
            'size' => '8',
            'unique' => 1,
            'editable' => 1
        ),
    );

    my $dataTable =
    {
        'tableName' => 'VirtualHosts',
        'printableTableName' => __('VirtualHosts'),
        'modelDomain' => 'Apache2',
        'defaultActions' => ['add', 'del', 'editField', 'changeView' ],
        'tableDescription' => \@fields,
        'help' => '', # FIXME
    };

    return $dataTable;
}

1;

We need to add this new model to the yaml schema at schemas/apache2.yaml:

class: EBox::Apache2

models:
    - Settings
    - Modules
    - VirtualHosts

Now let's make a couple of changes. We will set the printable name of our type from name to Virtual Host. We will also tell the framework to order the table using the name field.

Now our model looks like this:

package EBox::Apache2::Model::VirtualHosts;

use base 'EBox::Model::DataTable';

use strict;
use warnings;

use EBox::Gettext;

use EBox::Types::DomainName;

sub _table
{

    my ($self) = @_;  

    my @fields = (
        new EBox::Types::DomainName(
            'fieldName' => 'name',
            'printableName' => __('Virtual Host'), # Changed
            'size' => '8',
            'unique' => 1,
            'editable' => 1
        ),
    );

    my $dataTable =
    {
        'tableName' => 'VirtualHosts',
        'printableTableName' => __('VirtualHosts'),
        'modelDomain' => 'Apache2',
        'defaultActions' => ['add', 'del', 'editField', 'changeView' ],
        'tableDescription' => \@fields,
        'help' => '', # FIXME
        'sortedBy' => 'name', # Changed
    };

    return $dataTable;
}

1;

Let's add a new menu entry in the menu() entry to src/EBox/Apache2.pm as we learnt before:

# Method: menu
#
# Overrides:
#
#       <EBox::Module::menu>
#
sub menu
{
    my ($self, $root) = @_;

    my $folder = new EBox::Menu::Folder(
        'separator' => 'Core',
        'order' => 1,
        'name' => 'Apache2',
        'text' => __('Apache2')
    );

    my $settings = new EBox::Menu::Item(
        'url' => 'Apache2/View/Settings',
        'text' => __('Settings')
    );

    my $modules = new EBox::Menu::Item(
        'url' => 'Apache2/View/Modules',
        'text' => __('Modules')
    );

    my $vhosts = new EBox::Menu::Item(
        'url' => 'Apache2/View/VirtualHosts',
        'text' => __('Virtual Hosts')
    );

    $folder->add($settings);
    $folder->add($modules);
    $folder->add($vhosts);

    $root->add($folder);
}

Build and install the package as usual. Click on the Apache2 menu folder entry and you will see something like this:

Image(virtual-host-1.png)

Now we would like to let the user to enable and disable any virtual host. Your first thought should be just adding a new boolean field as we did with the Modules model. This is not necessary as Zentyal does it automatically for you under the hood if you set the enableProperty value to true. By doing this you are telling the framework to automatically add a new boolean field.

In the method _table() in src/EBox/Apache2/Model/VirtualHosts.pm you have to set enableProperty to 1 as follows:

sub _table                                                                      
{                                                                               
                                                                                
    my ($self) = @_;--                                                          
                                                                                
    my @fields = (                                                              
        new EBox::Types::DomainName(                                            
            'fieldName' => 'name',                                              
            'printableName' => __('Virtual Host'),                              
            'size' => '8',                                                      
            'unique' => 1,                                                      
            'editable' => 1                                                     
        ),                                                                      
    );                                                                          
                                                                                
    my $dataTable =                                                             
    {                                                                           
        'tableName' => 'VirtualHosts',                                          
        'printableTableName' => __('VirtualHosts'),                             
        'modelDomain' => 'Apache2',                                             
        'defaultActions' => ['add', 'del', 'editField', 'changeView' ],         
        'tableDescription' => \@fields,                                         
        'help' => '', # FIXME                                                   
        'sortedBy' => 'name',
        'enableProperty' => 1, # Change
    };                                                                          
                                                                                
    return $dataTable;                                                          
}

Build, install and check it out now:

Image(virtual-host-2.png)

Fetching the stored values

As we did with the previous versions, let's code a simple script so that we can retrieve the stored values:

use EBox;
use EBox::Model::ModelManager;
use EBox::Global;

# This is the very first thing we always have to do from external scripts
EBox::init();

my $module = EBox::Global->modInstance('apache2');

my $modules= $module->model('VirtualHosts');

# Iterates over the rows and print info
for my $id (@{$modules->ids()}) {
        my $row = $modules->row($id);
        my $name = $row->valueByName('name');
        my $enabled = $row->valueByName('enabled');
        print "Module: $name enabled $enabled\n";
}

Setting the apache configuration

For every virtual host we will create a file in /etc/apache2/sites-available/. For those that are available, we will create a link in /etc/apache2/sites-enabled.

We need to create a Mason template to configure every Apache virtual host:

Create a file in stubs/virtual-host.conf.mas and add the following code:

<%args>
$name
</%args>
<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        ServerName <% $name %>

        DocumentRoot /var/www/<% $name %>
        <Directory />
                Options FollowSymLinks
                AllowOverride None
        </Directory>
        <Directory /var/www/<% $name %>>
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                Allow from all
        </Directory>

        ErrorLog /var/log/apache2/error.log

        # Possible valu
        # alert, emerg.
        LogLevel warn

        CustomLog /var/log/apache2/access.log combined
</VirtualHost>

As you can see, the only parameter that this template receives is the name of the virtual host. This name is used to configure the ServerName and its document root. Check the apache documentation if you want to know what the other parameters mean.

Now it's time to do stuff in our main class to generate the configuration for each virtual host. Roughly speaking, we will do the following: for each virtual host we will create/modify a file in /etc/apache2/sites-available. We will use the apache2 tools a2ensite and a2dissite to enable or disable the virtual hosts according to the user configuration.

Let's create a private method called _setVirtualHosts() in our main class src/EBox/Apache2.pm:

# Method: _setVirtualHosts
#
#       This method is used to set the virtual hosts
#
sub _setVirtualHosts
{
    my ($self) = @_;

    my $model = $self->model('VirtualHosts');

    # Iterate over the virtual host table
    for my $id (@{$model->ids()}) {
        my $row = $model->row($id);
        my $name = $row->valueByName('name');
        my $enabled = $row->valueByName('enabled');
        my $outputFile = "/etc/apache2/sites-available/ebox-$name";
        my @params = (name => $name);
        # Write virtual host configuration file
        $self->writeConfFile(
            $outputFile, 'apache2/virtual-host.conf.mas', \@params);

        # Create the document root directory if it does not exist
        my $docRoot = "/var/www/$name";
        unless ( -d $docRoot ) {
            EBox::Sudo::root("mkdir $docRoot");
        }
        # Enable or disable the virtual host depending on the user
        # configuration
        if ($enabled) {
            EBox::Sudo::root("a2ensite ebox-$name");
        } else {
            EBox::Sudo::root("a2dissite ebox-$name");
        }
    }
}

As we are modifying files, we have to let the framework know which files we are working with. You should remember, we have to implement the method usedFiles() in our main class. We have to return an array reference containing all these files. So the code will look like:

# Method: usedFiles
#
#   Override EBox::ServiceModule::ServiceInterface::usedFiles
#
sub usedFiles                                                                   
{                                                                               
                                                                                
    my $model = $self->model('VirtualHosts');                                   
                                                                                
    my @usedFiles;                                                              
    for my $id (@{$model->ids()}) {                                             
        my $row = $model->row($id);                                             
        my $name = $row->valueByName('name');                                   
        push (@usedFiles, {                                                     
            file => "/etc/apache2/sites-available/ebox-$name",                  
            module => 'apache2',                                                
            reason => __('To configure the virtual host')                       
        });                                                                     
    }                                                                           
                                                                                
    push (@usedFiles, {                                                         
        'file' => '/etc/apache2/ports.conf',                                    
        'module' => 'apache2',                                                  
        'reason' => __('To configure the apache port')                          
    });                                                                         
                                                                                
    return \@usedFiles;                                                         
}    

The last change is actually calling the _setVirtualHost() method from _setConf:

# Method: _setConf
#
#       Overrides EBox::Module::Service::_setConf
#
sub _setConf
{
    my ($self) = @_;                                                            
                                                                                
    my $settings = $self->model('Settings');                                    
    my $port = $settings->value('listeningPort');                               
                                                                                
    my @params = (                                                              
        port => $port,                                                          
    );                                                                          
                                                                                
    $self->writeConfFile(                                                       
        $CONFFILE,                                                              
        "apache2/service.conf.mas",                                             
        \@params,                                                               
        { 'uid' => '0', 'gid' => '0', mode => '644' }                           
    );                                                                          
                                                                                
    $self->_configureModules();                                                 
    $self->_setVirtualHosts();  
}

Let's recap all the changes that we need to make to src/EBox/Apache2.pm:

package EBox::Apache2;

use base qw(EBox::Module::Service);

use strict;
use warnings;

use EBox::Global;
use EBox::Gettext;
use EBox::Sudo;

my $CONFFILE = '/etc/apache2/ports.conf';

# Method: _create
#
# Overrides:
#
#       <Ebox::Module::Base::_create>
#
sub _create
{
    my $class = shift;
    my $self = $class->SUPER::_create(name => 'apache2',
                                      printableName => __('Apache2'),
                                      @_);
    bless ($self, $class);
    return $self;
}

# Method: menu
#
# Overrides:
#
#       <EBox::Module::menu>
#
sub menu
{
    my ($self, $root) = @_;

    my $folder = new EBox::Menu::Folder(
        'separator' => 'Core',
        'order' => 1,
        'name' => 'Apache2',
        'text' => __('Apache2')
    );

    my $settings = new EBox::Menu::Item(
        'url' => 'Apache2/View/Settings',
        'text' => __('Settings')
    );

    my $modules = new EBox::Menu::Item(
        'url' => 'Apache2/View/Modules',
        'text' => __('Modules')
    );

    my $vhosts = new EBox::Menu::Item(
        'url' => 'Apache2/View/VirtualHosts',
        'text' => __('Modules')
    );

    $folder->add($settings);
    $folder->add($modules);
    $folder->add($vhosts);

    $root->add($folder);
}

# Method: _daemons
#
# Overrides:
#
#       <EBox::Module::Service::_daemons>
#
sub _daemons
{
    my $daemons = [
        {
            'name' => 'apache2',
            'type' => 'init.d',
            'pidfiles' => ['/var/run/apache2.pid']
        }
    ];

    return $daemons;
}

# Method: _configureModules
#
#       This method is used to enable or disable apache modules based
#       on the user configuration.
#
sub _configureModules
{
    my ($self) = @_;

    my $model = $self->model('Modules');

    for my $id (@{$model->ids()}) {
        my $row = $model->row($id);
        my $module = $row->valueByName('module');
        my $enabled = $row->valueByName('enabled');
        if ($enabled) {
            EBox::Sudo::root("a2enmod $module");
        } else {
            EBox::Sudo::root("a2dismod $module");
        }
    }
}


# Method: _setVirtualHosts
#
#       This method is used to set the virtual hosts
#
sub _setVirtualHosts
{
    my ($self) = @_;

    my $model = $self->model('VirtualHosts');

    # Iterate over the virtual host table
    for my $id (@{$model->ids()}) {
        my $row = $model->row($id);
        my $name = $row->valueByName('name');
        my $enabled = $row->valueByName('enabled');
        my $outputFile = "/etc/apache2/sites-available/ebox-$name";
        my @params = (name => $name);
        # Write virtual host configuration file
        $self->writeConfFile(
            $outputFile, 'apache2/virtual-host.conf.mas', \@params);

        # Create the document root directory if it does not exist
        my $row = $model->row($id);my $docRoot = "/var/www/$name";
        unless ( -d $docRoot ) {
            EBox::Sudo::root("mkdir $docRoot");
        }
        # Enable or disable the virtual host depending on the user
        # configuration
        if ($enabled) {
            EBox::Sudo::root("a2ensite ebox-$name");
        } else {
            EBox::Sudo::root("a2dissite ebox-$name");
        }
    }
}


# Method: _setConf
#
# Overrides:
#
#       <EBox::Module::Base::_setConf>
#
sub _setConf
{
    my ($self) = @_;

    my $settings = $self->model('Settings');
    my $port = $settings->value('listeningPort');

    my @params = (
        port => $port,
    );

    $self->writeConfFile(
        $CONFFILE,
        "apache2/service.conf.mas",
        \@params,
        { 'uid' => '0', 'gid' => '0', mode => '644' }
    );

    $self->_configureModules();
    $self->_setVirtualHosts();
}

# Method: usedFiles
#
#   Override EBox::Module::Service::usedFiles
#
sub usedFiles
{

    my $model = $self->model('VirtualHosts');

    my @usedFiles;
    for my $id (@{$model->ids()}) {
        my $row = $model->row($id);
        my $name = $row->valueByName('name');
        push (@usedFiles, {
            file => "/etc/apache2/sites-available/ebox-$name",
            module => 'apache2',
            reason => __('To configure the virtual host')
        });
    }

    push (@usedFiles, {
        'file' => '/etc/apache2/ports.conf',
        'module' => 'apache2',
        'reason' => __('To configure the apache port')
    });

    return \@usedFiles;
}

1;


Index || < Prev | Next >

Template:TracNotice

Personal tools
Namespaces

Variants
Actions

Zentyal Wiki

Zentyal Doc
Navigation
Toolbox