Category Archives: Tech Stuff

Fixing the Add Coupon button in Flatsome theme for Woocommerce

As I was building out Texas Forever (Shameless plug: TexasForever.net has the greatest Texas Forever Shirts in the world), I ran into an issue with the Flatsome theme. When you were in the shopping cart and added a coupon code and then pressed “enter”, the page would refresh without actually applying the coupon code. The only way to actually apply the coupon for your Texas Forever shirt was to click the button.logo2-400x400

That wouldn’t do at all, so I went code diving. The file we need to update is buried in /wp-content/themes/flatsome/woocommerce/cart/cart.php

Ideally, you are running a child theme of Flatsome. Assuming you are, just copy the file to your child theme to duplicate it, and then work on it there. If you are NOT, you can still edit the Flatsome theme file, but know that when you update the theme your change will be gone.

The solution itself is really simple: The theme author has a </form> tag out of place, so when you pressed enter in the shopping cart of TexasForever.net it interprets the ‘enter’ as being to submit the form to “Update Cart” and not to submit the form to apply the coupon code.

By moving the </form> tag from line 170 to line 148, the problem is solved and everything works as expected!

Toggle an SSH Config off or on with bash

terminal_icon_3dMy VPN at work is locked down to only allowing inbound and outbound traffic on port 22 to specific bastion servers, not to the entire internet. This means that if I am on the VPN, I need to have a ~/.ssh/config file to specify tunneling all connection through a bastion, but if I am NOT on VPN, I can not hit these bastion servers, so I need to move the config file out of the way before attempting to connect to a server via SSH.

This resulted in a LOT of the following:

And vice versa to move it back when I was on VPN. Because I’m lazy, I made this small bash utility and dropped it in my PATH as toggle_ssh_config.

Now, instead of using mv to move files back and forth, I just type tog<tab><enter> to toggle my SSH config off or on like this:

Fix Clipboard History for Mac Crashing

Everyone needs a clipboard history app. I just don’t understand how people are able to be efficient when their clipboard can only hold one item!

For the past few years, I have used Clipboard History and while I am sure that there are newer/better options that have popped up, this has worked for me for years and I just had no reason to change. That is until tonight.logo

I apparently copied WAY too much out of Excel, multiple times, and caused Clipboard History to freak out and required me to kill the process from terminal. Every time when I restarted the app, it would immediately crash again since it was trying to load my old history. This even persisted after reboot. The app immediately crashed, not allowing me to do anything with it.

In case anyone else runs into this, I was able to restore the app by manually tracking down the history and deleting it.

Fire up terminal, and navigate to ~/Library/Application Support/com.agileroute.clipboardhistory

In this directory, there is a directory for each of your clips, each with its own ID number. Inside those directories, there is the actual clip itself, in HTML, txt, etc and a properties file. It is important to note that your “Favorite” clips that never go away are also stored in here.

To fix Clipboard History, I did “ls -alt | head” to see what the IDs were for my oldest clips. These are your “Favorites” and you likely want to save them. Once you have identified what you want to keep, move them somewhere safe, delete everything else, and then move them back. I did the following (assume that 322 and 2608 are my “Favorites”)

Close terminal, and then fire up Clipboard History again, and all should be right with the world.

TabIt – Open Tabs in Chrome with a Variable

I constantly find myself needing to open a lot of similar tabs to research something at work. For example, maybe I want to review account notes on a few dozen accounts, or I want to audit 30-40 support tickets.

Most web apps usually just pass unique identifiers in the URL itself. For example, if you use Zendesk, a ticket URL might be https://subdomain.zendesk.com/tickets/123456 where 123456 is the Ticket ID number. You might have an internal CRM tool that has a URL like https://internal.company.com/accounts/95438.browsertabs

It doesn’t take a genius to figure out that by just changing the 95438 in the URL to a different number, you pull up a different account. So instead of going through the trouble of searching in the web app, most people just change the URL to the account they are looking for, or create a custom search in their browser.

When I have more than 4 or 5 of the same type of item I want to review (Tickets, Accounts, whatever), it becomes tedious to copy each item, open a new tab manually, paste the variable, and wait for the page to load.

For cases like this, I wrote a simple bash utility that I call tabit. Tabit has one job: Read input from a file and open a bunch of tabs with the specific variables. Here is a quick example using Youtube (since I obviously won’t share the links to Rackspace’s internal tools).

Say you have a list of the 10 most popular Youtube Video IDs.

