Search code examples
pythonnetmiko

Why Netmiko does not use the dynamically assigned (hostname) IP address for connection?


I have a basic question. I use Nornir to trigger Netmiko to configure a Cisco router. It only works, when I hardcode the IP address in the host inventory (hostname).

Europe-Cisco-Site1:
  hostname: "" <-- when I put the public IP here, it works!
  username: "ec2-user"
  password: ""
  platform: "cisco_xe"
  groups:
    - cisco
  connection_options:
    netmiko:
      extras:
        use_keys: true
        key_file: "/home/coder/.ssh/id_rsa"

In my case, I have to get the public IP from AWS and then assign the hostname variable dynamiclly:

def assign_aws_public_ips(task):
    task.host['hostname'] = get_aws_public_ip(str(task.host), task.host['aws_region'])
    print("****************************")
    print(task.host['hostname'])
    print("****************************")
    result = task.run(
        task=netmiko_send_config,
        config_file="templates/simple.j2"
    )
    print_result(result)
    return(f"{task.host} = {task.host['hostname']}")

This is only a test script to validate, if the public IP is assigned on the hostname:

****************************
**52.59.216.193** <-- this is the public IP which has been assigned to **hostname**
****************************
netmiko_send_config*************************************************************
* Europe-Cisco-Site1 ** changed : False ****************************************
vvvv netmiko_send_config ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv ERROR
Traceback (most recent call last):
  File "/home/coder/.local/lib/python3.8/site-packages/nornir/core/task.py", line 99, in start
    r = self.task(self, **self.params)
  File "/home/coder/.local/lib/python3.8/site-packages/nornir_netmiko/tasks/netmiko_send_config.py", line 24, in netmiko_send_config
    net_connect = task.host.get_connection(CONNECTION_NAME, task.nornir.config)
  File "/home/coder/.local/lib/python3.8/site-packages/nornir/core/inventory.py", line 494, in get_connection
    self.open_connection(
  File "/home/coder/.local/lib/python3.8/site-packages/nornir/core/inventory.py", line 546, in open_connection
    conn_obj.open(
  File "/home/coder/.local/lib/python3.8/site-packages/nornir_netmiko/connections/netmiko.py", line 59, in open
    connection = ConnectHandler(**parameters)
  File "/home/coder/.local/lib/python3.8/site-packages/netmiko/ssh_dispatcher.py", line 326, in ConnectHandler
    return ConnectionClass(*args, **kwargs)
  File "/home/coder/.local/lib/python3.8/site-packages/netmiko/cisco/cisco_ios.py", line 17, in __init__
    return super().__init__(*args, **kwargs)
  File "/home/coder/.local/lib/python3.8/site-packages/netmiko/base_connection.py", line 244, in __init__
    raise ValueError("Either ip or host must be set")
ValueError: Either ip or host must be set

Question: Why does Netmiko don't use the hostname, which has been assigned during the play? It always takes the hostname which has not been defined in the host inventory file?

One bad solution would be to update the host inventory file with the public IP but this is really a bad solution and I can’t imagine that this should be done!?


Solution

  • Got it now!!!! Missed really something basic, I though I can use hostname like a dictionary but this is not true. Thanks for the help!

    This is the correct code:

    def assign_aws_public_ips(task):
        task.host.hostname = get_aws_public_ip(str(task.host), task.host['aws_region'])
        return(f"{task.host} = {task.host.hostname}")
    

    This is the right Tutorial where the Well-knonw Attributes are described, for reference: https://gist.github.com/danielmacuare/c647880cfc99a605d25c3b669ab63fc7