Changing your Ruby version

Sometimes you’ll need different versions of Ruby for different projects. chruby allows you to have multiple versions at once and choose which one to use at any given time. This tutorial will assume you are on a mac (sorry Linux and Windows users). First install ruby-install and chruby.

brew install chruby --HEAD
brew install ruby-install --HEAD

Then install the needed version of Ruby. Let’s assume you need 2.3.1.

ruby-install ruby 2.3.1

Now change to that version of Ruby. If you use the command chruby you won’t see the new version in the list of versions you have until you restart your shell. So let’s restart your shell to refresh your list of Ruby versions displayed by chruby.

exec bash -l

Now if you use chruby you will see the version you just downloaded. So now you can switch to that version.

chruby 2.3.1

But your gems will still be on the old version. Let’s get the gems for the new version.

gem install bundler

Now let’s install the gems for 2.3.1.

bundle

And that’s it. You should be all set with your new version of Ruby. If you want to change back to another version of Ruby that you have installed you should not have to repeat the bundle commands.

Advertisements

Ways to handle terraform variables

There are 3 ways you can use terraform commands. It works the same whether you use destroy, plan, or apply. We’ll just use terraform apply in this post.

Each command requires variables. So when we say “3 ways to run these commands” we really mean 3 ways to handle the variables.

Way One: prompt

$ terraform apply

This command does not pass any variables so you will be prompted for things like you access key and secret key and stuff like that. You can simply answer the prompts and the command will run.

Way Two: arguments

$ terraform apply -var "access_key=ADfakdjafioauvuasvjekjfjd"

If you have several variables to pass then you can use a backslash to go to a new line.

$ terraform apply \
-var "access_key=DAJFKEJfkajdfiadlajkjf823" \
-var "key_name=my_key" \
-var "last_var=foobar"

You can use this method to override variables (if you have them defined elsewhere)

Way Three: terraform.tfvars

$ vim terraform.tfvars

access_key = "DAJFKEJfkajdfiadlajkjf823" 
key_name = "my_key" 
last_var = "foobar"

Then you can simply run terraform apply with no arguments and no prompts.

Also keep in mind that you can use environmnt variables for any of these.

$ export DO_PAT={YOUR_PERSONAL_ACCESS_TOKEN}

Then in your command $ terraform apply -var "do_token=${DO_PAT}"

This is just the tip of the iceberg when it comes to variables in Terraform. You can import them from modules and other places, but I won't cover that here...maybe I'll add it later or do another post about it.

Agent forwarding

Agent forwarding is a security measure in which you have to go through a preliminary server in order to get the server that you really need to reach. The Server being protected will not have a public IP address. You must ssh into the preliminary server with that servers public IP and then from there ssh into the protected server using it’s private IP. Let’s see what that looks like.

$ eval ssh-agent
...
$ ssh-add ~/.ssh/id_rsa
Identity added: /Users/user/.ssh/id_rsa (/Users/user/.ssh/id_rsa)
$ ssh -A -i ~/.ssh/id_rsa ubuntu@
...
ubuntu:~$ ssh ubuntu@

~/.ssh/id_rsa is the most common path for private keys, but if you have your private key somewhere else then you need to use that path instead. the -A option on the ssh command is what enables agent-forwarding. The -i (identity_file) command is what allows you to include the path to your private key.

UPDATE: It appears that if you do the ssh-agent and ssh-add commands then you will not need the -i ~/.ssh/id_rsa part of the command.

Bash Dates

Dates can be very simple in bash. the date command will output the date.

$ date
Wed Jul 19 13:45:03 UTC 2017

To format the date use the following:

%m for month
%d for day
%Y for year
%H for hours
%M for minutes
%S for seconds

You precede any formatting with a plus sign and can use the above symbols to format the date any way you like.

$ date +%m-%d-%Y
07-19-2017
$date +%m/%d/%Y
07/19/2017

If you are going to have spaces then you need to put it in quotes

$ date "+%m-%d-%Y %H:%M:%S"
07-19-2017 08:48:24

Put the date in a specific time zone with TZ.

TZ="America/Chicago" date

This has been a quick-n-dirty guide to dates in bash

Intro to Bash Scripting

