<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4123913300004912345</id><updated>2012-01-18T10:59:07.159-08:00</updated><category term='apache'/><category term='linux'/><category term='hack'/><category term='ext3'/><category term='centos'/><category term='mysql'/><category term='logs'/><category term='timemachine'/><category term='security'/><category term='one-liner'/><category term='perl'/><category term='syslog'/><category term='inventory'/><category term='monitoring'/><category term='lvm'/><category term='memory'/><category term='http'/><category term='osx'/><category term='sed'/><category term='nas'/><category term='rpm'/><category term='threading'/><category term='lvs'/><category term='redhat'/><category term='awk'/><category term='find'/><category term='lwp'/><category term='grep'/><category term='lamp'/><category term='forking'/><category term='network'/><category term='dmidecode'/><category term='replication'/><title type='text'>Greg's Tech Blog</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-5420618046050143249</id><published>2010-12-16T18:23:00.000-08:00</published><updated>2010-12-16T18:23:28.842-08:00</updated><title type='text'>PFunc</title><content type='html'>I've had a project over on google code for a while now called &lt;a href="http://code.google.com/p/pfunc/"&gt;PFunc&lt;/a&gt;.&amp;nbsp; It was inspired by &lt;a href="https://fedorahosted.org/func/"&gt;FUNC&lt;/a&gt; a project I used to use, but due to it's linear processing I figured I could improve by threading.&amp;nbsp; Func is written in python, and I'm far more comfortable in perl.&amp;nbsp; So I wrote Pfunc.&amp;nbsp; It's purpose, like Func's is to execute commands on arbitrary groups of servers immediately.&amp;nbsp; I figured Pfunc would be a threaded tied-me-over until the Func project progressed and added asynchronous processing of commands.&amp;nbsp; Instead the Func project has gone in a different direction, trying to be pluggable.&amp;nbsp; My tied-me-over has lasted much longer than I ever imagined.&amp;nbsp; I have yet to find something to replace it with.&lt;br /&gt;&lt;br /&gt;Pfunc's focus is narrow.&amp;nbsp; It's about running a command on arbitrary groups of servers instantly all at the same time from the command line and providing easily readable output.&amp;nbsp; Pfunc also logs the output and exit status of all commands run through it to a mysql database.&amp;nbsp; Pfunc will copy files, but it is not a configuration manager.&amp;nbsp; Pfunc should only be used on a closed private network or over an stunnel, because while it does verify commands&amp;nbsp; to execute and files via DSA signatures, it passes traffic in plain-text.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;Setup is simple, download the code on the central machine you want to control other machines from, and put a copy on all the machines you want to control.&amp;nbsp; Create a database and import the provided .sql file.&amp;nbsp; One daemon called dsacertd runs on your central server to provide certs to clients for signing commands and small files.&amp;nbsp; Configure it to point to your database server and start this up, then create some clients and groups using the phostadd.pl and pgroupadd.pl commands.&amp;nbsp; Now you can configure the client machines to connect to the same database server and dsacertd server, then start up the pfuncd daemon.&amp;nbsp; That's it, your done.&amp;nbsp; Now you can execute arbitrary commands on any group of servers you defined with the pfunc command on your central server.&amp;nbsp; Add the -o option and get nicely formatted output, or you only receive exit status for each machine in the group.&amp;nbsp; While pfunc does not suffer from the interpolation problems of Func, command-line interpolation is still an issue.&amp;nbsp; You've gotta escape what your shell requires escaping.&lt;br /&gt;&lt;br /&gt;Pfunc has become an integral part of my workplace and the application I support.&amp;nbsp; We use it for many things, including our RPM based release process, using it to execute synchronized yum update commands across groups of web servers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-5420618046050143249?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/5420618046050143249/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2010/12/pfunc.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/5420618046050143249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/5420618046050143249'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2010/12/pfunc.html' title='PFunc'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-7857200620280362555</id><published>2010-12-02T14:45:00.000-08:00</published><updated>2010-12-02T15:01:02.240-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='hack'/><title type='text'>Add AUTO_INCREMENT to MyISAM without Recreating the Table</title><content type='html'>Here's a Filthy hack. &lt;br /&gt;&lt;br /&gt;Using ALTER table to add AUTO_INCREMENT to a column in MySQL takes significantly longer than you might think.&amp;nbsp; It's because behind the scenes it has to recreate the whole table.&amp;nbsp; If you've been using sequence tables and now you'd like to do away with them, this may take much longer than you'd think.&amp;nbsp; I recently ran into this problem.&amp;nbsp; I had around 450 databases with tens of thousands of tables in each that I needed to convert.&amp;nbsp; I found this article on &lt;a href="http://www.mysqlperformanceblog.com/2007/10/29/hacking-to-make-alter-table-online-for-certain-changes/"&gt;mysql performance blog &lt;/a&gt;from a while back.&amp;nbsp; &lt;b&gt;This only works for MyISAM.&lt;/b&gt;&amp;nbsp; It suggests that at least at that time one could simply create a new table defined the way you wanted it ( in their example case removing AUTO_INCREMENT) and switch out the .frm files from your new table to the one you want to change.&amp;nbsp; They go on to specifically say it &lt;b&gt;doesn't work to add AUTO_INCREMENT&lt;/b&gt;.&amp;nbsp; While that might have been the case at the time, it's not true now.&amp;nbsp; &lt;b&gt;You can add AUTO_INCREMENT to a column this way,&lt;/b&gt; with the addition of switching out the .MYI file as well.&amp;nbsp; Here's the process:&lt;br /&gt;&lt;br /&gt;Do a 'SHOW CREATE TABLE `tablename`' on the table you'd like to add AUTO_INCREMENT.&amp;nbsp; Take the output and create a new table.&amp;nbsp; Alter the new &lt;b&gt;empty&lt;/b&gt; table adding AUTO_INCREMENT with&amp;nbsp; MAX+1 from the PRIMARY KEY of the original table as the AUTO_INCREMENT value.&amp;nbsp; Make sure your column type matches the existing type of the table you're converting.&amp;nbsp; (I.E. int(10) unsigned)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: blue;"&gt;&lt;span style="font-size: x-small;"&gt;ALTER TABLE `convert_table` MODIFY COLUMN `id` INT(10) UNSIGNED AUTO_INCREMENT, AUTO_INCREMENT = 1000;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now switch out the .frm and .MYI files in /var/lib/mysql/databasename/ from the new table to the old one.&amp;nbsp; Then it's likely a good idea to repair the table.&amp;nbsp; Flushing and Locking the tables is also likely a good idea.&lt;br /&gt;&lt;br /&gt;Here's the Perl code I wrote to do it to all of the tables I needed to do this for.&amp;nbsp; Backup first and use at your own extreme risk, it really is a filthy hack.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt; #!/usr/bin/perl&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;use strict; &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;use warnings;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;use DBI;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;use Carp;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;use File::Copy;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;use Getopt::Long;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $dbuser = q{root}; # Database user&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $dbpass = q{}; # Database password&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $db;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $safe = undef;       # Lock and Flush Tables&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $remove = undef;     # Drop the sequence tables&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $type = undef;       # Don't convert the table if the Primary key isn't an int(10) unsigned&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $ext = '_seq';       # Pattern appened to your sequence tables&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;GetOptions(&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        'database|d=s'  =&amp;gt; \$db,&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        'safe|s'        =&amp;gt; \$safe,&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        'remove|r'      =&amp;gt; \$remove,&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        'type|t'        =&amp;gt; \$type,&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        'extension|x=s' =&amp;gt; \$ext,&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;);&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;unless ( $db ) {&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        croak qq{ You must provide a database (-d/--database)\n };&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;}&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $dbh = DBI-&amp;gt;connect(&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        qq{dbi:mysql:host=localhost;database=$db},&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $dbuser,&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $dbpass,&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        { RaiseError =&amp;gt; 1 }&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;) or croak qq{Can't connect to the db, I haven't done anything yet, no cleanup needed.\n}.DBI-&amp;gt;errstr;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;# Get a list of all the sequence tables&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;my $sthm = $dbh-&amp;gt;prepare(q{&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        SELECT `TABLE_NAME` &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;          FROM `INFORMATION_SCHEMA`.`TABLE_CONSTRAINTS` &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;         WHERE `TABLE_SCHEMA` = ? &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;           AND `TABLE_NAME` LIKE ?&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;});&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;$sthm-&amp;gt;execute($db,qq{\%_$ext});&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;print "Commencing filthy hack\n";&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;$| = 1; # So we get output during the while&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;MAIN:&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;while ( my $row = $sthm-&amp;gt;fetchrow_hashref ) {&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Dump the $ext to get the table name&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $row-&amp;gt;{'TABLE_NAME'} =~ s/$ext$//;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        my $table = $row-&amp;gt;{'TABLE_NAME'};&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Make sure the table exists&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        my $sth = $dbh-&amp;gt;prepare(q{&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                SELECT `TABLE_NAME` &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                  FROM `INFORMATION_SCHEMA`.`TABLES` &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                 WHERE `TABLE_SCHEMA` = ? &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                   AND `TABLE_NAME` LIKE ?&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        });&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth-&amp;gt;execute($db,$table);&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        unless( $sth-&amp;gt;fetchall_arrayref-&amp;gt;[0]-&amp;gt;[0]) {&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                print qq{\nTable $table missing, mabye you should drop $table$ext\n};&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                next MAIN;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        }&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Get the table definition&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth = $dbh-&amp;gt;prepare(qq{SHOW CREATE TABLE $table});&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth-&amp;gt;execute;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        my ($primary,$create_statement,$type);&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        while ( my $create = $sth-&amp;gt;fetchrow_arrayref ) {&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                if ( $create-&amp;gt;[1] =~ /AUTO_INCREMENT/ ) {&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                        print "\nTable $table already has auto_increment, you might want to check this table out.\n";&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                        next MAIN;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                }&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                my $desc = $dbh-&amp;gt;selectall_hashref(qq{DESC $table}, q{Key});&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                unless ( $desc-&amp;gt;{'PRI'} ) {&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                        print qq{\nWTF? No primary col found for table $table, this is going to need manual intervention.\n};&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                        next MAIN;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                }   &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                # If type option set, don't convert if the type for the primary col isn't an int(10) unsigned   &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;if ( $type ) { &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;unless ( $desc-&amp;gt;{'PRI'}-&amp;gt;{'Type'} eq 'int(10) unsigned' ) { &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                        print qq{\nWTF? Your primary key isn't an 'int(10) unsigned' on table $table, it's a }. $desc-&amp;gt;{'PRI'}-&amp;gt;{'Type'} .qq{, I'm not touching it.\n};&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                        next MAIN;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                }&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;} &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                $type = $desc-&amp;gt;{'PRI'}-&amp;gt;{'Type'};    &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                # change the table name in the create statement to convert_table&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                $create-&amp;gt;[1] =~ s/CREATE TABLE `[^`]+`(.+)/CREATE TABLE `convert_table`$1/;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                # find the primary key&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                $primary = $desc-&amp;gt;{'PRI'}-&amp;gt;{'Field'};&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                $create_statement = $create-&amp;gt;[1];    &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        }   &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Get the max val from the table to use for AUTO_INCREMENT&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth = $dbh-&amp;gt;prepare(qq{SELECT MAX(`$primary`) FROM `$table`});&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth-&amp;gt;execute;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        my ($id) = @{ $sth-&amp;gt;fetchall_arrayref} ;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $id = $id-&amp;gt;[0] ? $id-&amp;gt;[0]+1 : 1;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Make sure we have an int cause the orginal DB might really be honked up       &lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        unless ( int($id) ) { &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                print "$id for table $table is jacked up. Manual intervention needed.\n";&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                next MAIN;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        }   &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Create the convert table&lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth = $dbh-&amp;gt;prepare($create_statement);&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth-&amp;gt;execute or croak qq{Can't create the convert_table, you might need to do some cleanup\n}.DBI-&amp;gt;errstr;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # For safty sake&lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        if ( $safe ) { &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                $dbh-&amp;gt;do(qq{FLUSH TABLES `$table`, `$table$ext`});&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                $dbh-&amp;gt;do(qq{LOCK TABLES `$table` WRITE, `$table$ext` WRITE, `convert_table` WRITE});&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        }   &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Alter the empty convert_table&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        my $alterquery = qq{ &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                ALTER TABLE `convert_table` &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;              MODIFY COLUMN `$primary` $type AUTO_INCREMENT,&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;             AUTO_INCREMENT = $id &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        };&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth = $dbh-&amp;gt;prepare($alterquery);&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth-&amp;gt;execute or croak qq{WTF? Can't alter the convert table, cleanup needed for sure, you've got locked tables\n}.DBI-&amp;gt;errstr;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Switch out the .frm and .MYI files from the convert table the table we're fixing&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        copy(qq{/var/lib/mysql/$db/convert_table.frm},qq{/var/lib/mysql/$db/$table.frm}) or croak "Very bad, cleanup needed, you have locked tables. Copy failed: $!";&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        copy(qq{/var/lib/mysql/$db/convert_table.MYI},qq{/var/lib/mysql/$db/$table.MYI}) or croak "Very bad, cleanup needed, you have locked tables. Copy failed: $!";&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Just in case, Cause this is a flithy hack&lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $dbh-&amp;gt;do(qq{REPAIR TABLE `$table`}) if $safe;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Shouldn't need to do with but it's a good non-invasive test of the table&lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $alterquery = qq{ALTER TABLE `$table` AUTO_INCREMENT = $id };&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        my $sth7 = $dbh-&amp;gt;prepare($alterquery);&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $sth7-&amp;gt;execute or croak qq{Hope you backed up, filthy hack failed.  Cleanup needed for sure, you have locked tables and possible corruption, try repair with USE_FRM\n}.DBI-&amp;gt;errstr;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        # Clean up&lt;/span&gt;&lt;/span&gt;&lt;span style="color: blue; font-size: xx-small;"&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        $dbh-&amp;gt;do(qq{DROP TABLE `convert_table`}) or croak qq{Clean up needed, you have locked tables\n}.DBI-&amp;gt;errstr;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        if ( $remove ) { &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                $dbh-&amp;gt;do(qq{DROP TABLE `$table$ext`}) or croak qq{Clean up needed, you have locked tables\n}.DBI-&amp;gt;errstr;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        }   &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        if ( $safe ) { &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;                $dbh-&amp;gt;do(q{UNLOCK TABLES}) or croak qq{Clean up needed, you have locked tables\n}.DBI-&amp;gt;errstr;&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        }   &lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;        print ".";&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;}&lt;/span&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;br style="font-family: Verdana,sans-serif;" /&gt;&lt;span style="font-family: Verdana,sans-serif;"&gt;print "\nFilthy hack complete! Hope I didn't just corrupt everything\n"                                                        &lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-7857200620280362555?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/7857200620280362555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2010/12/add-autoincrement-to-myisam-without.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/7857200620280362555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/7857200620280362555'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2010/12/add-autoincrement-to-myisam-without.html' title='Add AUTO_INCREMENT to MyISAM without Recreating the Table'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-6326694561258641485</id><published>2010-07-19T13:10:00.000-07:00</published><updated>2010-08-04T08:40:15.957-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='lvm'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Efficient Rule Based Scheduling</title><content type='html'>Recently at work we had a project to convert a number of myisam latin 1 databases to utf8.  The process we settled on was to lvm snapshot the databases before we started the conversions so that if something went wrong we could mount the snapshots and restore quickly.  The problem that arose from this was limited space for the snapshots.  We needed to break the conversions up so that we were never converting more data than the size of the snapshots we were creating.  I needed to come up with a schedule for doing the conversion, to maximize the number of conversions that could be undertaken at a time, while maintaining the rule of not allowing more data to change than the size of the snapshot.&lt;br /&gt;&lt;br /&gt;The answer was simple enough, collect the sizes of all the databases, sort them largest to smallest and then start scheduling each round by taking the largest database off the top of the list and start adding the smallest databases from the bottom of the list until we hit our max size limit.&lt;br /&gt;&lt;br /&gt;As per my usual, I solved this with perl.  Here is what it looked like;&lt;br /&gt;&lt;br /&gt;First lets get a list of the databases&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #3366ff; font-size: 85%;"&gt;my $dbh = DBI-&amp;gt;connect( $dsn, $user, $password, { RaiseError =&amp;gt; 1, AutoCommit =&amp;gt; 0 } );&lt;br /&gt;my $dbs = $dbh-&amp;gt;selectcol_arrayref(q{SHOW DATABASES});&lt;br /&gt;$dbh-&amp;gt;disconnect;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now lets get the sizes for each&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #3366ff; font-size: 85%;"&gt;&lt;br /&gt;my @dbsizes;&lt;br /&gt;foreach my $db ( @$dbs ) {&lt;br /&gt;next if grep /^$db$/, @skip;&lt;br /&gt;opendir my $fh, "$dbpath/$db" or die $!;&lt;br /&gt;my @files = readdir($fh);&lt;br /&gt;# Add up the file sizes for all files in the directory&lt;br /&gt;# there are no subdirectories or this would be to be recursive&lt;br /&gt;my $t;&lt;br /&gt;map { my @s = stat "$dbpath/$db/$_" or die $!; $t += $s[7]; } @files;&lt;br /&gt;push(@dbsizes, [$t,$db]) if defined($t);&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And now lets sort the list by database size&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #3366ff; font-size: 85%;"&gt;&lt;br /&gt;my @sites = sort { $a-&amp;gt;[0] &amp;lt;=&amp;gt; $b-&amp;gt;[0]; } @dbsizes;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Lets get to the actual scheduling.  Here I'm using a recursive function that will build a reference to  a hash keyed by round with an array of databases to convert.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #3333ff; font-size: 85%;"&gt;&lt;br /&gt;&lt;span style="font-size: 85%;"&gt;&lt;span style="color: #3366ff;"&gt;# Recursive function, builds a schedule for database conversion so that  no&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;# Round of conversions exceeds $max&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;sub build_schedule {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    my ($sites,$top,$round,$total,$schedule) = @_;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    $top = 1 unless defined($top);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    $round = 1 unless defined($round);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    $total = 0 unless defined($total);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    my $next_site =  $top ? shift @$sites : pop @$sites;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    $top = 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    return $schedule unless $next_site;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    my ($size, $site) = @$next_site;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    if (($total + $size) &amp;gt; $max_size_per_round || $#{$schedule-&amp;gt;{round}} &amp;gt; $max_sites_per_round) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        if ($schedule-&amp;gt;{$round}[0]) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;            unshift @$sites, $next_site;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        else {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;            push(@{$schedule-&amp;gt;{$round}}, $site);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        $total = 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        $top = 1;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        $round++;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    else {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        push(@{$schedule-&amp;gt;{$round}}, $site);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;        $total += $size;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;    build_schedule($sites,$top,$round,$total,$schedule);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #3366ff;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Finally we'll print the schedule&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #3366ff; font-size: 85%;"&gt;my $schedule = build_schedule(\@sites);&lt;br /&gt;# Print schedule&lt;br /&gt;foreach my $round ( sort { $b &amp;lt;=&amp;gt; $a } keys %$schedule ) {&lt;br /&gt;print "Round $round\n\t";&lt;br /&gt;print join("\n\t", @{$schedule-&amp;gt;{$round}} );&lt;br /&gt;print "\n";&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is the complete script&lt;br /&gt;&lt;span style="color: #3366ff; font-size: 78%;"&gt;&lt;br /&gt;#!/usr/bin/perl -w&lt;br /&gt;use DBI;&lt;br /&gt;use strict;&lt;br /&gt;my $dsn = q{dbi:mysql:mysql:localhost:3306};&lt;br /&gt;my $user = q{root};&lt;br /&gt;my $password = q{password};&lt;br /&gt;my $max_size_per_round = 4_000_000_000; # Max size for each round&lt;br /&gt;my $max_sites_per_round = 5; # Max number of sites for each round&lt;br /&gt;my $dbpath = q{/var/lib/mysql};&lt;br /&gt;my @skip = qw{ information_schema mysql };&lt;br /&gt;&lt;br /&gt;# Get a list of all databases on the server&lt;br /&gt;my $dbh = DBI-&amp;gt;connect( $dsn, $user, $password, { RaiseError =&amp;gt; 1, AutoCommit =&amp;gt; 0 } );&lt;br /&gt;my $dbs = $dbh-&amp;gt;selectcol_arrayref(q{SHOW DATABASES});&lt;br /&gt;$dbh-&amp;gt;disconnect;&lt;br /&gt;&lt;br /&gt;# Get the size on disk for each database;&lt;br /&gt;my @dbsizes;&lt;br /&gt;foreach my $db ( @$dbs ) {&lt;br /&gt;next if grep /^$db$/, @skip;&lt;br /&gt;opendir my $fh, "$dbpath/$db" or die $!;&lt;br /&gt;my @files = readdir($fh);&lt;br /&gt;# Add up the file sizes for all files in the directory&lt;br /&gt;# there are no subdirectories or this would be to be recursive&lt;br /&gt;my $t;&lt;br /&gt;map { my @s = stat "$dbpath/$db/$_" or die $!; $t += $s[7]; } @files;&lt;br /&gt;push(@dbsizes, [$t,$db]) if defined($t);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Sort dbs in order of largest to smallest&lt;br /&gt;my @sites = sort { $a-&amp;gt;[0] &amp;lt;=&amp;gt; $b-&amp;gt;[0]; } @dbsizes;&lt;br /&gt;my $schedule = build_schedule(\@sites);&lt;br /&gt;&lt;br /&gt;# Print schedule&lt;br /&gt;foreach my $round ( sort { $b &amp;lt;=&amp;gt; $a } keys %$schedule ) {&lt;br /&gt;print "Round $round\n\t";&lt;br /&gt;print join("\n\t", @{$schedule-&amp;gt;{$round}} );&lt;br /&gt;print "\n";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Recursive function, builds a schedule for database conversion so that no&lt;br /&gt;# Round of conversions exceeds $max&lt;br /&gt;sub build_schedule {&lt;br /&gt;my ($sites,$top,$round,$total,$schedule) = @_;&lt;br /&gt;$top = 1 unless defined($top);&lt;br /&gt;$round = 1 unless defined($round);&lt;br /&gt;$total = 0 unless defined($total);&lt;br /&gt;my $next_site =  $top ? shift @$sites : pop @$sites;&lt;br /&gt;$top = 0;&lt;br /&gt;return $schedule unless $next_site;&lt;br /&gt;my ($size, $site) = @$next_site;&lt;br /&gt;if (($total + $size) &amp;gt; $max_size_per_round || $#{$schedule-&amp;gt;{$round}} &amp;gt; $max_site_per_round ) {&lt;br /&gt;if ($schedule-&amp;gt;{$round}[0]) {&lt;br /&gt;unshift @$sites, $next_site;&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt;push(@{$schedule-&amp;gt;{$round}}, $site);&lt;br /&gt;}&lt;br /&gt;$total = 0;&lt;br /&gt;$top = 1;&lt;br /&gt;$round++;&lt;br /&gt;}&lt;br /&gt;else {&lt;br /&gt;push(@{$schedule-&amp;gt;{$round}}, $site);&lt;br /&gt;$total += $size;&lt;br /&gt;}&lt;br /&gt;build_schedule($sites,$top,$round,$total,$schedule);&lt;br /&gt;}&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-6326694561258641485?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/6326694561258641485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2010/07/efficient-rule-based-scheduling.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/6326694561258641485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/6326694561258641485'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2010/07/efficient-rule-based-scheduling.html' title='Efficient Rule Based Scheduling'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-7269818840939689417</id><published>2010-07-15T15:23:00.000-07:00</published><updated>2010-07-19T19:36:32.192-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='grep'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Process an SQL Dump one Statement at a Time ( Grep for Text Over Multiple Lines)</title><content type='html'>Recently I was asked how to loop through a MySQL dump file one statement at a time, given that the statements in a dump file are broken up over multiple lines.  There are any number of ways of doing this, but since I love Perl, that's usually my first stop.&lt;br /&gt;&lt;br /&gt;The answer in Perl is simple.  Change the end of line ( $/ ) and slurp the file into an array.  So for a MySQL dump, the actual record separator is a semi-colon and a \n.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;open( my $fh, "&lt;", "Dump.sql") or die;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;my @file;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;{&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;local $/ = ";\n";&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;my @file = &lt;$fh&gt;;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now unless ';\n' somehow ended up in the middle of an SQL statement, you have an array of SQL statements, one statement per element.&lt;br /&gt;&lt;br /&gt;There is one problem with this method.  It uses a lot of memory.  As least as much as the size of your file.  If you're dealing with large files, you'll want to process the file a line at a time instead.  Tie::File comes in handy here.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 102, 255);font-size:85%;" &gt;use Tie::File;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 255);font-size:85%;" &gt;my @file;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 255);font-size:85%;" &gt;{&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 255);font-size:85%;" &gt;local $/ = ";\n";&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 255);font-size:85%;" &gt;tie @file, 'Tie::File', "Dump.sql" or die;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 255);font-size:85%;" &gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now you can use this @file array to loop through the file, one SQL statement at a time, without having more than one SQL statement in memory at a time.  Now say you wanted to find a pattern and evaluate one statement at a time.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 102, 255);font-family:courier new;font-size:85%;"  &gt;my (@matches ) = grep /($pattern)/, @file;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 102, 255);font-family:courier new;font-size:85%;"  &gt;print "Found $#matches matches\n";&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-7269818840939689417?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/7269818840939689417/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2010/07/process-sql-dump-one-statement-at-time.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/7269818840939689417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/7269818840939689417'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2010/07/process-sql-dump-one-statement-at-time.html' title='Process an SQL Dump one Statement at a Time ( Grep for Text Over Multiple Lines)'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-6452863293278632993</id><published>2010-02-05T11:12:00.000-08:00</published><updated>2010-02-05T11:16:07.954-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='one-liner'/><category scheme='http://www.blogger.com/atom/ns#' term='awk'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><title type='text'>MySQL key_cache for MyISAM</title><content type='html'>Knowing the total size of all your indexes is helpful when setting your key_cache size.  This one-liner gives you that number in bytes.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255); font-family: courier new;"&gt;find /var/lib/mysql/ -name "*.MYI" -printf "%s\n" | awk '{ s += $1};  END { print s }'&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-6452863293278632993?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/6452863293278632993/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2010/02/mysql-keycache-for-myisam.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/6452863293278632993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/6452863293278632993'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2010/02/mysql-keycache-for-myisam.html' title='MySQL key_cache for MyISAM'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-7311923892108244427</id><published>2009-07-09T14:56:00.000-07:00</published><updated>2010-02-18T12:37:54.652-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rpm'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Compare Two Lists of Unique Items in Perl ( The Gregorian Join )</title><content type='html'>Let's say you wanted to compare two lists of unique items and see what's in list A and not B, what's in B and not A, and what's in both.  Say for example you had a list of all the rpms installed on two different machines ( the output of the command rpm -qa).  Well, I can't say if this is the best way or not, but this works, and I think it looks pretty cool.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;my (%comp,@a_only,@b_only,@both,$pushref);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;map $comp{$_} = 2, @a;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;map $comp{$_}++, @b;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;map { &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        $pushref = $comp{$_} == 3 ?     \@both &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                 : $comp{$_} == 2 ?     \@a_only &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                 :                      \@b_only;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        push(@$pushref,$_);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;} keys %comp;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-7311923892108244427?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/7311923892108244427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/07/compare-two-lists-of-unique-items.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/7311923892108244427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/7311923892108244427'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/07/compare-two-lists-of-unique-items.html' title='Compare Two Lists of Unique Items in Perl ( The Gregorian Join )'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-8140655944970026368</id><published>2009-07-02T23:43:00.000-07:00</published><updated>2009-07-07T14:13:47.931-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='http'/><category scheme='http://www.blogger.com/atom/ns#' term='lwp'/><category scheme='http://www.blogger.com/atom/ns#' term='monitoring'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>LWP: Test Posting Form Data</title><content type='html'>LWP::UserAgent is perl's web browser.  If you need to GET,POST or PUT, LWP is your friend.  It's very simple to use and very powerful.  My script example today will use LWP::Parallel::UserAgent to POST form data ( in my case, login to ) a bunch of sites in parallel.  Then it will grep the response data from each site looking for data we expect to see in the repsonse frmo the POST ( after we log in ).&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;#!/usr/bin/perl &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;############################################################&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# http://greg-techblog.blogspot.com&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Post data to a bunch of sites in parallel and test the responses for a string&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;############################################################&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;use strict;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;use warnings;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;use Getopt::Long;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;use LWP::Parallel::UserAgent;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;use HTTP::Request::Common;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;use HTTP::Cookies;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# --debug or -d as arg will turn on debugging&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;my $debug;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;GetOptions( 'debug|d' =&gt; \$debug );&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Regex to check for in response content from post&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;my $regex = q{logout};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# List of sites we want to Connect to&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;my @sites = ( www.siteOne.com, www.siteTwo.com, www.siteThree.com );&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Define your form fields and values for Post requests&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;my %form = (&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            'login_username'                 =&gt; 'admin',&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            'login_password'                 =&gt; 'password',&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            'hidden_form_field1'             =&gt; '1',&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Url encode form&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;my $form_encoded = join '&amp;amp;', map { "$_=$form{$_}"; } keys %form;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Replace spaces for url encoding&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;$form_encoded =~ s/\s/%20/g;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Header object for request&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;my $header = HTTP::Headers-&gt;new('Content-Type' =&gt; 'application/x-www-form-urlencoded');&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Create request objects for each site&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;my $reqs = [];&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;map { &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    my $req = HTTP::Request-&gt;new( 'POST', qq{$_/},$header, $form_encoded);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    push(@$reqs,$req);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;} @sites;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Execute request&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;my %stdout = parallel_reqs($reqs,$regex);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;map { print "Failed to login to $_\n" unless $stdout{$_}; } keys %stdout;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;######################################################&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Post form data to a bunch of sites and grep the&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# response data for a string&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Pass:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#  ref array of HTTP::Request objects&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#  regex to check response for&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Return:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;#  A hash keyed by urls with boolean success/fail values  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;######################################################&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;sub parallel_reqs {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    my ($reqs,$regex) = @_;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    my $pua = LWP::Parallel::UserAgent-&gt;new();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    # $pua-&gt;in_order  (1);  # handle requests in order of registration&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    $pua-&gt;duplicates(1);  # do not ignore duplicates&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    $pua-&gt;timeout   (60); # in seconds&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    $pua-&gt;redirect  (1);  # follow redirects&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    $pua-&gt;nonblock  (0);  # disable nonblocking&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    $pua-&gt;max_hosts (8);  # number of hosts to connect to at once&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    $pua-&gt;max_req   (20); # number of request per host&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;    # Allow POSTS to be redirected &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    push @{ $pua-&gt;requests_redirectable }, 'POST';&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    # Enable Cookies               &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    my $cookie = HTTP::Cookies-&gt;new({});    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    $pua-&gt;cookie_jar($cookie);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    # Start our requests&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    foreach my $req (@$reqs) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        if ( my $res = $pua-&gt;register($req) ) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            print STDERR $res-&gt;error_as_HTML if $debug;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    my $entries = $pua-&gt;wait(10);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    # Loop through the response content looking for our regex&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    my %return;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    foreach (keys %$entries) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        my $response = $entries-&gt;{$_}-&gt;response;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    print $response-&gt;request-&gt;url."\t\t".$response-&gt;message."\t".$response-&gt;code."\n" if $debug;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        $return{$response-&gt;request-&gt;url} = $response-&gt;content =~ /$regex/ ? 1 : 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    return %return;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-8140655944970026368?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/8140655944970026368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/07/lwp-test-posting-form-data.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/8140655944970026368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/8140655944970026368'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/07/lwp-test-posting-form-data.html' title='LWP: Test Posting Form Data'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-2532518500296616843</id><published>2009-06-25T11:56:00.000-07:00</published><updated>2009-06-25T12:02:00.764-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='one-liner'/><category scheme='http://www.blogger.com/atom/ns#' term='network'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Perl One-Liner Multithreaded Ping Scanner</title><content type='html'>&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;&lt;span style="color: rgb(0, 0, 0);font-family:times new roman;font-size:130%;"  &gt;Just another one-liner today.  This launches a thread for each address you want to scan in the range you provide.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;perl -e 'use threads; ($n,@r) = @ARGV; map { $t{$_} = new threads sub { $i = shift; print "$_ up\n" if `ping -c 1 $n$i` =~ /1 received/; }, $_;} $r[0]..$r[1]; map $t{$_}-&gt;join, keys %t;' 192.168.50. 1 254&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-2532518500296616843?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/2532518500296616843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/perl-one-liner-multithreaded-ping.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/2532518500296616843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/2532518500296616843'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/perl-one-liner-multithreaded-ping.html' title='Perl One-Liner Multithreaded Ping Scanner'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-8439080394295773659</id><published>2009-06-18T13:12:00.000-07:00</published><updated>2009-06-18T13:40:24.755-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='one-liner'/><category scheme='http://www.blogger.com/atom/ns#' term='logs'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Get a List of IPs that have Been Refused</title><content type='html'>Just a one-liner today.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new; color: rgb(0, 0, 153);"&gt;grep refused /var/log/secure | perl -ne '@l = $_; map { /from ::ffff:((?:\d{1,3}\.){3}\d{1,3}\b)/; $h{$1}++; } @l; END {map { print "$_ = $h{$_}\n" if $h{$_} &gt; 10;} keys %h; }'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This will print a list of all IPs that have received a 'refused connection' message more than 10 times and print how many times each has been refused.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-8439080394295773659?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/8439080394295773659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/get-list-of-ips-that-have-been-refused.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/8439080394295773659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/8439080394295773659'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/get-list-of-ips-that-have-been-refused.html' title='Get a List of IPs that have Been Refused'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-1042561191374372176</id><published>2009-06-16T15:06:00.000-07:00</published><updated>2009-07-06T16:05:32.750-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='forking'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='threading'/><title type='text'>Forking in Perl</title><content type='html'>Yesterday I posted how to &lt;a href="http://greg-techblog.blogspot.com/2009/06/threading-in-perl.html"&gt;thread&lt;/a&gt; in perl.  Today I figured I'd explain forking.  There are a few reasons you might choose to fork instead of thread.  One of them is that threading is a compile time option for perl that isn't enabled in every installation.  Another is that not every module is thread safe.  Most of the time you can just unload any modules that are not before you start threading, but if you need the module inside your thread, you'll need to switch to forking.  Lastly forking is more effecient than threading in some cases.  I'll actually explain this more in detail in a later post.&lt;br /&gt;&lt;br /&gt;Here I've written a sample script that is similar to my threading function.&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;######################################&lt;br /&gt;# http://greg-techblog.blogspot.com&lt;br /&gt;# Fork child processes for a list of hosts running a function&lt;br /&gt;# you pass to it. Passes host to function as argument.&lt;br /&gt;# args:&lt;br /&gt;# needs numbers of child to fork at a time&lt;br /&gt;# ref to sub to run&lt;br /&gt;# ref array of hosts or instances (will be passed to sub as arg)&lt;br /&gt;# returns:&lt;br /&gt;# a hash of returns from sub keyed by host or instance name&lt;br /&gt;######################################&lt;br /&gt;use strict;&lt;br /&gt;use warnings;&lt;br /&gt;my $debug;&lt;br /&gt;&lt;br /&gt;sub fork_run {&lt;br /&gt;    use POSIX qw( WNOHANG );&lt;br /&gt;    my ($children,$func_to_fork, $hosts) = @_;&lt;br /&gt;    my %stdout;&lt;br /&gt;    my $n = 0;&lt;br /&gt;&lt;br /&gt;    # This makes sure we don't start more than $threads threads at a time&lt;br /&gt;    my $m = $children-1 &gt; $#{$hosts} ? $#{$hosts} : $children-1;&lt;br /&gt;&lt;br /&gt;    while (1) {&lt;br /&gt;        last if $n &gt;= $#{$hosts}+1;&lt;br /&gt;        foreach my $host (@{$hosts}[$n..$m]) {&lt;br /&gt;            print "Forking for $host $n-$m\n" if $debug;&lt;br /&gt;            local *FROM_CHILD;&lt;br /&gt;            pipe(FROM_CHILD,TO_PARENT);&lt;br /&gt;            my $pid = fork();&lt;br /&gt;            if ( not defined $pid) {&lt;br /&gt;            # Something is wrong&lt;br /&gt;                print "resources not available.\n";&lt;br /&gt;            }&lt;br /&gt;            elsif ($pid == 0 ) {&lt;br /&gt;                # This is the child&lt;br /&gt;                # Turn on autoflush&lt;br /&gt;                $| = 1;&lt;br /&gt;                close(FROM_CHILD);&lt;br /&gt;                select(TO_PARENT);&lt;br /&gt;                $func_to_fork-&gt;($host);&lt;br /&gt;                close(TO_PARENT);&lt;br /&gt;                exit;&lt;br /&gt;            }&lt;br /&gt;            else {&lt;br /&gt;                # This is the parent&lt;br /&gt;                close(TO_PARENT);&lt;br /&gt;                $stdout{$host} = &lt;from_child&gt;;&lt;br /&gt;                close FROM_CHILD;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        # wait for some children to finish&lt;br /&gt;        my $kid;&lt;br /&gt;        do {&lt;br /&gt;            $kid = waitpid(-1, WNOHANG);&lt;br /&gt;        } while $kid &gt; 0;&lt;br /&gt;&lt;br /&gt;        # work out the next range of instances to work on&lt;br /&gt;        $n = $m == 0 ? 1 : $m+1;&lt;br /&gt;        $m = $n+$children-1 &lt; $#{$hosts} ? $n+$children-1 : $#{$hosts};&lt;br /&gt;        print "$n-$m\n\n" if $debug;&lt;br /&gt;        }&lt;br /&gt;    return %stdout;&lt;br /&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To use this, simply do something like this;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="font-size:85%;"&gt;use Data::Dumper;&lt;br /&gt;my @hosts = qw{ host1 host2 host3 host4 host5 };&lt;br /&gt;sub myFunc { my $hostname = shift; print TO_PARENT `ping -c 1 $hostname` ; return 1; }&lt;br /&gt;&lt;br /&gt;# Launch two threads at a time that ping hosts&lt;br /&gt;my %stdout = fork_run( 2, \&amp;amp;myFunc, \@hosts);&lt;br /&gt;map { print $stdout{$_}; } keys %stdout;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-1042561191374372176?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/1042561191374372176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/forking-in-perl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/1042561191374372176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/1042561191374372176'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/forking-in-perl.html' title='Forking in Perl'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-866998189534140724</id><published>2009-06-15T14:29:00.000-07:00</published><updated>2009-07-06T15:38:25.652-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='threading'/><title type='text'>Threading in Perl</title><content type='html'>&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Threading in Perl may seem daunting at first, but it's actually easier than it looks.  In some ways, threading is more straight forward than forking.  Communication between the threads and a parent process is much more straight forward in my opinion than communication between child and parent processes.&lt;br /&gt;&lt;br /&gt;Here I've written a little sample function that will take a number of threads to launch at a time, a reference to a function and an array of hostnames.  Then it will launch one thread for each hostname passing the hostname to the function, until the limit has been reached.  It then waits for each thread to become joinable (finishes) and then launches more threads till the limit is reached again.  When all threads are finished, it returns the output form all threads as a hash keyed by the hostnames.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;######################################&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;# http://greg-techblog.blogspot.com&lt;br /&gt;# Spawns threads for a list of hosts running a function&lt;br /&gt;# you pass to it.&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;  Passes host to function as argument. &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;# args:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;#   needs numbers of threads to launch at a time&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;#   ref to sub to run&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;#   ref array of hosts or instances (will be passed to sub as arg)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;# returns:&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;#   a hash of returns from sub keyed by host or instance name &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;######################################&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;use threads;&lt;br /&gt;my $debug;&lt;br /&gt;sub run_threaded {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    my ($threads,$func_to_thread, $hosts) = @_; &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    my (%stdout, %threads);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    my $n = 0;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;&lt;br /&gt;# This makes sure we don't start more than $threads threads at a time&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    my $m = $threads-1 &gt; $#{$hosts} ? $#{$hosts} : $threads-1;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    while (1) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;        last if $n &gt;= $#{$hosts}+1;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;        foreach my $host (@{$hosts}[$n..$m]) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;            print "Launching thread for $host $n-$m\n" if $debug;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;            unless ( $threads{$host} = new threads $func_to_thread, $host) {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;                print "Error on $host\n";&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;            }   &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;        }   &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;        map { $stdout{$_} = $threads{$_}-&gt;join if $threads{$_}; } @{$hosts}[$n..$m];&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;        # work out the next range of instances to work on&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;        $n = $m == 0 ? 1 : $m+1;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;        $m = $n+$threads-1 &lt; $#{$hosts} ? $n+$threads-1 : $#{$hosts};&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;        print "$n-$m\n\n" if $debug;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    }   &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    return %stdout;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To use this, simply do something like this;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;font-size:85%;"  &gt;use Data::Dumper;&lt;br /&gt;my @hosts = qw{ host1 host2 host3 host4 };&lt;br /&gt;sub myFunc { my $hostname = shift;  return `ping $hostname` ; }&lt;br /&gt;&lt;br /&gt;# Launch two threads at a time that ping hosts&lt;br /&gt;my %stdout = run_threaded( 2, \&amp;amp;myFunc, \@hosts);&lt;br /&gt;print Dumper \%stdout;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-866998189534140724?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/866998189534140724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/threading-in-perl.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/866998189534140724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/866998189534140724'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/threading-in-perl.html' title='Threading in Perl'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-8009836872918402909</id><published>2009-06-15T11:32:00.000-07:00</published><updated>2009-06-15T12:01:34.424-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='awk'/><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='sed'/><title type='text'>Kill a Ton of Queries in MySQL</title><content type='html'>Every so often I'll have a misbehaving query that read locks a table that is essential for every other query in our application.  Obviously this is a bug in our application that should have never made it past the Q/A process, but lets get back to the real world where programmers make these mistakes and Q/A isn't perfect.  When this happens, a ton of queries backup behind the query that read locked the table.  At this point, simply killing the primary query isn't going to fix the problem, because the load generated by all the queries waiting for the read lock to end will kill the server.  There is only two solutions at this point, restart MySQL or kill all the stuck queries.  Killing all the queries is really the best solution for our application, but the number is typically daunting.  Most of the time I've got as many queries as whatever my connection limit is set to.  So I came up with this little one-liner to get a list of all the processes for a user on the server, and kill them.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;mysql -u username -ppassword -e "show processlist" | sed '1d' |  grep mysql_username | awk '{print "kill ", $1, ";"}' | xargs -i  mysql -u username -ppassword -e "{}"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm sure someone has a better way to do this, but this works pretty awesomely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-8009836872918402909?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/8009836872918402909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/kill-ton-of-queries-in-mysql.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/8009836872918402909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/8009836872918402909'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/kill-ton-of-queries-in-mysql.html' title='Kill a Ton of Queries in MySQL'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-5587354215325632018</id><published>2009-06-15T10:03:00.000-07:00</published><updated>2009-06-15T10:30:56.384-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='one-liner'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='dmidecode'/><category scheme='http://www.blogger.com/atom/ns#' term='inventory'/><title type='text'>Inventory Your Machines with a One-liner</title><content type='html'>The command &lt;span style="font-family: courier new;"&gt;dmidecode&lt;/span&gt; dumps the DMI table from your machines BIOS in human readable text.  Depending on your machine, this should contain some really useful info.  Basically a total hardware profile on most machines, including info like service tags and model numbers.  I recently needed to quickly inventory a bunch of Dell servers and came up with this one-liner that will production a CSV line of text for the machine it's run on.  Combine these lines of text into one file and import into Excel, inventory done.&lt;br /&gt;&lt;br /&gt;Format is:&lt;br /&gt;'Hostname','Distro-Release Version','UUID','Service Tag','Model','Processor Version','Memory'  &lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;echo `hostname` , `cat /etc/*-release` , `dmidecode |egrep UUID |sed "s/\s\+UUID: //"` , `dmidecode -s system-serial-number` , `dmidecode -s system-product-name` , `dmidecode -s processor-version` , `dmesg |egrep Mem |awk '{ print $2; }'` &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now of course you'll need to modify this command for your own hardware, this won't even work for every Dell.  But, the output of dmidecode is readable enough to just scan through it and figure out what you need.  Also look in &lt;span style="font-family: courier new;"&gt;/proc/&lt;/span&gt; for other info you might want to add to your inventory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-5587354215325632018?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/5587354215325632018/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/inventory-your-machines-with-one-liner.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/5587354215325632018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/5587354215325632018'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/inventory-your-machines-with-one-liner.html' title='Inventory Your Machines with a One-liner'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-4425637753805282902</id><published>2009-06-08T09:35:00.000-07:00</published><updated>2009-06-24T15:05:54.563-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='awk'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='lvs'/><title type='text'>Add Up a Column of Data with Awk</title><content type='html'>&lt;span style="font-family:times new roman;"&gt;When you pipe a line of text to awk, every "word" (string of non-white space) shows up in $n, where n is equal to the order for which it appears in the line of text.  For example;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&gt;echo this is a test | awk '{print $2};'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;prints&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;is&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;If you have a column of numbers, say from the output of a command or a log file, you can do math with these numbers like this&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ps aux | awk '{ t =+ $6}; END { print t};'&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;This will give you the total for the sixth column of the output from the command ps aux.  In another example, lets say I wanted to see the total number of clients with active and inactive connections on my LVS server.  The command to see this info is&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;[root@lvs~]#ipvsadm -L&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;IP Virtual Server version 1.2.1 (size=4096)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Prot LocalAddress:Port Scheduler Flags&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; RemoteAddress:Port           Forward Weight ActiveConn InActConn&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;TCP  www:https sed&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp06:https               Route   110    54         86        &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp01:https               Route   70     36         46        &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp04:https               Route   300    148        207       &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp03:https               Route   300    146        307       &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp02:https               Route   120    58         77        &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;  -&gt; webapp05:https               Route   300    142        183  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:times new roman;"&gt;That's nice, but you'll notice I don't get totals.  The command doesn't have any syntax to give me totals either.  So we'll let awk take care of it.  First we need to grep just the lines that we want to add up.  In this case they all have the text '&lt;/span&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;webapp0&lt;/span&gt;&lt;span style="font-family:times new roman;"&gt;' in them, and that string of text doesn't appear on any lines we don't want to add up.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;[root@lvs~]#ipvsadm -L |grep webapp0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp06:https               Route   110    72         80        &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp01:https               Route   70     45         53        &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp04:https               Route   300    198        267       &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp03:https               Route   300    196        268       &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp02:https               Route   120    79         105       &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  -&gt; webapp05:https               Route   300    199        240      &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;Now the two columns we'd like to add up are the 5th and the 6th.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;[root@lvs~]#ipvsadm -L |grep webapp0|awk '{s += $5; i += $6} END { print s,i; };'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;846 1066&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:times new roman;"&gt;Now lets say instead of wanting a total, we wanted an average?  'NR' is equal to the number of rows we sent awk.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;[root@lvs~]#ipvsadm -L |grep webapp0|awk '{s += $5; i += $6} END { print s/NR,i/NR; };'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;68.5833 88.4167&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;   &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-4425637753805282902?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/4425637753805282902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/add-up-column-of-data-with-awk.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/4425637753805282902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/4425637753805282902'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/add-up-column-of-data-with-awk.html' title='Add Up a Column of Data with Awk'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-7912841808620425284</id><published>2009-06-04T15:44:00.000-07:00</published><updated>2009-06-24T15:05:32.781-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='lamp'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><title type='text'>MaxClients in Apache with Preforking MPM</title><content type='html'>The advice for figuring out what your MaxClients setting should be in Apache with the Preforking MPM is pretty straight forward.  First figure out the average amount of RAM each Apache process uses. Then divide the amount of RAM your system has, minus a little for other processes, by the average amount of RAM the average Apache process uses.  In CentOS the following command should give you that number.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;ps -ylC httpd |awk "{ s += \$8 } END { m = `cat /proc/meminfo|grep MemTotal|awk '{print $2}'`; printf \"MaxClients: %i\\n\", (m-(m*.15))/(s/NR) }"&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-7912841808620425284?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/7912841808620425284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/maxclients-in-apache-with-preforking.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/7912841808620425284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/7912841808620425284'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/06/maxclients-in-apache-with-preforking.html' title='MaxClients in Apache with Preforking MPM'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-4894922472705533485</id><published>2009-05-27T20:33:00.000-07:00</published><updated>2009-05-27T22:31:57.839-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='rpm'/><category scheme='http://www.blogger.com/atom/ns#' term='lamp'/><category scheme='http://www.blogger.com/atom/ns#' term='centos'/><title type='text'>Working with RPMs on CentOS</title><content type='html'>I'm pretty much going to just start spitting all my favorite rpm commands here.  Assuming CentOS, but most of this is applicable to any rpm based distro.&lt;br /&gt;&lt;br /&gt;List every rpm installed on your system, pipe it through grep to find something specific&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;rpm -qa&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;Info about a specific rpm, version number, build host an other useful info&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:78%;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-style: italic;"&gt;[root@webapp01 ~]# rpm -qi php&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Name        : php                          Relocations: (not relocatable)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Version     : 5.2.2                             Vendor: (none)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Release     : 3                             Build Date: Thu 13 Mar 2008 04:31:00 PM PDT&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Install Date: Fri 14 Mar 2008 11:02:12 AM PDT      Build Host: dev.myhost.com&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Group       : Development/Languages         Source RPM: php-5.2.2-3.src.rpm&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Size        : 12049373                         License: The PHP License v3.01&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Signature   : (none)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;URL         : http://www.php.net/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Summary     : The PHP HTML-embedded scripting language. (PHP: Hypertext Preprocessor)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Description :&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;PHP is an HTML-embedded scripting language. PHP attempts to make it&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;easy for developers to write dynamically generated webpages. PHP also&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;offers built-in database integration for several commercial and&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;non-commercial database management systems, so writing a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;database-enabled webpage with PHP is fairly simple. The most common&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;use of PHP coding is probably as a replacement for CGI scripts.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;The php package contains the module which adds support for the PHP&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What rpm a specific file is from&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;rpm -qf /path/filename&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;List everything installed by an rpm&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;rpm -ql packagename&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Turn any perl CPAN module into an rpm and install it&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;cpan2rpm -i Getopts::Long&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After you've installed a src rpm, change into &lt;span style="font-family:courier new;"&gt;/usr/src/redhat/SPECS/&lt;/span&gt; and execute this using your package's specfile and it builds an rpm and installs it.  If you don't have a src rpm, but you've got a specfile for a source tarball, put the specfile in /usr/src/redhat/SPECS/ and the tarball in /usr/src/redhat/SOURCES .&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;rpmbuild -bi packname.spec&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Creates an rpm repo in your current directory from the rpms in that directory&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;createrepo .&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Searches all your rpm repos for a specific file&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;yum provides '*/rpmbuild'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;List/Install/Remove package groups.  Package groups are groups of rpms that are generally needed together, IE 'Development Libraries' or 'KDE (K Desktop Environment)'&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;yum grouplist / yum groupinstall / yum groupremove&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-4894922472705533485?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/4894922472705533485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/working-with-rpms-on-centos.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/4894922472705533485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/4894922472705533485'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/working-with-rpms-on-centos.html' title='Working with RPMs on CentOS'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-6677119618465560334</id><published>2009-05-27T09:19:00.000-07:00</published><updated>2009-05-27T22:32:12.120-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='find'/><title type='text'>Fun with Find</title><content type='html'>Recently I needed to clean up a bunch of temp files being create by a web application but, not being properly removed.  I turned to &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; as a stop gap solution to this problem while the real problem was being solved.  In my situation I knew that no file should survive longer than two hours in the directory where the files were being created.  So using &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; I check the ctime on the files and remove them if it is more than 120 minutes old.  Using &lt;span style="font-style: italic;"&gt;find&lt;/span&gt;'s &lt;span style="font-style: italic;"&gt;-cmin&lt;/span&gt;  option with &lt;span style="font-style: italic;"&gt;+120&lt;/span&gt; will give us files that &lt;span style="font-weight: bold;"&gt;have not&lt;/span&gt; been changed in the last 120 minutes, a negative number (&lt;span style="font-style: italic;"&gt;-120&lt;/span&gt;) would give us files only files that &lt;span style="font-weight: bold;"&gt;have&lt;/span&gt; been changed in the last 120 minutes.  Since I only want to delete files, and keep directories I also use the &lt;span style="font-style: italic;"&gt;-type f  &lt;/span&gt;option.  If I simply run&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;shell&gt; find /path/to/files -cmin +120 -type f&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This will give me a list of all files that have not been changed in the last 120 minutes below the path I've given &lt;span style="font-style: italic;"&gt;find&lt;/span&gt;.  If I wanted to make sure &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; didn't list files in subdirectories I would add the option -maxdepth 1.&lt;br /&gt;&lt;br /&gt;So now we have a list of the files we want to delete, using the &lt;span style="font-style: italic;"&gt;-exec&lt;/span&gt; option will allow us to delete them.  This is pretty much the same as piping the out put of &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; to &lt;span style="font-style: italic;"&gt;xargs&lt;/span&gt; but it should use a little less overhead.  With the&lt;span style="font-style: italic;"&gt; -exec&lt;/span&gt; option foreach thing we've found with &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; the command we supply is executed.  Find 25 items with &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; and your command is executed 25 times.  Since we want the files we've found to be part of the command, we use '&lt;span style="font-style: italic;"&gt;{}&lt;/span&gt;' as a variable.  We also need to let &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; know when the command we are supplying is finished.  You use a '&lt;span style="font-style: italic;"&gt;;&lt;/span&gt;' for that, but since '&lt;span style="font-style: italic;"&gt;;&lt;/span&gt;' has it's own meaning in bash, it needs to be escaped.  So our option to remove all the files we've found without confirmation should looks like&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;-exec rm -f '{}' \;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If we used '&lt;span style="font-style: italic;"&gt;+&lt;/span&gt;' instead of  '&lt;span style="font-style: italic;"&gt;;&lt;/span&gt;' &lt;span style="font-style: italic;"&gt;find&lt;/span&gt; would try to string many of our files together and cause the command to be executed fewer times.  This could be more efficient depending on the command we are running.&lt;br /&gt;&lt;br /&gt;Now I needed to run this command every hour, so I created a little bash script to start this process up.  I  set it's nice level high so it's priority would be low, and setup a little checking to make sure we don't start this job up again if it hasn't finished from the last time it was started.&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;#!/bin/bash&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;# http://greg-techblog.blogspot.com&lt;br /&gt;TMPPATH=/var/www/html/tmp/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;# Check if cleantmp.cron is already running&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;if [ ! -f /var/run/cleantmp.pid ]; then&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;    # Delete all files in tmp that are older than two hours&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;    # run at lowest priority&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;    nice -n 19 find $TMPPATH -nowarn -cmin +120 -type f -exec rm -f '{}' \; &amp;amp;  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;    PID=$!                    # Get the pid of the find process&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;    echo "$PID" &gt; /var/run/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;cleantmp&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;pid&lt;/span&gt;     # create a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;pidfile&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;    wait $&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;PID&lt;/span&gt;                 # wait for find to finish&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;    rm -f /var/run/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;cleantmp&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;pid&lt;/span&gt;         # remove &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;pidfile&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;    exit&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;# &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;cleantmp&lt;/span&gt; is already running&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;echo &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;cleantmp&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;cron&lt;/span&gt; already running&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;cat /var/run/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;cleantmp&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;pid&lt;/span&gt;  # print &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;pid&lt;/span&gt; of find process&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-6677119618465560334?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/6677119618465560334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/fun-with-find.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/6677119618465560334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/6677119618465560334'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/fun-with-find.html' title='Fun with Find'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-3047785161969567320</id><published>2009-05-26T23:20:00.000-07:00</published><updated>2009-05-27T22:32:32.201-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='lamp'/><category scheme='http://www.blogger.com/atom/ns#' term='memory'/><category scheme='http://www.blogger.com/atom/ns#' term='apache'/><title type='text'>Dealing with Memory Usage in Apache</title><content type='html'>Whatever amount of memory an Apache process uses to full fill a request, that process will continue to hold onto that amount of memory for the lifetime of that process. When you graceful Apache you cause all your current processes to end as soon as they are finished serving the requests they have already received, and then Apache creates a new set of processes.  This typically frees up large blocks of memory used to serve old requests.  Apache does this on it's own and it's controlled by the &lt;span style="font-style: italic; color: rgb(255, 0, 0);"&gt;MaxRequestsPerChild&lt;/span&gt; directive.  This is the number of requests a process should serve during it's lifetime.  Making this number too low will cause Apache to tear down and create new processes quickly, increasing CPU overhead.  Setting &lt;span style="font-style: italic; color: rgb(255, 0, 0);"&gt;MaxRequestsPerChild&lt;/span&gt; too high will cause your machine to use more memory than it likely needs to, possibly causing your system to swap, or even run out of memory completely.  Apache has no other means of garbage collection.&lt;br /&gt;&lt;br /&gt;The default config for Apache on CentOS 5.3 has &lt;span style="font-style: italic; color: rgb(255, 0, 0);"&gt;MaxRequestsPerChild&lt;/span&gt; set at 4000.  I've seen people suggest that if your application is primarily serving dynamic content that a setting as low at 20 may make sense.  I've opt'ed for 800 to 1000.  It's a number I'm still playing with.  Setting it this low has reduced the overall amount of memory my systems are using without increasing my CPU load significantly.  It's something you'll need to experiement with.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-3047785161969567320?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/3047785161969567320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/dealing-with-memory-usage-in-apache.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/3047785161969567320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/3047785161969567320'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/dealing-with-memory-usage-in-apache.html' title='Dealing with Memory Usage in Apache'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-8157601737215509791</id><published>2009-05-22T16:45:00.000-07:00</published><updated>2009-05-27T22:32:50.117-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='redhat'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='syslog'/><category scheme='http://www.blogger.com/atom/ns#' term='centos'/><title type='text'>Centralize Syslogging Quick and Dirty</title><content type='html'>Lets start with that this shouldn't be done across a public network.  If you need to do that, you should do basically the same thing as all this, except through stunnel, but I'm not going to get into how to setup all that right now.  Basically what we are going to do is setup one machine to accept syslog messages from anywhere (remember, private network here, it would be a security risk to allow anyone to send you syslog messages).  Then we configure another machine to send it's syslog messages to the first machine.  Last, we'll setup cron jobs on both machines to make sure we'll still recieving messages from the remote server.&lt;br /&gt;&lt;br /&gt;I'm using CentOS/Redhat for this, so this setup will differ a little on different distros, but not much.&lt;br /&gt;&lt;br /&gt;Start with the machine we want to recieve syslog messages on.  We'll call this machine &lt;span style="font-style: italic;"&gt;foo&lt;/span&gt; and the machine we want to send messages from &lt;span style="font-style: italic;"&gt;bar&lt;/span&gt;.  Inventive... I know.&lt;br /&gt;&lt;br /&gt;On &lt;span style="font-style: italic;"&gt;foo&lt;/span&gt; we open up &lt;span style="font-style: italic;"&gt;/etc/sysconfig/syslog&lt;/span&gt; and add the -r option&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[root@foo ~]# vim /etc/sysconfig/syslog&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt; &lt;/span&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&lt;span style="font-size:85%;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;# Options to syslogd&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # -m 0 disables 'MARK' messages.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # -r enables logging from remote machines&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # -x disables DNS lookups on messages recieved with -r&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # See syslogd(8) for more details&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(255, 0, 0);"&gt;  SYSLOGD_OPTIONS="-m 0 -r"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # Options to klogd&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # -2 prints all kernel oops messages twice; once for klogd to decode, and&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  #    once for processing with 'ksymoops'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # -x disables all klogd processing of oops messages entirely&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # See klogd(8) for more details&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  KLOGD_OPTIONS="-x"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  #&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  SYSLOG_UMASK=077&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;  # set this to a umask value to use for all log files as in umask(1).&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;&lt;span style="font-size:85%;"&gt;  # By default, all permissions are removed for "group" and "other".&lt;/span&gt; &lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Now restart syslog with&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[root@foo ~]#&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; service syslog restart&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Shutting down kernel logger:                               [  OK  ]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Shutting down system logger:                               [  OK  ]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Starting system logger:                                    [  OK  ]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Starting kernel logger:                                    [  OK  ]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Next switch over to &lt;span style="font-style: italic;"&gt;bar&lt;/span&gt; and open up the syslogd.conf file&lt;span style="font-style: italic;"&gt;&lt;/span&gt;.  Use @foo as the destination and send over whatever messages you'd like.  For me, that's just going to be the stuff that normally ends up in &lt;span style="font-family:courier new;"&gt;/var/log/messages&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;/var/log/secure&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[root@bar ~]# vim /etc/syslog.conf&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 153);"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;font-size:85%;"  &gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:times new roman;"&gt;# Log all kernel messages to the console.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # Logging much else clutters up the screen.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; #kern.*                         /dev/console&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # Log anything (except mail) of level info or higher.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # Don't log private authentication messages!&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; *.info;mail.none;authpriv.none;cron.none;local0.none    /var/log/messages&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-family:times new roman;" &gt;*.info;mail.none;authpriv.none;cron.none;local0.none    @foo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # The authpriv file has restricted access.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; authpriv.*                      /var/log/secure&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);font-family:times new roman;" &gt;authpriv.*                      @foo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # Log all the mail messages in one place.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; mail.*                          -/var/log/maillog&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # Log cron stuff&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; cron.*                          /var/log/cron&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # Everybody gets emergency messages&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; *.emerg                         *&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # Save news errors of level crit and higher in a special file.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; uucp,news.crit                      /var/log/spooler&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; # Save boot messages also to boot.log&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; local7.*                        /var/log/boot.log&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt; local0.*                        /var/log/squid.log&lt;/span&gt;&lt;/span&gt;           &lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;Now still on &lt;span style="font-style: italic;"&gt;bar&lt;/span&gt; add &lt;span style="font-style: italic;"&gt;foo&lt;/span&gt; to&lt;span style="font-family:courier new;"&gt; /etc/hosts.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;  &lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style=";font-family:times new roman;font-size:85%;"  &gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# Do not remove the following line, or various programs&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;  # that require network functionality will fail.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;  127.0.0.1   localhost.localdomain   localhost   bar&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;  &lt;span style="color: rgb(204, 0, 0);"&gt;192.168.1.101  foo&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;Then restart syslog on &lt;span style="font-style: italic;"&gt;bar.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;[root@bar ~]#&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;service syslog restart&lt;br /&gt;Shutting down kernel logger:                               [  OK  ]&lt;br /&gt;Shutting down system logger:                               [  OK  ]&lt;br /&gt;Starting system logger:                                    [  OK  ]&lt;br /&gt;Starting kernel logger:                                    [  OK  ]&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;Now test it out.  Use the command &lt;span style="font-family:courier new;"&gt;logger&lt;/span&gt; on &lt;span style="font-style: italic;"&gt;bar&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;[root@bar ~]# logger test&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;And then on &lt;span style="font-style: italic;"&gt;foo&lt;/span&gt;, tail messages and see if you go it&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;[root@quagmire ~]# tail -1 /var/log/messages&lt;br /&gt;May 22 17:34:29 bar root: test&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;&lt;br /&gt;Now for our little verification script.  The way this will work is every hour we'll create a syslog message on &lt;span style="font-style: italic;"&gt;bar&lt;/span&gt; and on &lt;span style="font-style: italic;"&gt;foo&lt;/span&gt; we'll complain if it's been more than two hours since we got that message from &lt;span style="font-style: italic;"&gt;bar&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;On&lt;span style="font-style: italic;"&gt; bar&lt;/span&gt; change director to /etc/cron.hourly/ and create a shell script called rollcall.sh&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[root@bar cron.hourly]# vim rollcall.sh&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;#!/bin/bash&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;&lt;span style="color: rgb(0, 0, 153);font-size:85%;" &gt;/usr/bin/logger checking in&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Now chmod it executible.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;[root@bar cron.hourly]# chmod +x rollcall.sh&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;br /&gt;On &lt;span style="font-style: italic;"&gt;foo&lt;/span&gt; change into /usr/local/sbin/ create a perl script called rollcall_check.pl.  This script requires Sys::SyslogMessages and IO::Capture::Stdout.  Use &lt;span style="font-family:courier new;"&gt;cpan2rpm&lt;/span&gt; to install them if you don't already have both modules.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;[root@foo sbin]# vim rollcall_check.pl&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;#!/usr/bin/perl -w&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# http://greg-techblog.blogspot.com&lt;br /&gt;# This is a dirty hack, but it gets the job done&lt;br /&gt;use strict;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;use Sys::SyslogMessages;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;use IO::Capture::Stdout;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;my $rollcall_conf="&lt;/span&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;/usr/local/etc/rollcallhosts.conf&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;";&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;open (HOSTS, "$rollcall_conf") || die("Can't open $rollcall_conf");&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;my @hosts_conf = &lt;hosts&gt;;&lt;/hosts&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;close HOSTS;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;my %hosts = (); &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;map {chomp; my $key = $_; $hosts{$key} = 0;} @hosts_conf; &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;my $capture = IO::Capture::Stdout-&gt;new();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$capture-&gt;start();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;my $messages = new Sys::SyslogMessages();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$messages-&gt;tail({'number_minutes' =&gt; '120'});&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$capture-&gt;stop();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;my @all_lines = $capture-&gt;read;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;my @matches;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;map {$_ =~ /\d\d:\d\d:\d\d\s(\w+).*checking in/; push @matches, ($1) if $1;} @all_lines;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;foreach my $host (sort(keys(%hosts))){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;    map {$hosts{$host} = 1 if $_ eq $host} @matches;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;    print "$host did not report in.\n" if ! $hosts{$host}; &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;Now chmod it executible.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;[root@foo cron.hourly]# chmod +x &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;rollcall_check.pl&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;br /&gt;Create one more file in &lt;span style="font-family:courier new;"&gt;/usr/local/etc/&lt;/span&gt; called rollcallhosts.conf.  This will just be a list of hosts we expect to hear from.  One hostname per line.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;[root@foo etc]# vim rollcallhosts.conf&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;&lt;span style="color: rgb(0, 0, 153);font-family:times new roman;" &gt;bar&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Finally symlink &lt;/span&gt;rollcall_check.pl &lt;span style="font-family:times new roman;"&gt;in&lt;/span&gt; /etc/cron.hourly.&lt;br /&gt;&lt;br /&gt;[root@foo cron.hourly]# ln -s /usr/local/sbin/rollcall_check.pl&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-family:times new roman;"&gt;Now our script will only complain if &lt;span style="font-style: italic;"&gt;bar&lt;/span&gt; hasn't check in with &lt;span style="font-style: italic;"&gt;foo&lt;/span&gt; at least once in the last two hours and &lt;span style="font-style: italic;"&gt;root@foo&lt;/span&gt; should get an email about it.  There is one little problem with this, and that's when logrotate on &lt;span style="font-style: italic;"&gt;foo&lt;/span&gt; kicks in, you'll likely get a false message.  Oh well, that shouldn't happen too often.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-8157601737215509791?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/8157601737215509791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/centralize-syslogging-quick-and-dirty.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/8157601737215509791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/8157601737215509791'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/centralize-syslogging-quick-and-dirty.html' title='Centralize Syslogging Quick and Dirty'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-5228744533840683379</id><published>2009-05-22T11:34:00.000-07:00</published><updated>2009-05-27T22:33:06.630-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='lvm'/><category scheme='http://www.blogger.com/atom/ns#' term='ext3'/><title type='text'>Extend a Mounted LVM  EXT3 Partition</title><content type='html'>&lt;span style="font-family:times new roman;"&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Prerequisites:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;You need to have some extra unused space in your volume group.  That's pretty much it.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Dump:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[root@webapp /]# df -h&lt;br /&gt;Filesystem            Size  Used Avail Use% Mounted on&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;/dev/mapper/VolGroup00-LogVol00&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;                    5.9G  4.5G  1.1G  81% /&lt;/span&gt;&lt;br /&gt;/dev/xvda1             99M   29M   66M  31% /boot&lt;br /&gt;tmpfs                 3.0G     0  3.0G   0% /dev/shm&lt;br /&gt;&lt;br /&gt;[root@webapp /]# pvscan&lt;br /&gt;PV /dev/xvda2   VG VolGroup00   lvm2 [15.50 GB / &lt;span style="color: rgb(255, 0, 0);"&gt;7.56 GB free&lt;/span&gt;]&lt;br /&gt;Total: 1 [15.50 GB] / in use: 1 [15.50 GB] / in no VG: 0 [0   ]&lt;br /&gt;&lt;br /&gt;[root@webapp /]# lvextend -L&lt;span style="color: rgb(255, 0, 0);"&gt;+3G&lt;/span&gt; /dev/VolGroup00/LogVol00&lt;br /&gt;Extending logical volume LogVol00 to 9.00 GB&lt;br /&gt;Logical volume LogVol00 successfully resized&lt;br /&gt;&lt;br /&gt;[root@webapp /]# resize2fs /dev/VolGroup00/LogVol00&lt;br /&gt;resize2fs 1.39 (29-May-2006)&lt;br /&gt;Filesystem at /dev/VolGroup00/LogVol00 is mounted on /; on-line resizing required&lt;br /&gt;Performing an on-line resize of /dev/VolGroup00/LogVol00 to 2359296 (4k) blocks.&lt;br /&gt;The filesystem on /dev/VolGroup00/LogVol00 is now 2359296 blocks long.&lt;br /&gt;&lt;br /&gt;[root@webapp /]# df -h&lt;br /&gt;Filesystem            Size  Used Avail Use% Mounted on&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;/dev/mapper/VolGroup00-LogVol00&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;                    8.8G  4.5G  3.9G  54% /&lt;/span&gt;&lt;br /&gt;/dev/xvda1             99M   29M   66M  31% /boot&lt;br /&gt;tmpfs                 3.0G     0  3.0G   0% /dev/shm&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Done.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-5228744533840683379?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/5228744533840683379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/extend-mounted-lvm-ext3-partition.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/5228744533840683379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/5228744533840683379'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/extend-mounted-lvm-ext3-partition.html' title='Extend a Mounted LVM  EXT3 Partition'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-2222836941851554201</id><published>2009-05-22T08:42:00.000-07:00</published><updated>2009-05-27T22:33:29.729-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mysql'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='lamp'/><category scheme='http://www.blogger.com/atom/ns#' term='replication'/><category scheme='http://www.blogger.com/atom/ns#' term='lvm'/><title type='text'>Setup or Fix MySQL Replication Fast</title><content type='html'>&lt;span style="font-family:times new roman;"&gt;So here is how to use LVM snapshots to setup or fix MySQL replication quickly.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Prerequisites:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;First you need to have used LVM on the location of your MySQL store.  I'm not walking you through that.  And you need to have left some unused space in the volume group that your logical volume is in.  If you don't know what any of that means, go read up on LVM.&lt;br /&gt;&lt;br /&gt;Second, you're going to need to create an ssh key.  Also not walking you through that.  Setup an ssh key on your slave server, so that your master server can ssh to it as root without using a password.&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:times new roman;font-size:100%;"  &gt;Third, the script I've written assumes your MySQL store is in &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style=";font-family:times new roman;font-size:100%;"  &gt;/var/lib/mysql.  And I've written this for CentOS/Redhat, so I'm assuming&lt;/span&gt;&lt;br /&gt;service mysql stop&lt;br /&gt;&lt;span style=";font-family:times new roman;font-size:100%;"  &gt;Shuts down your mysql server.  Both of these should be easy to fix for your installation&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;.&lt;br /&gt;&lt;br /&gt;Fourth, make sure &lt;span style="font-family:courier new;"&gt;skip_slave_start&lt;span style="font-family:times new roman;"&gt; is in your &lt;/span&gt;my.cnf &lt;span style="font-family:times new roman;"&gt;on your slave server.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:times new roman;"&gt;Last, you'll need rsync, perl and the modules Linux::LVM and Getopt::Long.  If you're using an rpm based distro, use cpan2rpm to install those modules.  Everyone else, CPAN or your package manager.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The Plan&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;So what we are going to do is simple.  We shutdown MySQL on the slave server.  Then connect to your master database and get a list of all your databases, lock all the databases and get the master log position.  &lt;/span&gt;&lt;span style="font-family:times new roman;"&gt;Make sure a replication user is setup.  &lt;/span&gt;&lt;span style="font-family:times new roman;"&gt;Then we create a snapshot, and unlock the master.  Mount the snapshot and rsync the databases we got from the master to the slave.  Unmount and remove the snapshot on the master.  Start up the slave, set the log position and start up replication.  Done.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The Script&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/usr/bin/perl -w&lt;br /&gt;# Script to fix or setup MySQL replication&lt;br /&gt;# http://greg-techblog.blogspot.com&lt;br /&gt;&lt;br /&gt;use strict;&lt;br /&gt;use DBI qw{:sql_types};&lt;br /&gt;use Linux::LVM;&lt;br /&gt;use Getopt::Long;&lt;br /&gt;&lt;br /&gt;# Database user.  Assumes the slave user and pass on both slave and master&lt;br /&gt;my $dbuser = q{USERNAME};&lt;br /&gt;my $dbpass = q{PASSWORD};&lt;br /&gt;&lt;br /&gt;# Should be an ip address, not a hostname&lt;br /&gt;my $dbhost_master = q{192.168.1.2};&lt;br /&gt;my $dbhost_slave = q{192.168.1.3};&lt;br /&gt;&lt;br /&gt;# Replication user&lt;br /&gt;my $replication_user = q{repl};&lt;br /&gt;my $replication_pass = q{repl};&lt;br /&gt;&lt;br /&gt;# Databases to skip when rsyncing the data director&lt;br /&gt;my @skip   = qw{information_schema};&lt;br /&gt;&lt;br /&gt;# Name for our LVM snapshot&lt;br /&gt;my $snapshot_name = q{dbbackup};&lt;br /&gt;&lt;br /&gt;# Volume Group name where we are creating the snapshot&lt;br /&gt;my $volgroup = q{VolGroup00};&lt;br /&gt;&lt;br /&gt;# Logical Volume to snapshot&lt;br /&gt;my $logvol = q{LogVol02};&lt;br /&gt;&lt;br /&gt;# Location of ssh key&lt;br /&gt;my $ssh_key = q{/root/.ssh/id_rsa};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;my $dsn1 = qq|DBI:mysql:database=mysql;host=$dbhost_master;port=3306|;&lt;br /&gt;my $dsn2 = qq|DBI:mysql:database=mysql;host=$dbhost_slave;port=3306|;&lt;br /&gt;my $help;&lt;br /&gt;&lt;br /&gt;GetOptions (&lt;br /&gt;"master|m=s" =&gt; \$dbhost_master,&lt;br /&gt;"slave|s=s"  =&gt; \$dbhost_slave,&lt;br /&gt;"ruser=s"    =&gt; \$replication_user,&lt;br /&gt;"rpass=s"    =&gt; \$replication_pass,&lt;br /&gt;"duser=s"    =&gt; \$dbuser,&lt;br /&gt;"dpass=s"    =&gt; \$dbpass,&lt;br /&gt;"key|k=s"    =&gt; \$ssh_key,&lt;br /&gt;"vol|v=s"    =&gt; \$volgroup,&lt;br /&gt;"log|l=s"    =&gt; \$logvol,&lt;br /&gt;"help|?|h"   =&gt; \$help,&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;# Print help&lt;br /&gt;if ($help) {&lt;br /&gt;print "&lt;br /&gt;$0 [options]\n&lt;br /&gt;--master/-m         IP address of master server (Default: $dbhost_master)&lt;br /&gt;--slave/-s          IP address of slave server (Default: $dbhost_slave)&lt;br /&gt;--ruser             Replication username (Default: $replication_user)&lt;br /&gt;--rpass             Replication password (Default: $replication_pass)&lt;br /&gt;--duser             Database admin user (Default: $dbuser)&lt;br /&gt;--dpass             Database admin password (Default: XXXXXX)&lt;br /&gt;--key/-k            Full path to ssh-key (Default: $ssh_key)&lt;br /&gt;--vol/v             Volume Group (Default: $volgroup)&lt;br /&gt;--log/l             Logical Volume (Default: $logvol)&lt;br /&gt;--help/-?/-h        This help\n&lt;br /&gt;";&lt;br /&gt;exit 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Define a statement handle&lt;br /&gt;my $sth;&lt;br /&gt;# Check to see is snapshot volume exists already and die if it does&lt;br /&gt;my %lvm = get_logical_volume_information($volgroup);&lt;br /&gt;my @lvm = keys %lvm;&lt;br /&gt;if (grep /\/$volgroup\/$snapshot_name$/, @lvm) {&lt;br /&gt;die ("Snapshot volume already exists.  Use lvmremove to remove it before running this command.\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Shutdown Mysql on slave server&lt;br /&gt;unless ( -e $ssh_key ) {&lt;br /&gt;die ("Ssh key identity file missing: $ssh_key");&lt;br /&gt;}&lt;br /&gt;exe_cmd(&lt;br /&gt;qq{ssh -i $ssh_key root\@$dbhost_slave "service mysql stop"},&lt;br /&gt;qq{Couldn't ssh to slave and stop mysql}&lt;br /&gt;);&lt;br /&gt;print "Mysql on slave stopped\n";&lt;br /&gt;&lt;br /&gt;#Connect to Master database&lt;br /&gt;my $dbh = DBI-&gt;connect(&lt;br /&gt;$dsn1,&lt;br /&gt;$dbuser,&lt;br /&gt;$dbpass,&lt;br /&gt;{RaiseError =&gt; 0, AutoCommit =&gt; 1 }&lt;br /&gt;) or die ("Error Connecting to server: ".DBI::errstr);&lt;br /&gt;my $sth_dbs = $dbh-&gt;prepare(q{SHOW DATABASES});&lt;br /&gt;$sth_dbs-&gt;execute or die("Problem executing query: ".$sth_dbs-&gt;errstr);&lt;br /&gt;&lt;br /&gt;# Lock all tables on master database&lt;br /&gt;$sth = $dbh-&gt;prepare(q{FLUSH TABLES WITH READ LOCK});&lt;br /&gt;$sth-&gt;execute or die("Probelm executing query: ".$sth-&gt;errstr);&lt;br /&gt;print "All Databases on master locked\n";&lt;br /&gt;&lt;br /&gt;# Get the master log position and file&lt;br /&gt;$sth = $dbh-&gt;prepare(q{SHOW MASTER STATUS});&lt;br /&gt;unless ($sth-&gt;execute) {&lt;br /&gt;my $err_msg = $sth-&gt;errstr;&lt;br /&gt;my $sth_unlock = $dbh-&gt;prepare(q{UNLOCK TABLES});&lt;br /&gt;$sth_unlock-&gt;execute;&lt;br /&gt;die("Probelm executing query: $err_msg\n".$sth_unlock-&gt;errstr);&lt;br /&gt;}&lt;br /&gt;my $master_status;&lt;br /&gt;unless ($master_status = $sth-&gt;fetchrow_hashref) {&lt;br /&gt;my $err_msg = $sth-&gt;errstr;&lt;br /&gt;my $sth_unlock = $dbh-&gt;prepare(q{UNLOCK TABLES});&lt;br /&gt;$sth_unlock-&gt;execute;&lt;br /&gt;die("Probelm executing query: $err_msg\n".$sth_unlock-&gt;errstr);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Create the snapshot&lt;br /&gt;my $lvcreate_msg = `lvcreate -L1G -s -n $snapshot_name \&lt;br /&gt;            /dev/$volgroup/$logvol 2&gt;&amp;amp;1`&lt;br /&gt;;&lt;br /&gt;if ( $? ) {&lt;br /&gt;my $sth_unlock = $dbh-&gt;prepare(q{UNLOCK TABLES});&lt;br /&gt;$sth_unlock-&gt;execute;&lt;br /&gt;die("Couldn't create snapshot: $lvcreate_msg $?\n".$sth_unlock-&gt;errstr);&lt;br /&gt;}&lt;br /&gt;print "Snapshot created\n";&lt;br /&gt;&lt;br /&gt;# Unlock all tables&lt;br /&gt;$sth = $dbh-&gt;prepare(q{UNLOCK TABLES});&lt;br /&gt;$sth-&gt;execute or die("Probelm executing query: ".$sth-&gt;errstr);&lt;br /&gt;print "All databases on master unlocked\n";&lt;br /&gt;&lt;br /&gt;# Grant replication rights on master&lt;br /&gt;$sth = $dbh-&gt;prepare(q{GRANT REPLICATION SLAVE ON *.* TO ?@? IDENTIFIED BY ?});&lt;br /&gt;$sth-&gt;execute($replication_user,$dbhost_slave,$replication_pass)&lt;br /&gt;or die("Problem executing query: ".$sth-&gt;errstr);&lt;br /&gt;&lt;br /&gt;# Mount the snapshot&lt;br /&gt;unless ( -d qq{/mnt/$snapshot_name}) {&lt;br /&gt;mkdir qq{/mnt/$snapshot_name} or die ("Couldn't create mount point directory: $?");&lt;br /&gt;}&lt;br /&gt;my $mount_snapshot_msg = `mount /dev/$volgroup/$snapshot_name \&lt;br /&gt;                  /mnt/$snapshot_name -onouuid,ro 2&gt;&amp;amp;1`&lt;br /&gt;;&lt;br /&gt;die ("Couldn't mount snapshot: $mount_snapshot_msg $?") if $?;&lt;br /&gt;&lt;br /&gt;# Start rsyncing the snapshot to the slave&lt;br /&gt;print "Starting rsync\n";&lt;br /&gt;my $out;&lt;br /&gt;while ( my ($db) = $sth_dbs-&gt;fetchrow_array ) {&lt;br /&gt;unless (grep /^$db$/, @skip) {&lt;br /&gt;$out .= `rsync -zrav /mnt/$snapshot_name/lib/mysql/$db/ \&lt;br /&gt;         $dbhost_slave:/var/lib/mysql/$db/ 2&gt;&amp;amp;1`&lt;br /&gt;;&lt;br /&gt;}&lt;br /&gt;die ("rsync failed: $out $?") if $?;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# Diconnect from Master Database&lt;br /&gt;$dbh-&gt;disconnect;&lt;br /&gt;&lt;br /&gt;# Get rid of snapshot&lt;br /&gt;print $out;&lt;br /&gt;exe_cmd(&lt;br /&gt;qq{umount /mnt/$snapshot_name},&lt;br /&gt;qq{Couldn't umount snapshot}&lt;br /&gt;);&lt;br /&gt;exe_cmd(&lt;br /&gt;qq{lvremove -f /dev/$volgroup/$snapshot_name},&lt;br /&gt;qq{Couldn't remove snapshot volume}&lt;br /&gt;);&lt;br /&gt;print "Snapshot removed\n";&lt;br /&gt;&lt;br /&gt;# Start Mysql back up on slave (skip_slave_start better be in the my.cnf)&lt;br /&gt;exe_cmd(&lt;br /&gt;qq{ssh -i $ssh_key root\@$dbhost_slave "service mysql start"},&lt;br /&gt;qq{Couldn't ssh to slave and start mysql}&lt;br /&gt;);&lt;br /&gt;print "Mysql on slave started\n";&lt;br /&gt;&lt;br /&gt;# Connect to slave and setup replication&lt;br /&gt;$dbh = DBI-&gt;connect( $dsn2, $dbuser, $dbpass, { RaiseError =&gt; 0, AutoCommit =&gt; 1 }  )&lt;br /&gt;or die ("Error Connecting to server: ".DBI::errstr);&lt;br /&gt;my $change_master_query = q{&lt;br /&gt;CHANGE MASTER TO MASTER_HOST    = ?,&lt;br /&gt;MASTER_USER                     = ?,&lt;br /&gt;MASTER_PASSWORD                 = ?,&lt;br /&gt;MASTER_LOG_FILE                 = ?,&lt;br /&gt;MASTER_LOG_POS                  = ?&lt;br /&gt;};&lt;br /&gt;$sth = $dbh-&gt;prepare($change_master_query) or die ("Problem preparing query\n $change_master_query\n".DBI::errstr);&lt;br /&gt;# Make MASTER_LOG_POS an INT&lt;br /&gt;$sth-&gt;bind_param(5,1,SQL_INTEGER);&lt;br /&gt;$sth-&gt;execute(&lt;br /&gt;$dbhost_master,&lt;br /&gt;$replication_user,&lt;br /&gt;$replication_pass,&lt;br /&gt;$master_status-&gt;{'File'},&lt;br /&gt;int($master_status-&gt;{'Position'})&lt;br /&gt;) or die ("Problem changing master:".$sth-&gt;errstr);&lt;br /&gt;&lt;br /&gt;# Slave slave&lt;br /&gt;$sth = $dbh-&gt;prepare(q{START SLAVE});&lt;br /&gt;$sth-&gt;execute or die ("Problem starting slave:".$sth-&gt;errstr);&lt;br /&gt;&lt;br /&gt;# Check to see if everything worked&lt;br /&gt;print "Sleep for 5 seconds...\n";&lt;br /&gt;sleep 5; # this may need to be longer&lt;br /&gt;$sth = $dbh-&gt;prepare(q{SHOW SLAVE STATUS});&lt;br /&gt;$sth-&gt;execute;&lt;br /&gt;my $slave_status = $sth-&gt;fetchall_arrayref({});&lt;br /&gt;print "Slave_SQL_Running:\t".$slave_status-&gt;[0]-&gt;{'Slave_SQL_Running'}."\n";&lt;br /&gt;print "Slave_IO_Running:\t".$slave_status-&gt;[0]-&gt;{'Slave_IO_Running'}."\n";&lt;br /&gt;print "Slave_IO_State:\t".$slave_status-&gt;[0]-&gt;{'Slave_IO_State'}."\n";&lt;br /&gt;print "Last_IO_Error:\t".$slave_status-&gt;[0]-&gt;{'Last_IO_Error'}."\n";&lt;br /&gt;print "Seconds_Behind_Master:\t".$slave_status-&gt;[0]-&gt;{'Seconds_Behind_Master'}."\n";&lt;br /&gt;&lt;br /&gt;sub exe_cmd {&lt;br /&gt;my $cmd = shift;&lt;br /&gt;my $fail_msg = shift;&lt;br /&gt;my $msg = `$cmd 2&gt;&amp;amp;1`;&lt;br /&gt;chomp $msg;&lt;br /&gt;die ("$fail_msg : $msg\n$?") if $?;&lt;br /&gt;}&lt;br /&gt;__END__&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-2222836941851554201?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/2222836941851554201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/setup-or-fix-mysql-replication-fast.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/2222836941851554201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/2222836941851554201'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/setup-or-fix-mysql-replication-fast.html' title='Setup or Fix MySQL Replication Fast'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4123913300004912345.post-4980392396984532337</id><published>2009-05-22T00:12:00.000-07:00</published><updated>2009-07-07T14:21:28.781-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='timemachine'/><category scheme='http://www.blogger.com/atom/ns#' term='nas'/><category scheme='http://www.blogger.com/atom/ns#' term='osx'/><title type='text'>OSX Time Machine Over Your Network Without a Timecapsule</title><content type='html'>So I spent the other day figuring out how to do this, and then when I went to price buying a NAS, timecapsules were going for $200, so I bought one.  I'm generally happy with it.  Thinking I had wasted my time figuring out how to make timemachine work with an unsupported network device, my co-worker mentioned to me today that he needed to get this working for our Macs at work.  Ha! I said, I'll get to use this bit of knowelege after all.  So here it is.&lt;br /&gt;&lt;br /&gt;Start by connecting to your network storage through either SMB or AFP.  Create a file called&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;.com.apple.timemachine.supported&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Next you're going to need your machine name and the MAC address of your network card.&lt;br /&gt;&lt;br /&gt;Drop to a terminal to get both of these.  You machine name should be your host name, or the first part of your command prompt, the bit before the colon.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Laptop:~ greg$&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Next now, execute&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;ifconfig&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Locate the line that says&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:130%;"  &gt;ether&lt;/span&gt;&lt;br /&gt;under the network interface card.  That's your MAC address.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;en0: flags=8863&lt;up,broadcast,smart,running,simplex,multicast&gt; mtu 1500&lt;/up,broadcast,smart,running,simplex,multicast&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-family:courier new;"&gt;    ether 00:13:db:9d:62:fc&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now take that machine name and MAC address minus the colons to create the name of the disk image you'll need to create to make this thing work.  Put them together seperated by an underscore.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Laptop_0013db9d62fc&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now you'll need to create a disk image.  Use this command, replacing your image name with mine and add &lt;span style="font-family:courier new;"&gt;.sparsebundle&lt;/span&gt; to the end of it.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;Laptop:~ greg$ hdiutil create -library SPUD -megabytes 204800 -fs HFS+J \&lt;br /&gt;-type SPARSEBUNDLE -volname "Laptop_0013db9d62fc.sparsebundle" \&lt;br /&gt;"Laptop_0013db9d62fc.sparsebundle&lt;/span&gt;"&lt;/blockquote&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;You should also set the size of your disk image about twice the size of the drive you are backing up.  After the disk image is finished being created, drop it on your network storage device.&lt;br /&gt;&lt;br /&gt;One last step and you're good to go.  Execute this at the terminal.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;defaults write com.apple.systempreferences\&lt;br /&gt;TMShowUnsupportedNetworkVolumes 1&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Now connect to your network storage device and open up timemachine, hit&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Change Disk&lt;/span&gt;&lt;br /&gt;and your network storage device should show up as an available device.&lt;br /&gt;&lt;br /&gt;Of course this is all subject to change.  I read through a number of&lt;br /&gt;how-to postings on this written a different times, and it seems apple&lt;br /&gt;keeps making this process more and more complicated, but as of the&lt;br /&gt;writing of this posting, this process works.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:times new roman;"&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4123913300004912345-4980392396984532337?l=greg-techblog.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://greg-techblog.blogspot.com/feeds/4980392396984532337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/osx-time-machine-over-your-network.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/4980392396984532337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4123913300004912345/posts/default/4980392396984532337'/><link rel='alternate' type='text/html' href='http://greg-techblog.blogspot.com/2009/05/osx-time-machine-over-your-network.html' title='OSX Time Machine Over Your Network Without a Timecapsule'/><author><name>Greg</name><uri>http://www.blogger.com/profile/04953765625493254267</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://2.bp.blogspot.com/_fFXiOUzFsdg/Skul-7B9IJI/AAAAAAAAAAs/uIIpmJVjqqc/S220/Photo+11.jpg'/></author><thr:total>0</thr:total></entry></feed>
