12

Our saltstack is based on hostnames (webN., dbN., etc.). But for various things I need IPs of those servers. For now I had them stored in pillars, but the number of places I need to sync grows.

I tried to use publish + network.ip_addrs, but that kinda sucks, because it needs to do the whole salt-roundtrip just to resolve a hostname. Also it's dependent on the minions responding. Therefore I'm looking for a way to resolve hostname to IP in templates.

I assume that I could write a module for it somehow, but my python skills are very limited.

Tomáš Fejfar
  • 11,129
  • 8
  • 54
  • 82

7 Answers7

12

You could use a custom grain. Create file _grains/fqdn_ip.py in the state tree directory:

import socket

def fqdn_ip():
    return {
        'fqdn_ip': socket.gethostbyname(socket.getfqdn())
    }

In template:

{{ grains.fqdn_ip }}

Another way is use dnsutil module (requires dig command on minion):

{{ salt['dnsutil.A']('host.name.tld')[0] }}
kubus
  • 783
  • 6
  • 11
  • 1
    That would return the ip of the machine the salt is running on, right? That's not exactly what I need. I need to resolve arbitary hostnames like `{{ host2ip(pillar.db.hostname) }}`. – Tomáš Fejfar Aug 22 '13 at 10:45
  • I add another way to the answer. – kubus Aug 22 '13 at 11:08
  • Also, you can create [macros](http://docs.saltstack.com/ref/renderers/all/salt.renderers.jinja.html#macros) host2ip – kubus Aug 22 '13 at 11:09
  • In the end I used my copy-paste-fu with a grain of common-dev-sense and created a module, that uses `socket.gethostbyname`, which works like I need - problem with dnsutil would be it does not respect `/etc/hosts` which I need. – Tomáš Fejfar Aug 22 '13 at 15:26
  • `socket.gethostbyname` _may_ be vulnerable to being exploited using [GHOST](https://nakedsecurity.sophos.com/2015/01/29/the-ghost-vulnerability-what-you-need-to-know/). It would be advisable to use `socket.getaddrinfo` which is not vulnerable and works for IPv4 and IPv6 – RedBaron Dec 21 '16 at 12:25
5

I've see this: http://cnygaard.blogspot.com.es/2012/11/how-to-template-eth0-address-with.html

This is the easy way that I've found.

#init.sls:

...
...

/etc/swift/proxy-server.conf:              
   file:
     - managed                              
     - source: salt://swift/proxy-server.conf
     - template: jinja
     - context:
         proxy_ip: {{ salt['network.interfaces']()['eth0']['inet'][0]['address'] }}

And then:

#In proxy-server.conf

...

[filter:cache]
use = egg:swift#memcache
memcache_servers = {{ proxy_ip }}:11211
José Ibañez
  • 652
  • 8
  • 10
4

This is a very old post, but it is highly ranked in Google for getting the ipv4 address. As of salt 2015.5.8, the best way to get the primary ipv4 address is {{ grains['ipv4'][0] }}.

Andrey
  • 485
  • 3
  • 17
  • 1
    Could you please explain more thoroughly what you mean by {{ grains['ipv4'][0] }} ? – J Fabian Meier May 13 '16 at 12:48
  • That it's first entry in the ipv4 key in grains (https://docs.saltstack.com/en/latest/topics/targeting/grains.html) - obviously, you can access it any way you want ;) – Tomáš Fejfar May 14 '16 at 17:44
  • In salt, grains is an array of values (or hashmap or similar). Using the 'ipv4' grain, you can access all IPv4 addresses on the minion. For my purpose, I need the primary IPv4 address or the 0th entry. – David Meiser Jun 07 '16 at 15:14
2

Reading through the ansible documentation, I found a much simpler solution. Here are my results.

enter the following into the template:

lookup hostname: {{ lookup('dig', 'google.ca.') }}

My jinja2 template:

# mytemplate.j2
## lookup directly
lookup hostname: {{ lookup('dig', 'google.ca.') }}

## in a variable
{% set fqdn = 'google.ca' %}
lookup hostname: {{ lookup('dig', fqdn) }}

Result:

# mytemplate.j2
## lookup directly
lookup hostname: 172.217.2.163

## in a variable
lookup hostname: 172.217.2.163
Bhav
  • 21
  • 2
1

Currently - to aggregate a list of all ip addresses requires either salt-mine or interrogating all minions. I prefer salt-mine.

There is an accepted issue to extend the new roster system to maintain addresses of all minions, not just ssh based hosts. https://github.com/saltstack/salt/issues/7759

Dan Garthwaite
  • 3,436
  • 4
  • 22
  • 32
0

Just a reminder, you always can pass it from Flask app.

import os

host = os.uname()[1]

return render_template("template.html", host=host)
easai
  • 71
  • 1
  • 6
0

If you need to get IPs that are not available in grains, do not want to setup custom grains and need those IPs to be dynamically resolved in your pillars ( typically to setup the firewall, network interfaces, BGP to the host, etc. ) you can proceed as follow:

Let's say you have:

  • idrac-hostname.domain
  • management-hostname.domain
  • hostname.domain

Then you can just resolv them using the dig modules from SaltStack

{% set fqdn = salt['grains.get']('fqdn') %}
{% set idrac = 'idrac-' ~ fqdn %}

{% set idrac_ip = salt['dig.A'](idrac)[0] %}
{% set main_ip = salt['dig.A'](fqdn)[0] %}

Hope it helps

Ref: https://docs.saltproject.io/en/latest/ref/modules/all/salt.modules.dig.html

rilCy
  • 413
  • 4
  • 11