Knowing Bash is a very useful because it’s available on any Unix system. And when you are dealing with servers you have to use it a lot. Bash scripts can be as simple as a list of commands or be complicated with lots of functions and logic. Anything you can do in a terminal you can do in a Bash script and vice versa. This will be a very basic intro. It will show how to declare and use variables, make and use functions, and use if-else statements. But we’re gonna start with the hello world bash script.

Hello World

You can make a script and run it with one command if you want.

$ echo "echo hello world" > helloworld && sh helloworld
hello world

Above we are putting the output of echo "echo hello world" into a file called helloworld, and then (if that is successful) we run the sh program with our file as an argument. Now this is the laziest way to do it. We should at least call our file helloworld.sh so we know it’s a bash script. But better practice would be also including the interpreter at the top and making the script executable. Then we can run it by itself.

$ vim helloworld.sh

#!/bin/bash

echo hello world

$ chmod +x helloworld.sh
$ ./helloworld.sh
hello world

running a script with sh will work regardless of permissions. To run the script directly then you will need to make it executable. (I’ve had weird errors with one way and not the other so if that happens just use whichever way works)

Variables

Variable declarations are pretty simple. Type the name of the variable then the equal sign then what the variable will be. When you use the variable you precede it with a dollar sign.

foo="bar"
echo $foo

The biggest mistake people make when declaring variables is that they put space around the equal sign. There must be no space.

Functions

foo() {
  echo "bar"
}

The code of above declares a function. Even though it looks like a function you’d see in other languages like javascript it doesn’t behave that way. It has parenthesis, but no parameters will go there, and you don’t call a function with parenthesis either. You can call the function simply by typing the name. This is how it would work with arguments.

#foobar.sh

function foo () {
  echo $1
}

foo bar

$ sh foobar.sh
bar

if-else Statements

if [[ 1 == 1 ]]; then
  echo "one equals one!"
else
  echo "somehow one does not equal one"
fi

And alternate way to write an if-else is:

if [[ 1 == 1 ]]
then
  echo "one equals one!"
else
  echo "somehow one does not equal one"
fi

I prefer the former.

You can use only 1 bracket for the if statement instead of 2, but double brackets are newer syntax and preferred. They have worked better in my experience.

Here’s some other things to keep in mind when using if statemenets.

  1. Must have a space after [ and before ]
  2. It is recommended that you put double quotes around variable names in if tests when using only one bracket. That way if the variable doesn’t exist then it will be an empty string. If you don’t have the double quotes then you will get some unexpected behavior if the variable is empyt.
  3. Must use : as a placeholder for empty bodies

Arithmetic

Any variable that involves arithmetic must be preceded with let.
Screen Shot 2017-07-20 at 3.37.02 PM
That’s it for now. I’ll do another post on dates in Bash later.

Case Statement

var=$1

case $var in
foo)
  echo foo
  ;;
bar | blah)
  echo "bar or blah"
  ;;
*)
  echo dunno
  ;;
esac

Git Reverting!

I used to think revert would get you back to the state when a given commit was submitted. It does not. Instead it simply undo’s the given commit. To do the former, you have to use reset instead.

git reset --hard HEAD~5

Will take you back to the state of the repo 5 commits ago. If you have uncommited work you want left alone then use --soft instead of --hard. git revert undo’s the commit who’s hash was given, and makes new commit with the changes that undo that given commit.

If it’s a merged commit then you have to use the -m option (for merge) along with either a 1 or a 2. 1, meaning you want to take it back to the state of the remote parent. 2 meaning you want to take it back to the state of your local parent. (I usually use 1. I trust remote more than myself)

If anything goes wrong when you try to revert use git cherry-pick --abort and try again.

Sometimes you may have to merge. If anything goes wrong with the merge you can use git merge --abort and start over.

So let’s go through this with a realistic (but hopefully not common) scenario. Let’s say some bad code went live. You’re on your site and notice something terribly wrong. Don’t fret! Let’s say you did a recent push and you think you know which commit has the problem, but don’t want to take the time to debug it while your live app is in a bad state. Here’s what you do (assuming you are up-to-date on your master branch).

$ get checkout -b revert-branch
$ get revert
$ git push origin revert-branch

Above we are checking out a new branch, undoing the bad commit, and pushing the branch up. You can find the hash of the bad commit on Github or with git log. git revert will put you in your default text editor with the commit message “revert “, so all you have to do is save and quit (:wq if the editor is vi or vim) and you’re ready to push up. Then pull the pr in and update the site and you’re in the clear!

