This is one of those ‘I must be living under a rock’ things.  I’m not sure how I’ve never heard of TMUX before but it’s really pretty awesome.  I initially came across it when searching for a way to share a terminal session with another user.  It does that quite well but it’s also a great terminal session manager allowing for pane, window, and session management.  Let’s take a look at a quick example to show you what I mean.

Here we have a server called ‘tmuxtest’.  The server already has TMUX on it by default but if it’s not there you can easily install it (sudo apt-get install tmux, etc).  So let’s say I want to start a new session.  The easiest way to do this is to just type ‘tmux’..

Now we’re in TMUX.  We are in what’s called a ‘session’.  The session can contain multiple panes and multiple windows.  For instance, if I wanted to create a second pane I could do by pressing ‘Ctrl-b + %’…

Notice that the screen on the right, the new one, has a green boarder around it.  That’s my active screen.  Now if I want to split this screen horizontally I can use ‘Ctrl-b + “‘…

You might be figuring it out, but ‘Ctrl-b’ is the magic key sequence in TMUX.  Here’s a list of commands that relate to panes…

As you can see, we can select different panes pretty easily by using the arrow keys and end them as we typically end windows with ‘exit’.  So that’s all well and good, but that didnt buy us much.  What else is there?

Well before I forget, remember that we’re in a session that I can attach and detach to.  Have you ever needed to start a download on a remote server and worried about losing your connection and having the download crash?  I have!  So why not run it in a session?  Simply start a TMUX session, start the download, and then detach from the session (Cltrl-b d)…

Now I shut my laptop and go home.  When I get home, I get on VPN, log back into the server, and see that the download is still running (the size is increasing) and the TMUX session is still there which I can reconnect to…

I can reconnect to the session by using ‘tmux attach -t <session ID or name>’ which in this case is ‘3’…

Pretty cool huh?  Here are some commands that are relevant to dealing with sessions…

And before I get too far ahead of myself, I should talk about windows as well.  A session can have multiple windows.  For instance, if I start a TMUX session I can press ‘Ctrl-b c’ (I’ll do it twice)..

Notice how along the bottom I now have 3 sessions?  They’re labelled 0, 1, and 2.  I’m currently on the ‘2’ sessions which we can tell by the asterisk being next to it.  I can change between windows by pressing ‘Ctrl-b p’ or ‘Ctrl-b n’ which stand for previous and next.  Here are some other commands related to windows…

Ok – so now for the terminal sharing.  We know how to create a session and how to attach and detach from them.  Surprisingly, that’s all we need to know to share a session between two users using the same account.  For instance, let’s have two users log into the server both using the ‘user’ account. We’ll have the first user create a session called ‘watchme’ with the command ‘tmux new -s watchme’.  Now if we have another person log in to the same server, with the same user account, they can see that session by using ‘tmux ls’…

All the second user has to do is attach to that same session using the ‘tmux attach -t watchme’ command…

Pretty slick huh?  But what about if you have two different users on the same server?  Unfortunately, it’s not as easy to share sessions between multiple users, but it is still possible by creating a socket that both users can reach.  For instance, if we log into the same server with two different users we can see that by default user2 can’t see user1’s sessions…

However, we can specify a socket file for TMUX to use and make it accessible by both users like this…

Notice how we create the session under user1 as normal with the exception of passing a parameter to the ‘-S’ flag.  The ‘-S’ flag tells TMUX to create a socket at the specified location, in this case ‘/var/tmp/tmuxsocket’. Then I detach from the session, and change the permissions on the file so that all users can access it with the ‘chmod 777 /var/tmp/tmuxsocket’ command.  Now, user2 can see the session by telling TMUX where to look for the socket.  Is this secure?  Gosh no.  Is this probably something you should only do with another user that you fully trust?  Yes.  But if you fit that criteria, it’s drop dead simple to share a session.  That or you can both use the same account as we saw in the first example.

In any case – TMUX is pretty awesome.  I plan on making it a permanent addition to my toolbox.

Update: Ivan Pepelnjak reached out to me after this was published and suggested that it would make more sense to move the functions inside the defined class.  Doing this removes the functions from the global namespace and avoids the possibility of function names overlapping.  I think that’s a great idea so I’ve updated the examples below to align with this thinking.  Thanks Ivan!

I’ve been playing around with Ansible quite a bit lately.  One of the issues I’ve started to run into is that Ansible can’t always do what you want by default.  Put more plainly, Ansible can’t always easily do what you want.    Many times I found myself writing tasks to manipulate variables and thinking to myself, “Man – if I could just run some Python code on this it would be way easier”.  As luck would have it, you can!  Ansible supports a whole slew of plugins but the type I want to talk about today are called filter plugins.  Filter plugins, in my opinion, are one of the easiest ways to manipulate your variables with native Python.  And once you know how to do it you’ll see that it opens up a whole realm of possibilities in your playbooks.  Some of the most popular filters that exist today were once custom filters that someone wrote and then contributed to Ansible.  The IP address (ipaddr) filter set is a great example of filters that can be used to manipulate IP related information.

