Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 3 additions & 51 deletions netsim/outputs/ansible.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,16 @@

from box import Box

from ..augment import devices, nodes, plugin
from ..augment import nodes, plugin
from ..data import append_to_list, global_vars
from ..utils import files as _files
from ..utils import log, strings, templates
from ..utils import routing as _rp_utils
from . import _TopologyOutput, check_writeable
from .common import adjust_inventory_host

forwarded_port_name = { 'ssh': 'ansible_port', }

def copy_provider_inventory(host: Box, p_data: Box) -> None:
if 'inventory' in p_data:
for k,v in p_data.inventory.items():
host[k] = v

if 'inventory_port_map' in p_data and 'forwarded' in p_data:
for k,v in p_data.inventory_port_map.items():
if k in p_data.forwarded:
host[v] = p_data.forwarded[k] + host.id

def copy_device_provider_group_vars(host: Box, node: Box, topology: Box) -> None:
p_data = devices.get_provider_data(node,topology.defaults)
if not 'group_vars' in p_data:
return

for k,v in p_data.group_vars.items():
if not k in host:
host[k] = v

def provider_inventory_settings(host: Box, node: Box, topology: Box) -> None:
defaults = topology.defaults
node_provider = devices.get_provider(node,topology)
p_data = defaults.providers[node_provider]
if p_data:
copy_provider_inventory(host,p_data)

if 'provider' in node: # Is the node using a secondary provider?
copy_device_provider_group_vars(host,node,topology)

topo_to_host = { 'mgmt.ipv4': 'ansible_host', 'hostname': 'ansible_host', 'id': 'id' }
topo_to_host_skip = [ 'name','device' ]

def ansible_inventory_host(node: Box, topology: Box) -> Box:
host = Box({})
for (node_key,inv_key) in topo_to_host.items():
if "." in node_key:
value = node[node_key]
else:
value = node.get(node_key,None)
if value:
host[inv_key] = value

for (k,v) in node.items():
if not k in topo_to_host_skip:
host[k] = v

provider_inventory_settings(host,node,topology)
return host

"""
Create a 'hosts' dictionary listing usable IPv4 and IPv6 addresses of all lab devices.
"""
Expand Down Expand Up @@ -157,7 +109,7 @@ def create(topology: Box) -> Box:

for name,node in topology.nodes.items():
group = node.get('device','all')
inventory[group].hosts[name] = ansible_inventory_host(node,topology)
inventory[group].hosts[name] = adjust_inventory_host(node,defaults=topology.defaults,group_vars=False)

for xg in extra_groups.keys():
if node.get(xg,False): # Add device to the extra group if it has the corresponding attribute set
Expand Down
51 changes: 40 additions & 11 deletions netsim/outputs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
from ..augment import devices
from ..data import get_box, get_empty_box

topo_to_host = { 'mgmt.ipv4': 'ansible_host', 'hostname': 'ansible_host', 'id': 'id' }
topo_to_host_skip = [ 'name','device' ]

def provider_inventory_settings(node: Box, defaults: Box) -> None:
p_data = defaults.providers[defaults.provider]
n_provider = devices.get_provider(node,defaults)
p_data = defaults.providers[n_provider]
if not p_data:
return # pragma: no cover -- won't create an extra test case just to cover the "do nothing" scenario

Expand All @@ -29,14 +28,28 @@ def provider_inventory_settings(node: Box, defaults: Box) -> None:
def add_group_vars(
host: Box,
node: Box,
defaults: Box) -> None:
defaults: Box) -> typing.Optional[Box]:

group_vars = devices.get_device_attribute(node,'group_vars',defaults)
if isinstance(group_vars,dict):
for (k,v) in group_vars.items():
if k not in host:
host[k] = v

return group_vars

def add_device_provider_group_vars(host: Box, node: Box, defaults: Box) -> None:
p_data = devices.get_provider_data(node,defaults)
if not 'group_vars' in p_data:
return

for k,v in p_data.group_vars.items():
if k not in host:
host[k] = v

topo_to_host = { 'hostname': 'ansible_host', 'mgmt.ipv4': 'ansible_host', 'id': 'id' }
topo_to_host_skip = [ 'name','device' ]

def adjust_inventory_host(
node: Box,
defaults: Box,
Expand All @@ -45,19 +58,35 @@ def adjust_inventory_host(
group_vars: typing.Optional[bool] = False) -> Box:
host = get_empty_box()

if group_vars: # Add group variables before doing netlab-to-ansible
g_vars = add_group_vars(host,node,defaults) # ... attribute conversion because we need 'ansible_connection'
else:
# The caller does not want to have group vars copied into node data, but we still have to do that
# for provider group_vars on nodes with non-default provider, as they might have (for example)
# different ansible_connection
#
g_vars = devices.get_device_attribute(node,'group_vars',defaults)
n_provider = devices.get_provider(node,defaults)
if n_provider != defaults.provider:
add_device_provider_group_vars(host,node,defaults)

translate = translate or topo_to_host
if ignore is None:
ignore = topo_to_host_skip

if group_vars:
add_group_vars(host,node,defaults)
# For Docker nodes, do not use mgmt.X attributes (to set ansible_host)
# Everywhere else, 'mgmt.ipv4' will overwrite 'hostname' (set by clab)
# resulting in an IPv4 address, not a hostname, for nodes using SSH/HTTPx
# connections, making ansible-pysshlib happy (see #2911)
ansible_connection = host.get('ansible_connection','')
if not ansible_connection and isinstance(g_vars,dict):
ansible_connection = g_vars.get('ansible_connection','')
if ansible_connection == 'docker':
translate = { k:v for k,v in translate.items() if 'mgmt.' not in k }

for (node_key,inv_key) in translate.items():
if "." in node_key:
value = node[node_key]
else:
value = node.get(node_key,None)
if value:
value = node.get(node_key,None)
if value is not None:
host[inv_key] = value

for (k,v) in node.items():
Expand Down