That’s what you do if you’ve royally screwed up live, but sometimes you mess up your local branch beyond repair and you just want to start over with whatever is in the remote master branch. If that’s the case run the below command.

git reset --hard origin/master

that will simply replace your current branch with the origin/master branch. If your remote is named something else besides origin, such as upstream then instead of origin/master, you’d use upstream/master. You can check double check what your remote is named with git remote -v.

Getting started with tmuxinator

Tmuxinator is a way to easily manage tmux sessions. This guide will assume you have tmux and ruby gems installed.

Start by installing tmuxinator.

gem install tmuxinator

Tmuxinator will use you default editor so make sure it’s set.

export EDITOR=vim

Find where the tmuxinator executable was saved.

find . -name tmuxinator 2>&1 | grep -v "Permission denied"

The above command finds any file or directory named “tmuxinator” and pipes the output to a grep that leaves out any results that contain “Permission denied”

When you find the path to the tmuxinator command then add it to your $PATH. I keep my path in .bash_profile, but you can update your path with the following command.

export PATH=$PATH:path/to/tmuxinator

If you do have a ~/.bash_profile or ~/.bashrc file that you want to use then you can add the above line to it. You can also set an alias for tmuxinator there since it’s kind of long.

alias mux='tmuxinator'

add the above line to your .bash_profile and run source ~/.bash_profile to refresh your environment. (This didn’t quite work for me the first time. You may have to restart your terminal)
Now let’s make a new tmux session (I know we just made an alias, but for clarity’s sake, I’m going to use the full command name)

tmuxinator new foo

If you set your default editor above it should open up a yml file in your default text editor. Have a look around the file. We’ll keep it the way it is for now. Save and quite when you are done checking it out. Now in the terminal you can run this session with the following command.

tmuxinator foo

It’s as simple as that! You can use bind s to switch between sessions. bind is the key combination that you will use to do basically all tmux commands. The default is ctrl-b I believe. So ctrl-b s will let you switch between session. foo may be your only session unless you opened up a default session before you opened foo. If foo is your only session then this won’t be meaningful, but imagine you have a whole list of sessions. To be able to quickly choose another session you may want to use j and k instead of the arrows keys (vim style). To do that you may have to add the following line to ~/.tmux.conf.

set-window-option -g mode-keys vi

Restart tmux to make it go into effect. Command-t exits tmux (I found that out on accident), but if that doesn’t work you may have to kill your tmux processes and then start tmux again. See my post about killing processes here.

