Codementor Events

Quick Access to Your Production Rails Console

Published Sep 10, 2017
Quick Access to Your Production Rails Console

Back when I was a dev manager, I used to monotonously perform the same sequence of terminal commands about 5 times a day: ssh into a particular host, sudo su to a user with correct permissions, cd to a project, and then open up rails console or hbase shell. I did this so many times it became second nature to me. Whenever my product guy had a problem, in order to save my team from potential distractions, I'd say "Alright, let me look at HBase real quick, we'll figure it out" or "Oh I can fix that user's account, hold on."

Being an engineer, this kind of repetitive sequence drove me nuts and I quickly got tired of it. I set out to automate as much of the process to get to a production shell prompt as soon as possible and that’s when I came across expect.

expect is a handy tool that allows you to write scripts against interactive text interfaces, which means you can automate a simple workflow like ssh'ing into a host and run commands against it. It fits perfectly — below I'll share with you an abstract version of my production rails console script and another one I just developed to get into Rails console in a Docker environment.


A productionrails console session spun up in a couple seconds!

Traditionally Hosted Scenario

Sharing the code for these scripts will help explain a lot, so I’m going to start off with that:

#!/usr/bin/expect -f
# prod_railsc.sh <hostname - optional>

set hostname [lindex $argv 0]
set default_hostname $YOUR_PRIMARY_RAILS_HOST_HERE
set prompt "$ " # This may be $ or # or something else dependent on host environment. Change accordingly.

if {$hostname != ""} {
  spawn ssh $hostname
} else {
  spawn ssh $default_hostname
}

expect $prompt

# NOTE: You might not need this step if the user you ssh in as has Rails available.
send "sudo su $USER_WHO_HAS_ACCESS_TO_RAILS_GEMS\r"
expect $prompt

send "cd $RAILS_PROJECT_DIRECTORY\r"
expect $prompt

send "rails console\r"
expect "irb(main):001:0> "

interact

The above is doing what we’ve discussed: ssh’ing into a host, changing to a different user, changing directories, and then opening up a rails console session. The way this works is that expect creates a new process (via spawn) for the ssh session and then issues (send) commands against that ssh process, 'expecting' (expect) certain output from those responses.

If what it expects doesn't match up after a certain time has passed, it'll exit. Otherwise, it'll proceed through these steps and will finally get to our interact command, which brings the spawned process to the foreground and allows us to take over the session.

Ta-da, we've got a remote rails console and it only takes a few seconds and much less typing!

Docker Hosted Scenario

The reason I got back into thinking about these expect scripts again is due to Docker. I have a Dockerized Rails application that I was putting it into production with AWS Elastic Beanstalk and was updating the README with instructions on how to open rails console in that environment. While writing them I was thinking to myself, “Well, this is going to be a PITA”, so I figured I could adapt my old prod_railsc.sh script to the task. This is what I ended up with:

#!/usr/bin/expect -f
# prod_railsc.sh <hostname - optional>

set hostname [lindex $argv 0]
set default_hostname $YOUR_EBS_HOST_HERE

if {$hostname != ""} {
  spawn ssh $hostname
} else {
  spawn ssh $default_hostname
}

expect "$"

send "sudo su - root\r"
expect "#"

set image_id_cmd "docker images -q | head -n 1"

send "$image_id_cmd\r"
expect "$image_id_cmd\r\n"
expect -re "(.*)\r\n(.*) "

set image_id $expect_out(1,string)

# Run a interactive Docker command against our image to kick off rails console.
send "docker run -it --rm $image_id rails console\r"
expect "irb(main):001:0> "

interact

This code performs everything very similar to our first script, except we now have to fetch the Image ID of the Rails Docker image before we can run the rails console command against it. expect allows us to use regular expressions to pull out specific output from our previous command, which we used above in the expect -re "(.*)\r\n(.*) " line. We then pull out the image_id variable and used that in our docker run command. This only works in Single Container nodes, but it could be adapted pretty easily if you're running other services on the same host.

Wrapping Up

We’ve got ourselves a fast, automated way to access rails console in both traditionally hosted and Docker hosted rail's environments. If you're interacting with your Rails instance in production to pull important database information, administer data, or even kick off one-time jobs then this script can save you time in the long run!

If you have an improvement or a better way of accessing your production shell, I would love to hear about it in the comments!


About: Matt Gowie runs Masterpoint, a small consulting shop creating high-quality software on the web using technologies like Ruby on Rails and Emberjs.

This post was originally published by the author here. This version has been edited for clarity and may appear different from the original post.

Discover and read more posts from Matt Gowie
get started
post commentsBe the first to share your opinion
Show more replies