When I first looked into writing a custom filter I found the Ansible documentation not very helpful.  It essentially points you to their GitHub repo where you can look at the current filters.  Since I learn best by example, let’s write a quick filter so you can see how easy it is to do…

Nothing to it right?  This file defines a single filter called ‘a_filter’.  When called it receives the variable being passed into it (the variable to the left of the pipe (|)), appends the string ‘ CRAZY NEW FILTER’ to it, and then returns the new variable.  Now the trick is where to put this file.  For now, let’s create a folder called ‘filter_plugins’ in the same location as your playbook.  So in my case, the file structure would look like this…

/home/user/my_playbook.yml
/home/user/filter_plugins/my_filters.py

So let’s go ahead and create a quick little test playbook too…

This is a pretty simply playbook.  All it does is use the debug module to output a variable.  However, note that instead of just outputting the word ‘test’, we’re wrapping it in double curly braces like we do for any normal Ansible variable and we’re also piping it to ‘a_filter’.   The piping piece is what’s typically used to pass the variable to any of the predefined, or built-in, filters.  In this case, we’re piping the variable to our own custom filter.

This playbook assumes that you’ve told Ansible to use a local connection when talking to the locahost.  To do this, you need to set the ‘ansible_connection’ variable for the localhost to ‘local’ in your Ansible host file…

Once this is set, and you have both the playbook and the filter files in place, we can try running the playbook…

As you can see, the filter worked as expected.  The variable ‘test’ was passed to our custom filter where it was then modified and returned.  Pretty slick huh?  This is a uber simple example but it shows just how easy it is to inject custom Python functionality into your playbooks.  You’ll notice that in this example, there was only one variable passed to our function.  In this case, it was the variable to the left of the pipe.  In the case of filters, that will always be your first variable however, you can always add more.  For instance, let’s add a new filter to our function like this…

There are a couple of interesting things to point out in our new my_filters.py file.  First off – you’ll notice that we added another Python function called ‘b_filter’.  Its worthwhile to point out that your filter names don’t need to match your function names.  Down in the filters function at the bottom you’ll notice that we map the filter name ‘another_filter’ to the Python function ‘b_filter’.  You’ll also notice that the function b_filter takes 3 arguments.  The first will be the variable to the left of the pipe and the remaining need to be passed directly to the function as we’d normally pass variables.  For example…

Here you can see that we pass the second and third variables to the filter just like we’d normally pass variables to a function.  And while these examples only show doing this with strings, you can pass many other Python data types such as lists and dicts as well.

Lastly – I want to talk about the location of the filters.  By default, Ansible will look in the directory your playbook is located for a folder called ‘filter_plugins’ and load any filters it finds in that folder.  While this works, I don’t particularly care for this as I find it confusing for when you’re moving around playbooks.  I prefer to tell Ansible to look elsewhere for the filters.  To do this, we can edit the /etc/ansible/ansible.cfg file and uncomment and update the ‘filter_plugins’ parameter with your new location.

As you can see, filter plugins make it ridiculously easy to get your variables into native Python for manipulation.  Keep in mind that there are LOTS of default filter plugins so before you go crazy search the documentation to see if what you want already exists.

imageAs many of you have noticed I’ve been neglecting the blog for past few months.  The main reason for this is that the majority of my free time was being spent generating content for a new book.  I’m pleased to announce that the book, Docker Networking Cookbook, has now been released! 

Here’s a brief description of the book…

“Networking functionality in Docker has changed considerably since its first release, evolving to offer a rich set of built-in networking features, as well as an extensible plugin model allowing for a wide variety of networking functionality. This book explores Docker networking capabilities from end to end. Begin by examining the building blocks used by Docker to implement fundamental containing networking before learning how to consume built-in networking constructs as well as custom networks you create on your own. Next, explore common third-party networking plugins, including detailed information on how these plugins inter-operate with the Docker engine. Consider available options for securing container networks, as well as a process for troubleshooting container connectivity.  Finally, examine advanced Docker networking functions and their relevant use cases, tying together everything you need to succeed with your own projects.”

The book is available from Packt and I believe Amazon has it as well.  If you happen to buy a copy I would greatly appreciate it if you would send me any and all feedback you have.  This is my first attempt at writing a book so any feedback and critiques you can share would be really great.

A big thank you to all of the folks at Packt that made this possible and worked with me through the editing and publishing process.  I’d also like to thank the technical reviewer Francisco Souza for his review. 

Now that the book is published I look forward to spending my free time blogging again.  Thanks for hanging in there!

Tags:

« Older entries