Being able to use vi commands will also be helpful when you use bind [. This command will allow you to traverse output. Let’s say you are compiling your code or running a server and it errors, but the pane is too small to show all of it. bind [ will allow you to move up in the window to see the above output. If you have your mode-keys set to vi then you can use j, k, h, and l to move around the output.

You can kill your session with command

tmux kill-session -t foo

You can use command-line arguments in your yml session files.

#~/.tmuxinator/foo.yml

name: foo
root: ~/

...

tmuxinator foo bar will open up a session and place you in the ~/bar directory.

There are a few handy things you may want to add to your ~/.tmux.conf

bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

bind J resize-pane -D 5
bind K resize-pane -U 5
bind H resize-pane -L 5
bind L resize-pane -R 5

In tmux you can do commands that change your environment with bind :
select-pane -D and resize-pane -D 5 (can also just be resize-p) are the type of commands you can do in your window with bind :
the above lines make those commands possible with quick hot keys so now instead of bind :resize-pane -D 5 to resize your pane you can simple do bind J. bind J will take you to the pane that left of the current pane (-L for left), and the following lines work the same way.

this is only the tip of the iceberg with tmux. You can find out more about tmuxinator and see other config files with the links below.

https://github.com/tmuxinator/tmuxinator
https://gist.github.com/spicycode/1229612

Testing Private Functions

I’m a big fan of test driven development, but until now I’ve never had a good way of testing private functions. For the purposes of this article, private functions are functions that are not exported.

//addService.js

const id = x => x
const add = (x, y) => x + y

module.exports = add

the id function is private since it’s not exported. The add function is public since it’s exported. If we were to test our module it would look something like this.

const expect = require ('chai').expect
const addService = require ('./addService.js')

describe ('add service', function () {
  
  it('should add', function (done) {
    const func = addService.add
    expect(func(1, 1)).to.equal(2)
  })
})

notice the const func = addService.add line. It’s possible to grab the add function because it’s exported. If we tried the same thing with the id function then it would be undefined. We could just export the id function also, but that’s not good practice. You don’t want to expose more than you have to. Luckily we don’t have to with Rewire. Rewire works exactly like require accept that it gets the private functions also. By using rewire we can test all our functions. Our tests would look something like this.

const expect = require ('chai').expect
const rewire = require ('rewire')
const addService = rewire ('./addService.js')

describe ('add service', function () {
  
  it('should add', function (done) {
    const func = addService.add
    expect(func(1, 1)).to.equal(2)
    done()
  })

  it('should return identity with id function', function (done) {
    const func = addService.__get__('id')
    expect(func(1)).to.equal(1)
    done()
  })
})

Notice instead of require ('./addService.js') We have rewire ('./addService.js'). We just substituted “rewire” for “require”. Rewire has a special getter function that allows it to get private variables. __get__ takes in a String, which is the name of the function or variable you want to get. So in our other test we can get the private function and test it like we would any exported function.

Please forgive the useless example here where we have the identity function that doesn’t do anything and it’s even used.

Fyi, this was not covered, but you will need mocha to run these tests.

npm install -g mocha
mocha nameoftestfile.js

This has been a quick-n-dirty guide to testing private functions from a module. You can see other solutions for this problem here https://stackoverflow.com/questions/22097603/unit-testing-of-private-functions-with-mocha-and-node-js and shout out to barwin for his answer, in which this blog was inspired by.

Killing a process

I was asked about killing a process in an interview and my answer was close, but not quite correct. I realized it wasn’t correct when I found myself actually having to do it just days later. Let’s say you have a node app running that you want to kill.

ps aux | grep "node"

ps aux will list all processes. We pipe it into grep to find our node process.

kill pid

The kill command kills the process. pid is a placeholder for the actual process id that we get from ps aux

This has been a quick-n-dirty guide to finding and killing a process.

UPDATE: I found an even easier way to kill processes. The pidof command will find the pid of a process. You may have to brew install pidof or apt-get install pidof if you don’t have it, but once you do then running the following command will show you the pid of your node app.

pidof node

This may give you multiple pid’s if multiple node apps are running. You can kill them all with one simple command.

kill $(pidof node)

UPDATE: Yet another very easy way to kill a process

$ pgrep node
93498
$ kill 93498

ES6 Destructuring

If you’ve ever dealt with functions that have a ton of arguments then you will appreciate this. Consider the following function

function foo (user, company, invoice, status, bar, stuff, things){ 
      //do some stuff with all thing things
}

According to Code Complete a function should never have more than 7 arguments. Here we have exactly 7, but it still seems like too many. Perhaps an args object would help.

 function foo (argsObject) {
      //do some stuff with all the things
}

That might look great, but in practice it’s usually like this:

 function foo (argsObject) {
      var user = argsObject.user;
      var company = argsObject.company;
      var invoice = argsObject.invoice;
      var status = argsObject.status;
      var bar = argsObject.bar;
      var stuff = argsObject.stuff;
      var things = argsObject.things;

      //do some stuff with all the things
}

Sheesh. We might as well go back to having a billion arguments. This is one instance where deconstruction can make our code a little cleaner. With ES6 destructuring we can do this

function foo (argsObject) {
  var {user, company, invoice, status, bar, stuff, things} 
    = argsObject

  //do some stuff with all the things
}

In the above code, your //do all the things section can look exactly like the first code snippet because you’ll be able to use all the variables with their normal names thanks to the destructuring.

You can test this concept out very easily.

var obj = { foo: 'bar' };
var { foo } = obj;

console.log(foo);

The output of this should be bar. If it’s not then you may be running an old version of JavaScript.

The same can be done the other way around. Instead of taking an object and getting vars out of it, we can take vars and get an object.

var foo = "foo";
function bar () { console.log("bar"); }

var obj = { foo, bar } //{ foo: "foo", bar: [Function: bar] }

This has been a quick-n-dirty guide to destructuring with ES6. You can find out what else you can do with destructuring here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment