Mapping strings into numbers in Ansible

George Shuklin
OpsOps
Published in
1 min readAug 12, 2019

A rather simple solution for a rather obscure problem: We have a set of strings and we want to map each string into number in a given range. Our range is a very special — it’s a list of non-privileged non-dynamic TCP ports [1024–49152].

So, our goal is to create a hash function from arbitrary string into fixed range of integers. Moreover, we need to make it stable, that means, that each time we pass the same string, we are getting the same number on every following run of Ansible.

Examples of the matching:

  • string1 — 6870
  • string_two — 46399
  • bar-bar — 33750
  • some string — 43305

The solution

(((item|md5)[-4:]| int(0, 16))/1.4 + 1024)|int

Explanation:

  • item — our variable with a string to map
  • md5 — a filter which produces md5 hash
  • [-4:] — takes last for character of the string
  • |int(0,16) — converts those 4 characters from hex to int (range [0–65535]).
  • /1.4 — a special coefficient. I calculated it as roundup from 65535.0/(49152–1024).
  • +1024 — shift values into desired range.
  • final |int strips away any fractional remains after division.

The example:

- hosts: localhost
gather_facts: no
tasks:
- debug: msg="Hash for {{ item }} is {{ (((item |md5)[-4:]| int(0, 16))/1.4 + 1024)|int }}"
with_items:
- string1
- string_two
- bar-bar
- some string

Update: there is a better solution

I just can’t compete with SO hivemind. Here is a really good solution, from this answer:

range(1000, 37272) | random(seed=item)

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.