Category: Geek Stuff

  • Graphite Graphs for WordPress

    It’s no secret that I love Graphite. My co-workers think it’s a bit ridiculous how much data I feed into our graphite server. I may be a bit excessive, but I have a monitor in my office which allows me to see at a glance every little detail about our network in real time – server health, pageviews, Google Pagespeed Insight scores, etc. I can’t even describe how wonderful a tool it is.

    I wanted an easy way to display graphite graphs on the WordPress dashboard. So I rolled out a plugin over the weekend. I give you WordPress Graphite Graphs – I admit I [somewhat] got the idea from WPVIP’s “page generation time” graph in the VIP dashboard, but I’m sure they won’t mind. This plugin allows me (or you) to rapidly deploy monitoring graphs across many different sites without a lot of hassle and NO custom code for each site. Just plug in the URL of your graphite server, the metrics you want to display, and viola – Graphy delight! While I was at it, I went ahead and added support for graphs on the front-end in the sidebar that can be hidden from non-users if needed. Why not, right?

    Shoot me a tweet if you’re interested in additional features or get in on the action and fork it on github.

  • Cambridge, MIT, and WordCamp Boston 2013

    Cambridge, MIT, and WordCamp Boston 2013

    I had the pleasure of attending WordCamp Boston 2013 last weekend where I got my third WordCamp T-Shirt for 2013. The camp was held at the Microsoft New England Research & Development (NERD) Center. I also had the pleasure of checking out the MIT campus while I was in Cambridge which was a total treat. Here’s some pictures from the weekend.

  • A little PHP script to watch for 404 errors

    This is a quick script which reads a standard RSS feed and then grabs the response header for each feed item and makes a log file of 404 errors. Useful in debugging sticky situations.

    <?php 
    
    $link_queue = array(); 
    $exception_queue = array(); 
    
    $timestamp = date( 'Y-m-d H:i:s' ); 
    $rss = simplexml_load_file( $argv[1] ); 
    
    foreach ( $rss-&gt;channel-&gt;item as $item )
      array_push( $link_queue, $item-&gt;link );
    
    foreach ( $link_queue as $url ) {
      $handle = curl_init( $url );
      curl_setopt( $handle, CURLOPT_RETURNTRANSFER, TRUE );
      $response = curl_exec( $handle );
      $response_code = curl_getinfo( $handle, CURLINFO_HTTP_CODE );
    
      if ( $response_code !== 200 )
        array_push( $exception_queue, &quot;{$url} returned status code {$response_code}&quot; );
    
      curl_close( $handle );
    }
    
    if ( count( $exception_queue ) ) {
      foreach ( $exception_queue as $e )
        echo $timestamp . ' &gt; ' . $e . &quot;n&quot;;
    } else {
      echo $timestamp . &quot; &gt; All URLs returned status code 200n&quot;;
    }
    
    die();
    
    // omit
    

    Throw it in cron like this:
    */30 * * * * php /path/to/script.php http://somesite.com/feed/ >> /path/to/log 2>&1

    Or run it on the command line like this:
    php /path/to/the/script.php http://somesite.com/feed/

  • Some Helpful Varnish Commands

    Look at incoming requests for URL
    varnishlog -c -m RxURL:"/somepage.html"

    Look at requests made to the backend for URL
    varnishlog -b -m TxURL:"/somepage.html"

    Requests for one specific host
    varnishlog -c -m RxHeader:"Host: somehost.com"

    See cache age for a specific host
    varnishlog -c -m RxHeader:"Host: somehost.com" | grep Age

    Test VCL compilation
    varnishd -C -f /path/to/file.vcl

    Ban all URLs
    varnishadm -S /path/to/secret -T :6082 "ban.url /"

    View Ban List
    varnishadm -S /path/to/secret -T :6082 "ban.list"

    Real time URLs being sent to backend
    varnishtop -b -i TxURL

    List backend traffic
    varnishlog -b -o

    List URLs going to backend
    varnishlog -b -o -i TxURL | grep TxURL | awk '{print $4}'

  • Assign Random Featured Images To All Posts

    Assign Random Featured Images To All Posts

    Could be used for setting up dummy content for a staging environment, or something similar. Be my guest and let me know how you decide to use it in the comments! Also, check my github for this function built into a WP-CLI command.

    	$posts = new WP_Query( array( 
    		'posts_per_page' => -1, 
    		'post_type' => 'post', 
    	));
    	
    	$post_ids = array();
    	
    	while ( $posts->have_posts() ) {
    		$posts->the_post();
    		array_push( $post_ids, get_the_ID() );		
    	}
    	
    	wp_reset_query();
    	
    	$attachments = new WP_Query( array( 
    		'posts_per_page' => -1, 
    		'post_type' => 'attachment', 
    		'post_status' => 'inherit', 
    	));
    	
    	$attachment_ids = array();
    	
    	while ( $attachments->have_posts() ) {
    		$attachments->the_post();
    		array_push( $attachment_ids, get_the_ID() );
    	}
    	
    	wp_reset_query();
    	
    	foreach ( $post_ids as $post_id ) {
    		$attachment_id = rand( 0, count( $attachment_ids ) - 1 );
    		
    		echo 'post:' . $post_id . ' attachment:' . $attachment_ids[$attachment_id];
    		
    		if ( update_post_meta( $post_id, '_thumbnail_id', $attachment_ids[$attachment_id] ) )
    			echo ' SUCCESS';
    		else
    			echo ' FAILED';
    	}
    	
    	die( 'script complete' );
  • Extract Memory Usage As Integer

    free -m | grep Mem | awk '{print $3}'

    Use that and feed memory usage into a graphite server every minute from a cron script:

    */1 * * * * echo "some.system.memoryusage `free -m | grep Mem | awk '{print $3}'` `date +%s`" | nc graphite.somedomain.com 2003
  • WordPress Trackback Maintenance

    Sometimes you just need to get rid of all that trackback data from your WordPress database. Here’s how to do it manually from your MySQL command line:

    DELETE FROM wp_comments WHERE comment_type='trackback';
    DELETE FROM wp_comments WHERE comment_type='pingback';

    Great, but now your comments counts are all out of whack, since that integer is stored in the wp_posts table. Here’s how to check that:

    SELECT wpp.id, wpp.post_title, wpp.comment_count, wpc.cnt
    FROM wp_posts wpp
    LEFT JOIN (
    	SELECT comment_post_id AS c_post_id, count(*) AS cnt FROM wp_comments
    	WHERE comment_approved = 1 GROUP BY comment_post_id) wpc
    	ON wpp.id=wpc.c_post_id
    	WHERE wpp.post_type IN ('post', 'page')
    	AND (wpp.comment_count!=wpc.cnt OR (wpp.comment_count != 0 AND wpc.cnt IS NULL)
    );

    And here’s how to fix it (make a backup of your database first, just in case):

    UPDATE wp_posts wpp
    LEFT JOIN (
    	SELECT comment_post_id AS c_post_id, count(*) AS cnt FROM wp_comments
    	WHERE comment_approved = 1 GROUP BY comment_post_id) wpc
    	ON wpp.id=wpc.c_post_id
    	SET wpp.comment_count=wpc.cnt
    	WHERE wpp.post_type IN ('post', 'page')
    	AND (wpp.comment_count!=wpc.cnt OR (wpp.comment_count != 0 AND wpc.cnt IS NULL)
    );

    Cheers!

  • Making A Bootable CentOS 6.4 x86_64 USB Key

    Making A Bootable CentOS 6.4 x86_64 USB Key

    1. Download the PenDriveLinux “Univerals USB Installer” from http://www.pendrivelinux.com/downloads/Universal-USB-Installer/Universal-USB-Installer-1.9.3.9.exe.
    2. Download the Centos 6.4 Live DVD from http://holmes.umflint.edu/centos/6.4/isos/x86_64/CentOS-6.4-x86_64-LiveDVD.iso (or any other mirror).
    3. Run the Universal USB Installer utility and click “I Agree” on the license agreement screen.
    4. Insert your USB drive into an open USB port on your computer.
    5. Installer Step 1 – Select CentOS from the dropdown list. It’s near the bottom under the “Other Distros Alphabetical” category.
    6. Installer Step 2 – Click “Browse” to locate the ISO. Now, because the utility is trying to locate a specifically named ISO file, you need to type in *.* and hit enter to show all files. Now select your newly downloaded CentOS ISO and click “open”.
    7. Installer Step 3 – Select the drive letter of the USB drive, and finally hit create.
    8. Wait for the utility to work its magic. It will load up 7zG and install the ISO file onto your USB thumb drive.
    9. When it’s done, move the USB key to your target machine, restart, and boot from USB. You’ll now be looking at the CentOS 6.4 live version and you have the option to play with it or install it to disk.

    Universal USB Installer7zG

  • Using Samba on CentOS With Windows 7/8

    Using Samba on CentOS With Windows 7/8

    Go ahead and install the samba packages:

    sudo yum install samba samba-client samba-common
    smbd --version
    sudo chkconfig smb on
    sudo chkconfig nmb on
    sudo nano /etc/selinux/config

    Disable SELINUX by editing /etc/selinux/config and make one small change:

    SELINUX=disabled

    Make some additions to iptables:

    sudo iptables -I INPUT 4 -m state --state NEW -m udp -p udp --dport 137 -j ACCEPT
    sudo iptables -I INPUT 5 -m state --state NEW -m udp -p udp --dport 138 -j ACCEPT
    sudo iptables -I INPUT 6 -m state --state NEW -m tcp -p tcp --dport 139 -j ACCEPT
    sudo service iptables save

    NOW, restart the server:

    sudo reboot now

    Backup and modify smb.conf:

    sudo cp /etc/samba/smb.conf /etc/samba/smb.conf.bak
    sudo rm /etc/samba/smb.conf
    sudo touch /etc/samba/smb.conf
    sudo nano /etc/samba/smb.conf

    The file should contain:

    [global]
    workgroup = WORKGROUP
    server string = server_name
    security = user
    map to guest = bad user
    
    [private-share]
    path = /media/sdd
    valid users = @smbgrp
    guest ok = no
    writable = yes
    browsable = yes

    Restart smb and nmb:

    sudo service smb restart
    sudo service nmb restart

    Add your groups and add users to them:

    sudo groupadd smbgrp
    cd /media/sdb
    sudo mkdir secureshare
    sudo chown -R username:smbgrp secureshare/
    ls -l
    sudo chmod -R 0770 secureshare/
    sudo usermod -a -G smbgrp username
    sudo smbpasswd -a username
    sudo service smb restart
    sudo service nmb restart
    sudo testparm

    private-share

    Now connect from a windows PC using credentials from CentOS server by right-clicking within “Computer” and selecting “Add a network location”. Follow the prompts and your share will be usable from Windows!

    If you cannot connect, it’s most likely the firewall on the CentOS machine. Backup and then flush iptables to test if needed, and then rebuild your firewall accordingly. If you cannot get access to your shares, you have a permissions problem on the server end. Check users, groups, share permissions, and smb.conf for proper values.

    You’re welcome 😉

  • More Goodies For The Boat

    More Goodies For The Boat

    I wanted to write an update to my last post about fixing up my boat.

    I re-installed the starter, tightened up all the other small issues, and cranked the engine for about ten minutes. Nothing.

    BUT … I think I flooded it … because the next day she fired up on the first try, nice and strong, just like she should!

    Before it was running, I bought this tool to [attempt to] test the ignition system:

    AutoCraft AC664 Ignition TesterTo be fair, the boat has a points ignition system which may somehow differ from other similar systems, but this thing DID NOT do the job. A spark is a spark, and nothing was happening with this tool installed as it should be. My guess? The shaft is pretty loose and difficult to adjust, and coated with some sort of anodized material. They should have made the shaft uncoated copper, aluminum, or nickel. NOT anodized steel.

    I know the tool wasn’t working as it should, because the engine actually fired up while it was connected, but this thing still wasn’t sparkin’!

    Yesterday, I decided I was sick of wrenching the batteries on and off every time I got on the boat. So, I ordered this:

    SAMSUNGThis is a fantastic piece, which allows me to select a single battery, both batteries, or completely disconnect them. It’s rated for 230A continuous and 345A momentary, which should be ample (no pun intended). It also includes a field disconnect, so the switch can be moved with the engine running – which is a great feature. Installation was quick and easy.

    So the boat starts, runs, shifts, and (hopefully) floats well. Time to go play! We’re leaving for the Keys tomorrow evening … Cheers!