We know that Youtube’s URL format is https://www.youtube.com/watch?v=<Unique ID>. Instead of manually copying/pasting that 10 times, here is how you would do it with Tabit.

First, grab the source from github: https://github.com/joshprewitt/tabit or copy the script below.

Place it somewhere in your default path. If you don’t know what that means, just put it at /usr/local/bin/tabit

Make it executable:

By default, Tabit looks for a file in your user’s home directory called ‘.tabit’. Paste the list of Youtube IDs into that file. If you are on a Mac and just copied the list above, the following will do the trick:

All that is left to do now is run the script. Using the defaults, the syntax is really simple: Just run

I added a few options like the ability to specify a file instead of the default ~/.tabit and also the option to have the tabs open in your current Chrome window. Lastly, if you happen to have a URL where the variable is NOT the last part of the URL, you can add on a suffix. You get the following help documentation if you run tabit with no arguments:

Help documentation for tabit

Basic usage: tabit [options] <start of URL with trailing slash> [Remainder of URL with leading slash]

Options:
-f <path to file>. — File to read variables from. Default is ~/.tabit
-c — Use Current Window.

That’s it! After you get used to using this, you will find that it is much easier to just paste the variables into ~/.tabit and run the script instead of manually opening a bunch of tabs.

Keyboard Shortcuts

When working with dozens (to hundreds) of tabs, don’t forget these shortcuts

Shortcut Keys Action
Cmd+Shift+{ Go to Left Tab
Cmd+Shift+} Go to Right Tab
Cmd+w Close Tab
Cmd+Shift+T Re-Open Most Recently Closed Tab
Click a tab + Shift + Click a different tab Select Range of Tabs (Cmd+w will close all selected tabs)

Gotchas

The script assumes a standard installation of Google Chrome. If you installed it somewhere else, you will need to edit lines 58 and 62 with the correct path to Chrome on your system.

References

Optargs help came from http://tuxtweaks.com/2014/05/bash-getopts/

Picture: Browsers by Eightemdi from the Noun Project

Using an Amazon Dash button to control Philips Hue lights

It’s been about 3.5 years since I wrote a post – better late than never 😀

All of my old content was in some way inspired by customers that I was supporting as an admin for Rackspace Cloud. This one is different and just something geeky and fun.

The Dash button is a nifty little piece of technology that Amazon put out last year. A lot of people thought it was an April Fools joke when announced, but it was no joke and is meant to let Amazon customers purchase consumables at the push of a button anywhere in their house. I received one when my son was born in February that would let me purchase Huggies Diapers.

41Q4Pp9l8zL._SX342_

I thought instead of buying diapers with it, I could probably figure out a way to hijack the URL that it was calling to make the purchase and instead have it call my Philips Hue hub. It turns out, it’s actually even easier than that. See, Amazon was so deliberate about preserving battery life that they built these little guys to be completely turned off and when the button is pressed it connects to your router to get an IP address before making the call to Amazon for the purchase. A few seconds later, it turns off and the IP is released.

This is important because after the Dash button is issued an IP, it sends an ARP probe broadcast out to the rest of the network. The image below explains an ARP Probe.

arpProbe-DashButtonSo all we need to do is have some other device on the network constantly waiting to see the ARP probe, and when it does, have it kick off a script to interact with the lights. This can be some other computer in the house. For me, I used a RaspberryPi.

Getting Started – Setting up the Dash Button

The first thing you need to do is connect the dash button to your wireless network. The dash button uses the speaker on your phone to send a magically encrypted sound to the dash button, which it interprets as the wifi settings to be able to connect to your network. Can we just take a moment to appreciate how freakin’ cool that is?

Following the below steps will connect the dash button to your network, but not actually configure it to buy a product. Otherwise, you will have a box of diapers (or ziploc bags, or razor refills) showing up on your doorstep every time you turn on the lights. Not cool.

  1. Use your phone to Download the Amazon app
  2. In the Amazon App, login to your Amazon account
  3. In the app, go to “Your Account -> Dash Devices -> Set up a new device
  4. Go through the steps to enter your wifi credentials and connect the dash button. But..
  5. Do NOT actually pick a product that you want the dash button to buy. After it is connected to your network and you are on the “Choose a Product” page, just close the app, never actually completing setup.

Collecting all of the information

To make this work, you will need to know the following

  1. IP address of your Hue Bridge
  2. A valid user for the bridge
  3. The ID number of the light(s) you want to control
  4. The MAC address of the Dash button

