Archive

Archive for May, 2010

Apache virtual host script in perl

May 27th, 2010 Ivan Villareal 2 comments

This is a very short post about a little script I did to create remove virtual hosts easily.

I’ve found a couple of scripts (http://patrickgibson.com/utilities/virtualhost/, http://www.tamdenholm.com/portfolio/apache)  to do this but they didn’t worked right, I’m using Ubuntu Karmic, maybe thats why. However instead of fixing those scripts I went to my vim editor and started typing this, I’ve spent about 2 hours writing this while I was watching a crappy tv program, but in the end it worked, it surely contains some bugs, or it is unsafe to run it, I just wanted to share this.

#!/usr/bin/perl -w
use strict;
use File::Path qw(mkpath rmtree);
use Getopt::Long;
 
 
our $ipAddress        = '127.0.0.1';
our $apacheConfigFile = 'apache2.conf';
our $apacheConfigDir  = '/etc/apache2';
our $sitesAvailable   = 'sites-available';
 
our $docRootPrefix = '/home/ivan/www';
our $docRoot = 'public_html';
our $logsDir  = 'logs';
 
 
my $del = '';
my $add = '';
my $domain = '';
 
unless (GetOptions ('del' => \$del, 'add' => \$add, 'domain=s' => \$domain) or usage()) {
    usage();
}
 
#print $paramResults;
if ($add || $del) {
    if ($domain) {
        if ($add) {
            createVhost($domain);
        } elsif ($del) {
            deleteVhost($domain);
        }
    } else {
        usage();
    }
   #print 'add aqui';
} else {
    usage();
}
 
sub usage {
    print < <USAGE
This program will add or remove
apache virtual hosts on ubuntu karmic 9.10
 
usage: vhost-updater.pl [--add | --del] --domain newhost.tld 
USAGE
}
 
sub returnVhostPaths
{
    my $vhost = shift;
    my @dir = split(/\//, $docRootPrefix);
    my %res;
 
    push(@dir, $vhost);
 
    my $hostDir = join('/', @dir);
    $res{'docRoot'} = $hostDir . '/' . $docRoot;
    $res{'logsDir'} = $hostDir . '/' . $logsDir;
 
    #todo dir validation
    @dir = split(/\//, $apacheConfigDir);
    push(@dir, $sitesAvailable);
    push(@dir, $vhost);
    $res{'apacheConfig'} = join('/', @dir);
 
    return %res;   
}
 
sub createVhost {
    my $vhost = shift;
    #first create the docRoot
    my %vhostInfo = returnVhostPaths($vhost);
 
    informOut("Creating docroot dir: $vhostInfo{'docRoot'}");
    informOut("Creating log dir: $vhostInfo{'logsDir'}");
    mkpath($vhostInfo{'docRoot'}, $vhostInfo{'logsDir'});
 
 
    informOut("Site File: $vhostInfo{'apacheConfig'}");
 
    my $vhostContent = << "EOF";
<VirtualHost *:80>
    ServerName $vhost
    DocumentRoot $vhostInfo{'docRoot'}
    <directory $vhostInfo{'docRoot'}>
        Options Indexes FollowSymLinks
        AllowOverride All
        Order allow,deny
        Allow from all
    </directory>
        ErrorLog $vhostInfo{'logsDir'}/error_log
        CustomLog $vhostInfo{'logsDir'}/access_log "%h %l %u %t \\"%r\\" %>s %b \\"%{Referer}i\\" \\"%{User-agent}i\\""
        LogLevel debug
 
 
EOF
    informOut("Creating Vhost...");
    open FILE, ">", $vhostInfo{'apacheConfig'} or die $!;
    print FILE $vhostContent;
    close FILE;
 
    informOut("Adding host $vhost");
    open FILE, ">>", '/etc/hosts' or die $!;
    print FILE $ipAddress ."\t". $vhost ."\n";
    close FILE;
 
    my $output = `/usr/sbin/a2ensite $vhost`;
    print $output;
 
    restartApache();
    #print $vhostConten t;
}
 
sub restartApache
{
    informOut("Restarting apache");
    my $output = `/etc/init.d/apache2 restart`;
    print $output; 
}
 
sub deleteVhost
{
    my $vhost = shift;
     my %vhostInfo = returnVhostPaths($vhost);
 
    informOut("Removing $vhost from hosts file");
    open IN, '< ', '/etc/hosts' or die $!;
    my @hostsFile = <IN>;
    close IN;
 
    my @contents = grep(!/^127.0.0.1\t$vhost/, @hostsFile);
 
    open FILE, ">", '/etc/hosts' or die $!;
    print FILE @contents;
    close FILE;
 
    my $output = `/usr/sbin/a2dissite $vhost`;
    print $output;
 
    informOut("Removing  $vhostInfo{'apacheConfig'} file");
    unlink($vhostInfo{'apacheConfig'});
 
    restartApache();
 
    print " manually remove $vhostInfo{'docRoot'}... \n";
 
}
 
sub informOut {
    my $message = shift;
    print "$message \n";
}

Here is a screenshot of the program running

vhost creator Screenshot

Categories: Linux, Perl, configuration Tags:

Bulk domain name resolver with perl

May 7th, 2010 Ivan Villareal No comments

I was in the need of getting the ip address from a long list of domain names, the domains were stored in a MySQL db, so I quickly turned into perl for making a script that got the list and then use an external command to resolve the domain.

At first I was going to use the dig command, but that would have taken to much effort, then I thought about using the ping command, but again to much effort, instead I’ve decided to leverage the IO::Socket::INET module, trying to open a socket to a domain name, will resolve the name and I could use that.

My implementation was very simple and it worked well, here is the relevant part:

 

 

 

#include the module
use IO::Socket::INET;
 
#create a socket to uncommon udp port, because tcp is likely to be firewalled
my $sock = IO::Socket::INET->new(
                           PeerAddr=> "$domain",
                           PeerPort =>40125,
                           Proto=>'udp');
 
#if we can create a socket, then we have an ip
if (defined $sock) {
         $result = $sock->peerhost;
         logOut("Success!");
    } else {
        logOut("Failed trying to connect to $domain");
        return;
    }

 

This was Pretty simple no?, here is the complete script, which gathers all the rows with no ip address and then it will try to get the ip, update the row and continue.

 

#!/usr/bin/perl
use strict;
use DBI;
use IO::Socket::INET;
 
####Global Variables###
 
our %db = ('host' => 'localhost','name' => 'domains','user' => 'ivan','pass' => '1234','port' => '3306');
our $dsn;
our $dbh;
 
#log function
sub logOut {
    my ($msg) = @_;
    print $msg . "\n";
}
 
#db connection
sub initialize {
    logOut("Connecting to db server on $db{'host'}");
    $dsn = "DBI:mysql:database=$db{'name'};host=$db{'host'};port=$db{'port'}";
    $dbh = DBI->connect($dsn, $db{'user'}, $db{'pass'}) or die('failed to connect');
}
 
#function to gather the ip fo a domain
sub getIpAddress {
    my ($domain) = @_;
    logOut("Trying to connect to: $domain...");
    my $result;
    my $sock = IO::Socket::INET->new(
                           PeerAddr=> "$domain",
                           PeerPort =>40125,
                           Proto=>'udp');
    if (defined $sock) {
         $result = $sock->peerhost;
         logOut("Success!");
    } else {
        logOut("Failed trying to connect to $domain");
        return;
    }
    return $result;
}
 
##This function
# gets all domains from domains table
sub getDomains {
    logOut("Fetching db for domains...");
    my $result = $dbh->selectall_hashref("SELECT domain_name FROM domains WHERE ip_address IS NULL", 'domain_name');
    logOut(keys( %$result ) . " domains returned.");
    my $updatedDomains = 0;
    my $noIpDomains    = 0;
    foreach my $id (keys %$result) {
        my $ip = getIpAddress($result->{$id}->{domain_name});
        if ($ip) {
            logOut("Ip found $ip for $result->{$id}->{domain_name}");
            my @values = ($ip, $result->{$id}->{domain_name});
            my $re = $dbh->do("UPDATE domains SET ip_address=? WHERE domain_name=?",undef, @values);
                if ($re == 1) {
                    $updatedDomains++;
                }
        } else {
            logOut("no ip for $result->{$id}->{domain_name}");
            $noIpDomains++;
        }
    }
    logOut("Updated Domains: $updatedDomains");
    logOut("Domains with no Ip found: $noIpDomains");
}
 
#script starts here
initialize();
getDomains();

Maybe there are more efficient methods but as I said, this worked pretty well, it didn’t consume a lot of results and it performs fast enough for my needs.

Partial Db backups with mysqldump

May 5th, 2010 Ivan Villareal No comments

I was updating my db dev instance with a set of changes, and when I was restoring the dump for a table it contained a drop db clause :( it was a simple table and it took a about 15 seconds to finish the operation, when I looked at the db schema all the tables were gone!

This db has a very large table about 16Gb of binary data, so getting a new dump would require a lot of time, so as workaround I’ve dumped only sets of data that I need to my tests.

First I did a dump of the db schema with no data:

mysqldump -h host-u ${USER} --password=${PASS} --no-data --add-drop-database --databases largeDb> schema_largeDb.sql

then I created a dump for the tables that I need, for this I have to include a list of tables that I don’t want, I’ve created the list of unwanted tables manually.

mysqldump -h host-u ${USER} --password=${PASS} --no-create-info --ignore-table=largeDb.unwantedTable1 --ignore-table=largeDb.unwantedTable2 --ignore-table=largeDb.unwantedTable3 > smallData.sql

And because I need data from the big table, I’ve used the –where clause to limit the rows returned in

mysqldump -h host-u ${USER} --password=${PASS} "--where=brand_id='2496'" largeDb bigTable > binaryData.sql

With this one I was able to get only the binaryData that I need to make my tests, instead of waiting to get for the entire dbDump,

Categories: Development, Mysql Tags: