Displaying Docker containers and their history with Go
What Changed?
Finally, the program maintains in its right subwindow a history log of all containers that appear and later go away. For this, Listing 4 compares two string array slices in the diff()
function and determines which new entries have been added in the second array and which entries are in the first array but have not made it into the second.
Unix experts know the procedure from the diff
tool, which also displays the difference between two files in terms of lines that have either been added or omitted. Figure 2 illustrates that diff
correctly finds out that the bar
and zap
entries have been removed from the test1.txt
file and that the pow
entry has been added to test2.txt
.
Smart Algorithm
How does the diff
algorithm work? The basis is the longest common subsequence (LCS) procedure [6], which determines the longest common partial sequence of two arrays. A naive approach could simply delete all entries from the first array and add all items of the second array to arrive at the result. But that's not the point: It's about getting from A to B with as few steps as possible.
The LCS method provides a series of identical positions in both strings. In this way, it determines that the first entry foo
occurs at the same position in both strings. The baz
entry, on the other hand, has been shifted: In the first string, it is at the third position; in the second, it is at the second position (index (2,1)). The LCS algorithm therefore outputs the pairs (0,0),(2,1) when comparing the files test1.txt
and test2.txt
, as shown in Figure 3.
Listing 4 retrieves the LCS algorithm from the golcs
project on GitHub. From the delivered pairs, the code calculates container names to add
and to remove
. In order to move from the last list to the current one, it traverses the old and new arrays (left
and right
) step by step using for
loops, while moving from pair to pair.
One difficulty here is the strict type system in Go: The LCS algorithm on GitHub was implemented with a generic type (interface{}
), similar to void
in C, because it is supposed to be able to analyze data of any type. To be able to process arrays of strings, however, the programmer needs to convert them into arrays of interface{}
types first, which is laborious and time-consuming. Otherwise the compiler refuses to call the library function. The reason given by Go followers is that strings have a different memory layout than interface{}
types. This mess will hopefully be resolved by the next Go version.
Conclusions and Outlook
Granted, the procedure for determining the Docker history is not 100 percent accurate. Between two queries, the Docker daemon could have created a container that disappeared on the second call. A ghost container of this kind could only be detected by a subscription mechanism that would receive a message from the Docker daemon on each event. Maybe I'll add it in the next iteration of this project.
The procedure is still good enough to observe appearing and vanishing containers and will help to detect any irregularities. Since it is a DIY program, there are no limits to the developer's creativity: Click on a displayed container and it shuts down? Sort by alphabetical order rather than by start date? Make missing containers red and new ones green? As always, the solution is just a few keystrokes away.
Infos
- "A Go terminal UI for displaying network adapters in real time" by Mike Schilli, Linux Magazine, issue 218, January 2019, pp. 42-45
- "Calculating weekdays and dates with Go" by Mike Schilli, Linux Magazine issue 227, October 2019, pp. 44-47
- "Go program stores directory paths" by Mike Schilli, Linux Magazine, issue 228, November 2019, pp. 42-45
- Listings for this article: ftp://ftp.linux-magazine.com/pub/listings/linux-magazine.com/231/
- Docker Client API: https://godoc.org/github.com/docker/docker/client#Client
- LCS: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
« Previous 1 2
Buy this article as PDF
(incl. VAT)