IP address of your Hue Bridge

If you have never before tinkered with the API for your Philips Hue system, then you have probably never setup a new user. No worries, we will make it pretty easy. First, you need to find the IP of your bridge. Philips makes this pretty painless in most cases. Just go to https://www.meethue.com/api/nupnp while on your network and it will look for the bridge. Tada!

Note: If that didn’t work, you can use the official Hue app: Go to the settings menu in the app. Go to My Bridge. Go to Network settings. Switch off the DHCP toggle. The ip address of the bridge will show. Note the ip address, then switch DHCP back on.

A valid user for the bridge

Now to register a new user. Craft a POST to http://<IP-of-Your-Bridge>/api with the payload ‘{“devicetype”:”my_dash_button_user”}’. The following cURL command should do the trick. Note: You MUST push the button on your bridge FIRST and run the following command while the light is flashing. Otherwise, you will get a response that says “link button not pressed”

In the response, you are looking for the randomly generated username. It is 32 characters long and will be between quotation marks. Copy that and save it somewhere.

The ID number of the light(s) you want to control

Now that we have the IP of the bridge and a valid user, we need to figure out what the ID number is for the light we will be controlling. The script below can be ran to list all of your Hue bulbs and their ID.

Edit it to include the correct variables for your bridge IP and user, save it as showLights.py, and run it!

The MAC address of the Dash Button

Now we need to capture the MAC address of the Dash button. The easiest way to do this is with scapy. Scapy is a packet manipulation library for Python. I installed it via pip:

With it installed, you can use a simple script to find the MAC address. I created a file called findMac.py

Paste this into a text document, and run it from terminal.

While the script is running, press your dash button. Within 1-5 seconds, you should see a MAC address show up. Press ctrl+c to stop the findMac.py tool. Copy the MAC address and save it somewhere.

You’ve come a long way – now we just need to put it all together

You can edit the script below to toggle a single light on/off using your dash button

Copy/Paste the script, modify the variables at the top and then save it as toggle.py. Make the file executable and then run it!

With the script running, push the Dash button. With any luck, you will get a few blinks on the dash button and in about 3 seconds your hue light will turn on. Push it again and the light will turn off!

Three Second Delay?!? What the heck!

Yes, this isn’t a light switch. Think about everything that has to happen:

  1. Your Dash button needs to power on
  2. Dash connects to your wireless network and requests an IP address
  3. IP is assigned to Dash
  4. Dash sends a probe out to the rest of the network
  5. Your RaspberryPi (or other computer) sees the probe
  6. Your RaspberryPi calls to your hue bridge to get the current status of the light
  7. Your RaspberryPi calls to your hue bridge to request the light turn off/on

So yeah, it takes 3 seconds. Deal with it. :-p

Making it Persist

The script above is a neat party trick, but if you actually intend to use the dash button regularly to turn on/off your lights, you need to make sure that the python script is always running, that multiple copies of the script aren’t running simultaneously, and that it starts on boot automatically in case your Pi loses power. This is where an init script comes in handy. Below is a modified script from http://blog.scphillips.com/posts/2013/07/getting-a-python-script-to-run-in-the-background-as-a-service-on-boot/

Create this script as /etc/init.d/dash-lights and edit lines 14-16 and line 20 based on where your files are stored, then change the permissions so it is executable:

Next, make sure that it starts on boot:

You can now start/stop this service just like you would any other daemon:

Extending the toggle script

The script above can get you started, but you may want to extend it to control multiple lights with the push of a button, or maybe have multiple dash buttons around the house for different lights. Here is an example of my toggle.py script. I have one dash button that controls two lamps in the living room, and a different dash button that controls the light in the nursery.

 

References

Here were some of the resources that helped along the way

Creating an init script for a python script http://blog.scphillips.com/posts/2013/07/getting-a-python-script-to-run-in-the-background-as-a-service-on-boot/

Using scapy to catch ARP probes from a dash button: https://medium.com/@edwardbenson/how-i-hacked-amazon-s-5-wifi-button-to-track-baby-data-794214b0bdd8#.spdcsx9ou

Philips Hue API Docs: http://www.developers.meethue.com/philips-hue-api

I put all the scripts I referenced above in github at https://github.com/joshprewitt/dash-lights

Using Sed to add a new line in Mac Terminal

This was driving me crazy until I hunted down the correct syntax. The following will replace a semicolon with a new line in Terminal for Mac

sed -e ‘s/;/\’$’\n/g’ /tmp/blah

dsh (Dancer’s Shell / Distributed Shell) and you

dsh is an awesome tool for administering pools of servers where you would just want to run the same few commands on each one. I run Mac OSX locally, so I’ll write the article from that perspective:

Install DSH on a Mac

First and foremost, you need to install dsh. The downloads page for the project is a nightmare (http://www.netfort.gr.jp/~dancer/software/downloads/list.cgi), but you basically want the latest version of libdshconfig and dsh. At the time of this writing, that would be 0.20.13 and 0.25.9 respectively.

I just dropped them into /tmp for the time being:

Then go through the normal install from source process, starting with libdshconfig

now you should be able to run dsh and have it return an error that no machine was specified:

Configuring DSH

You will want to setup RSA keys for your user on each of the machines that you want to log in to remotely so that you are not prompted for a password. (This is outside the scope of this article, there are about a gazillion different articles online that will teach that). Once the keys are in place, you will want to create group files. You will need to mkdir -p ~/.dsh/group and then create a text file in the group directory that lists the machines you want to connect to. Here is an example:

This sets the user and the host that you want in the “web” group.

Next up is a very important configuration change. dsh wants to use rsh by default instead of ssh. You will need to edit /usr/local/etc/dsh.conf as an Administrator to change that. Just change the line:

to read:

Save the file, and you are ready to go.

Actually using DSH

Ok, now for the magic. Assuming you have a group named ‘web’, you could run:

This will return the results of uname -a for each server. The -c flag does it concurrently instead of going to each machine one at a time. The -M flag tells it to list the machine name by the response.

Other stuff

I prefer to always see the machine name, so instead of always specifying -M, I created a new file at ~/,dsh/dsh.conf and included the line “showmachinenames=1”. You can set other options here too. For example, say you use a non standard ssh port. You could specify on the command line with -o:

OR, you can set dsh to always use a different port by adding the line “remoteshellopt=-p 2222” to your configuration file.

Other sources if my article didn’t make sense:

Check out Racker Hacker’s post: http://rackerhacker.com/2010/01/20/crash-course-in-dsh/

Bash One Liner that uses multiple variables

I’m not sure if this particular post will come in handy to a lot of people, but my bash scripting is still pretty weak and I think the best way to commit this to memory will be to write a short post on it.

I find myself doing one line “for” statements from the command line all the time to make quick loops. Maybe I need to loop through a list of servers and delete them all, maybe I need to ping a group of servers and see if they all reply, maybe I need to build a lot of servers of different flavors at once, etc.

Whatever the reason, I have occasionally come across the need for multiple variables in my loop. For example, let’s say that I have a list of data like this:

That format may look familiar if you use the Python Command Line tool for Rackspace Cloud Servers (http://pypi.python.org/pypi/python-cloudservers/1.2)

Now let’s say that I want to create an image of the 8 servers listed above. I would usually put the above table in a tmp file, and just call out the Server ID. Something like:

This gets the job done, but it is pretty ugly. I end up with image names like “Image-of-11114”, which can be more difficult to read than “Image-of-Cherry”

Using something like the following, I can allow multiple variables in my for loop:

The whole idea is to read the full line into a variable (x) and then loops through the line assigning a specific variable to whichever fields I need.

Upgrading to PHP 5.3 on Centos 5.5

The latest version of wordpress requires that you be running at least version 5.3 of php. This poses a problem for a lot of people who are still running 5.1 or 5.2 since that was the latest version available in the CentOS or Epel repositories for a long time.

Fortunately, php 5.3 is now available in the CentOS Base repo, so upgrading shouldn’t be too much of a nightmare. Here is what I did:

First and foremost, hopefully you are using a Cloud Hosting provider like Rackspace that will allow you to take a quick image of the server before you go messing with it. I strongly encourage you to have a recent backup of the server available, just in case. Once you have your image, move on:

First, you want to know what modules you currently have installed. The easiest way to do that would be to query rpm:

This will query all packages for php and output to a file in your home directory named php52. For example, on one of my old servers, that list looked like this:

Now, you will want to make a copy of that list, and modify the names to be php53.

Using a text editor, open up php53 and remove from the major version to the end of the line, then replace ‘php’ with ‘php53’. For example, the above list became this:

Now you have your list of what was installed (php52) and what you want installed (php53). Remove the old version of php:

(Note that those are backticks before cat and after php52. The backtick is the weird looking character next to the number 1 on your keyboard.)

Now that all of those packages are removed, install the php53 ones.

Expect some of the packages to fail. Some modules are now built into php53 common (mhash for one, I believe) and others simply don’t have a php53 package available yet (pear). Make note of the ones that yum complained were not available.

Any packages that were listed as not available will need to be examined one at a time to determine if you can use the old version, if it is deprecated, etc.

Once you are done, just restart apache and you should be good to go.

The one gotcha I ran into is that on some old custom sites I wrote sloppy code and used shorthand to open php code blocks (I used <? instead of <?php ) In the php.ini that comes with php53 from Centos, they have disabled this shorthand tag. To resolve this, just open up php.ini in a text editor and find the line for short_open_tag and turn it on. You can also use sed to make the change:

That should be it! The nice part about doing it this way is that if you screw something up, you can just yum install cat ~/php52 to return all of your old packages.

Setting up MemCache to handle PHP Sessions for a Web Cluster

A really common issue when people start to look towards scaling horizontally (adding on additional web/app servers) is session persistence.

Rackspace Cloud Load Balancers as a Service offers session persistence for HTTP (Port 80) traffic. This is done by the LB injecting a cookie into the response that specifies a node. The next time the user requests a page, they send the cookie and the load balancer reads it then directs traffic to the correct node.

This Session Persistence does NOT work on HTTPS (Port 443) because the LB is not able to terminate SSL. This means that the LB has no way to read the cookie being sent by the browser to achieve persistent sessions (and for that matter, no way to inject the cookie either).

Even if you are just load balancing port 80 traffic, what happens if you want to change or modify some code on a node? If you pull it out of rotation, it will go into a draining state where existing sessions can still connect; Not exactly a fast solution.

The solution to Load Balancing HTTPS or simply to load balancing without having to worry about session persistence at the LB is to store your sessions somewhere else. But where? You can store them in a Database if you want, but more than likely your database is busy enough as it is. A better solution would be to store the sessions on a separate memcache server.

For the uninitiated, memcache was originally created by livejournal. What it does is fairly simple: Gives you control over a certain amount of memory on the server so that you can store anything you want in there. This allows you to retrieve it much faster than if you had to read from disk. You can store DB query results, pages, or practically anything. We are going to store sessions.

This is assuming a brand new install of CentOS 5.5 from Rackspace Cloud Servers. First, let’s setup the memcache server.

MemCache Server

You will need the EPEL repo, so run this to install it:

Now that the EPEL repo is available, you can use yum to install it (while we are doing this, might as well install vim and tcpdump so we can watch it working)

Next up, we need to setup the very simply config file that memcache uses. It will be at /etc/sysconfig/memcached. Here is mine:

The variables are pretty straight forward: Port (default for memcache is 11211) User, Maximum Connections, Cache Size (How much memory in MB you are allowing memcache access to), Options (I specified -l for listen and told it to listen on the private IP address only. This would be the IP of the Memcache server, NOT the web server(s))

Next up, start the daemon and make it start on boot.

Next up, secure the memcache server. We don’t want to allow just anyone on the private network access to memcache. A rule set like this should do. Note that 10.1.1.1 and 10.2.2.2 would represent my Web Server Private IPs. If you don’t know the difference between -A and -I read up on it Here

That’s it for the memcache server. Now all you have to do is setup the web server to write the sessions to the correct place.

The Web Server

Again, this is assuming a stock Centos 5.5 server from Rackspace, so we have to install what we need.

Now you can test that php has the memcache module loaded in.

Look for memcache; it should be there.

Start apache and make it start on boot

Open up iptables on the websevrer:

Now we need to edit the php configuration file to tell it that we want to save sessions to memcache, and where our memcache server is. This file will be at /etc/php.ini.

Look for these 2 lines:

You will change these to (where 10.3.3.3 is your memcache servers IP address:

This simply tells php to write sessions to memcache and gives the address and port of the memcache server.

Now restart apache so that this will take effect:

All that is left to do now is test it. I created a file named sessiontest.php in /var/www/html that contains:

Start up a tcpdump on the memcaceh server listening for 11211:

Then access your test page at http://YourIpAddress/sessiontest.php. You will see that there is activity on the memcache server when the page is activated. If you really want to see the test in action, start up a 2nd web server with the exact same configuration, but change the script to:

You will see it echo out the session that was created on the 1st web server.

That about covers it, Leave a message if you have any questions!