Friday, April 10, 2009

JavaScript: Get the Current URI's Domain Name

We have consultants that do some work for us (who doesn't?). I have a beta site setup for them to test with. But for some reason when I check the beta site, the URI's for this one part are going directly to the production site. "Hmmm...why...oh huh?! why!?" So it turns out they were hard-coding a domain root as part of the URI in one of their javascript runs. Now really, what kind of portability does that give me!?

Their code looked similar to this:var uri = 'http://drincruz.blogspot.com/' + uriPath;

So, I figured I'll fix this little nuisance by writing a quick function that will get the domain root of a URI. Now, I'm sure there's some sort of built-in function that'll get me what I need, but I couldn't find it. So if there is, someone please let me know!


function getDomainRoot()
{
var uri = location.href;
var startIndex;
if (null != uri.match("file:///") )
startIndex = 8;
if (null != uri.match("http://") )
startIndex = 7;
if (null != uri.match("https://") )
startIndex = 8;
var endIndex = uri.indexOf("/", startIndex);
var domainRoot = uri.substring(0, endIndex);
return domainRoot;
}


Now, I can put this function into their javascript and it can now be used like this:
var uri = getDomainRoot + '/' + uriPath;

/* I should really add a trailing slash check. Ah well. Next time! */

Cheers!

Tuesday, April 7, 2009

Moving a MySQL Cluster to New Hardware

Well, it came to that point in any server's life, it could no longer add any additional disks for space, the cost to upgrade the memory and/or hard disks don't outweigh the benefits of upgrading to new hardware; it's time to put these babies to sleep.

So one of our active/passive MySQL clusters had a three hour maintenance window last night (technically this morning: 12am-3am). The servers came in a few weeks earlier so I had them prepped beforehand. Though, how do you minimize downtime while moving moving the databases over? Well, obviously don't take down the server unless absolutely necessary and of course automate as much of the process as possible!

12am: I'll kick off my script that backs up all DBs in our cluster and saves them in a mount point on a SAN that the new servers can read as well.
## I really could have run this process before 12am as it didn't cause an outage. Ah well, next time.

~12:45am: Now that we have the data, we can now take down the MySQL cluster. I basically rebooted the cluster servers with new IP addresses and hostnames. I now set the IP addresses of the new cluster boxes to have the original IP addresses of the old cluster. See what I did there? Basically, we have a lot of web apps pointing to the DNS of the MySQL cluster, so we need that DNS. (Yes, yes, we could've just updated DNS as well; it's a long story, but basically my department doesn't handle DNS, so going this route is more seamless.)

I already set up replication in MySQL, but as the hostnames have now changed, well replication broke. This was the only snag in the maintenance really. Basically, what happened was MySQL was looking for the old relay logs with the old hostname. Enter, MySQL's nice documentation. I just needed to do this really:

shell< cat new_host_name-relay-bin.index >> old_host_name-relay-bin.index

shell< mv old_host_name-relay-bin.index new_host_name-relay-bin.index


1am: Now that replication is working, all I needed to do was load the data, which is one last script to run.

Here's the basic rundown:
- find the db dump
- create the db
- gunzip the db dump to a tmp dir
- load the dump to the db
- run GRANTs for whatever user


#!/usr/bin/perl -w

# mysqldumpload.pl

use strict;
use DBI;
use File::Find;

my $dbuser = qw(dbuser);
my $dbpass = qw(dbpass);
my $backupdir = "/mnt/backup/mysql";
my $dumpdir = "/usr/local/tmp/dump";

my $dbh = DBI->connect("DBI:mysql:mysql",$dbuser,$dbpass)
or die "Couldn't connect to db: $!";

my @files;

find(\&findFile, $backupdir);


sub findFile {
my $file = $File::Find::name;
# if it's a db, another_db, or another_db2 process it!
if ($_ =~ /db/ or $_ =~ /another_db/ or $_ =~ /another_db2/) {
print "Processing $_...\n";
my $dump = $_;
$dump =~ s/\.gz//g;
my $mysqldb = $dump;
$mysqldb =~ s/\.sql//g;
my $sql = qq!CREATE DATABASE $mysqldb!;
$sth = $dbh->prepare($sql);
print "$sql\n";
$sth->execute();
my $dumpfile = "$dumpdir/$dump";
my $gunzip = qq!gunzip -c $file > $dumpfile!;
print "$gunzip\n";
system($gunzip);
my $mysqlload = qq!mysql --user=$dbuser --password=$dbpass $mysqldb < $dumpfile!;
print "$mysqlload\n";
system($mysqlload);
if ($_ =~ m/db/) {
$sql = qq!GRANT ALL PRIVILEGES on `$mysqldb`.* TO 'dbuser'\@'%'!;
$sth = $dbh->prepare($sql);
print "$sql\n";
$sth->execute();
}
if ($_ =~ m/another_db/) {
$sql = qq!GRANT ALL PRIVILEGES on `$mysqldb`.* TO 'another_db'\@'%'!;
$sth = $dbh->prepare($sql);
print "$sql\n";
$sth->execute();
}
}
}


~1:45am: The script finally finished with the last DB around 1:45am. Not too bad!

Now, as you can see, we have a fairly simple setup. We only wanted to move over certain DBs and only needed a few db users to grant privileges to. With minor modifications to this script, you can have it fit your needs.

*NOTE: A lot of the prep work (i.e. adding mysql users) was done earlier, but can probably be done in one shot as well.

1400+ databases successfully moved to a new cluster, yay! Cheers!

Friday, April 3, 2009

WordPress Plugin: Change Directory Location of Smilies

We recently moved our WordPress smilies to our caching server (for obvious reasons). Well, we then needed to have WordPress use the new URI. We always want to leave core WordPress code intact unless absolutely necessary, so I wrote this quick plugin to search for the old/original URI and use the new one.

Plain. Simple.

Cheers!


function custom_smilies($text) {
$output = str_replace(get_settings('siteurl') . "/wp-includes/images/smilies/", "http://new.location.com/img/wp/", $text);
return $output;
}

add_filter('comment_text', 'custom_smilies', 30);


Note: This works for WordPress 2.0.1. I'll try and test with 2.7 and any other installations I have installed already later. :)