Non-capturing groups in regular expressions

In one of my recent merge requests, someone suggested to use non-capturing group to simplify one of my regular expressions. I haven’t heard of those before, so I hit up the search bar.

Turns out, non-capturing groups use this syntax (?:foobar). And unlike normal groups, they donot store reference to the matched content. That makes them perfect when you just want to specify a quantifier for a group.

I am definitely going to start using them often now. It’s moments like these, that make me love code reviews. No matter how much you think know, there is always someone dropping knowledge bombs.

For more regular expression tips, check out my lookbehind assertions example and Mozilla’s Regular Expressions Cheet Sheet.

Level Up Your YAML: Tips For Advanced Usage

Leveraged by tools such Ansible & Kubernetes, YAML has become a ubiqitous configuration format over the last decade. It owes its high adoption rate can be attributed to its simple design. It is consise yet readable, thanks to its minimal use of syntactical marks. However, under the surface it is surprisingly complex. This post aims to introduce some of its features you might not be aware of.

Read more…

Chaining Comparisons in Python and Rust

I love chaining comparisons in Python. Not only are expressions like a < b < c terser, but I also find them more readable than the alternative (a < b and b < c). So when I started coding in Rust, I wanted something similar.

Limitation in Rust

Unfortunately, Rust does not support chaining operators. The arguments are revolving around cases where the interpretation would not be obvious (a != b != c), or situations where they they could potentially decrease readability when used incorrectly. Those are fair points. But luckily, there are alternative approaches to achieve the same goals in Rust.

Read more…

Why I Prefer Vim to Neovim

Vim needs no introduction. However, what you might not be aware of is that there was a period when its development was stagnant. To address this issue, Neovim was born with the goal of creating an easier-to-maintain codebase, encouraging more community involvement, and adopting new features more rapidly. It made quite a splash several years ago.

After reading about Neovim for years, I finally decided to give it a try. The promises were enticing - faster plugins thanks to Lua, improved responsiveness, better syntax highlighting, and more. Once I started using it, I immediately noticed a snappier performance, more sensible default, and effortless pasting without needing to enable :paste. Impressed, I began adapting my vimrc to Neovim and sought Lua alternatives for the plugins I had used.

Read more…

ansible_user Is Undefined on Localhost

I rely on Ansible for configuring my workstation, so I can easily synchronize it across multiple computer. However, I recently ran into an intriguing issue when my playbook failed with the following error after adding a third-party role:

'ansible_user' is undefined

This puzzled me, because by default all ansible_* variables should be automatically populated, unless gather_facts has been explicitly disabled. It turns out that this behavior does not apply for ansible_user, if you run the playbook on localhost with a local connection instead of SSH.

Read more…

Powerline does not play nice with Tmux

Tmux has been an invaluable tool for me over the years. If you haven’t come across it before, Tmux is akin to a window manager for your terminal. It allows you to create multiple tabs, split windows into panes, and, most notably, keeps your remote sessions alive even after you disconnect.

I am also a fan of Powerline, the fancy status line for Vim, shell prompt and other applications. So, I naturally wanted to use it for my Tmux status line. But to my great surprise, it did not work as expected.

Read more…

Create Terraform Array In a Loop

The other day, I needed to create a multi-SAN TLS certificate in Terraform. The DNS names ended in a number sequence, so you could easily create them in a loop. Now, Terraform has count & for_each loop to create multiple resources. But what if you want to create a variable in a loop? (I am sure some people are screaming Pulumi now.)

Luckily, Terraform has null_resource available, which is exactly what I needed. It creates a virtual resource with a map of strings. So, you can define it in a loop and then use the result to declare a variable.

Here’s example code:

locals {
  dns_sans = null_resource.dns_sans[*].triggers.dns_name
}

resource "null_resource" "dns_sans" {
  count = var.replicas

  triggers = {
    dns_name = "service-${count.index}.service-internal"
  }
}

This made my life easier. Maybe it will make yours too.

Start AWX Job Via API

If you are using Ansible, there is high change you are also using AWX (or Ansible Tower) to orchestrate your jobs. And you might want trigger AWX jobs externally in some cases, such as from your CI pipeline. Luckily, AWX has an API that allows you to do just that.

To run AWX jobs remotely, you will need to make 3 API calls. One to start the job itself, another one to monitor its progress and lastly a request to print the output. You can see sample code to do that in bash shell below. In order to keep things simple, it uses authentication token, but you could also use OAuth 2.

POLLING_SLEEP=30

function print_job_output() {
  api_request GET "/jobs/${id}/stdout/?format=txt"
}

response=$(
  curl -s -i -o - "${AWX_API}/job_templates/${TEMPLATE_ID}/launch/" \
    -H "Authorization: Bearer ${API_TOKEN}" \
    -H "Content-Type: application/json" \
    -XPOST
)

http_status=$(head -n 1 <<<"${response}" | awk '{print $2}')
body=$(grep '^{' <<<"${response}")

if [[ ${http_status} != 201 ]]; then
  echo "AWX returned error."
  exit 1
fi

id=$(jq <<<"${body}" '.id')
echo "Monitoring job ID: ${id}"
while true; do
  echo "Sleeping for ${POLLING_SLEEP}s"
  sleep $POLLING_SLEEP

  response="$(api_request GET "/jobs/${id}/" -i)"

  http_status=$(head -n 1 <<<"${response}" | awk '{print $2}')
  body=$(grep '^{' <<<"${response}")
  if [[ ${http_status} != 200 ]]; then
    echo "AWX returned error."
    exit 1
  fi

  status="$(jq -r '.status' <<<"${body}")"
  if [[ "${status}" == "failed" ]]; then
    echo "Job failed."
    print_job_output
    exit 1
  elif [[ "${status}" == "successful" ]]; then
    echo "Job has finished successfully."
    print_job_output
    exit 0
  fi
done

Postfix SASL authentication in Alpine Linux

Most of the popular Postfix Docker images assume that you run the service as a local SMTP forwarder. Therefore, they do not bother with authentication. So, if you want to use Postfix as your central mail sending agent, you need to roll your own. This post will walk you through the setup of Postfix with SASL authentication on Alpine Linux, my container distro of choice.

Read more…

Choosing the Right Programming Font

, updated

Programmers and other IT professionals often customize their desktops to increase productivity. However, fonts often remains overlooked. Since you spend around 8-10 hours per day staring at a screen, it is an important choice. The right font increases legibility. That in turn helps battling eye fatigue and lowers the risk of typos (which can lead to nasty bugs). This article compares some of the most popular programming fonts.

Criteria for choosing a font

First of all, a programming font should be monospace. I don’t think this needs much explanation. The main reason is for structures in code to be aligned.

As mentioned above, the font should also be legible. Especially characters that are easily confused, such as lowercase l and uppercase I. To compare the various fonts, I am using a modified programming font test pattern from Martinus. It looks like this:

o0O s5S z2Z qg9 !|l1Iij {([|])} .,;: ``''""
a@#* vVuUwW <>;^°=-~ öÖüÜäÄßµ \/\/ -- == __
the quick brown fox jumps over the lazy dog
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
0123456789 &-+@ for (int i=0; i<=j; ++i) {}

Last, but not least, you should consider the license. As more people use some mix of Linux, Windows and MacOS to do their work, I have picked only open-source fonts. You can easily get those on any OS. This disqualifies some popular choices, such as Consolas and Menlo.

Read more…