ironic-python-agent-builder/tinyipa/build_files/export_network_data.py

186 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python3
#
# Copyright 2019 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import collections
import json
import sys
import argparse
DESCRIPTION = """\
This tool turns OpenStack network metadata, supplied in a form of JSON
document, into a collection of bash arrays.
Each array variable holds values belonging to a specific option (e.g.
IP address) indexed by entity number (e.g. NIC). This representation
is thought to be more convenient to use from bash scripts.
The caller of this tool is expected to `eval` its stdout to get bash
variables into caller's environment.
Example
-------
This fragment of L2 configuration:
.. code-block:: json
{
"links": [
{
"id": "interface2",
"type": "vif",
"ethernet_mac_address": "a0:36:9f:2c:e8:70",
"vif_id": "e1c90e9f-eafc-4e2d-8ec9-58b91cebb53d",
"mtu": 1500
},
{
"id": "interface0",
"type": "phy",
"ethernet_mac_address": "a0:36:9f:2c:e8:80",
"mtu": 9000
}
}
Will turn into these bash variables:
.. code-block:: bash
ND_L2_ID=('interface2' 'interface0')
ND_L2_TYPE=('vif' 'phy')
ND_L2_ETHERNET_MAC_ADDRESS=('a0:36:9f:2c:e8:70' 'a0:36:9f:2c:e8:80')
ND_L2_VIF_ID=('e1c90e9f-eafc-4e2d-8ec9-58b91cebb53d' '')
ND_L2_MTU=(1500 9000)
"""
def main():
parser = argparse.ArgumentParser(
description=DESCRIPTION, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
'--source',
metavar='<network_data.json>',
type=str,
required=True,
help='OpenStack network configuration meta data '
'(AKA network_data.json)')
parsed_args = parser.parse_args()
with open(parsed_args.source) as fl:
network_data = json.load(fl)
subnets = collections.defaultdict(collections.defaultdict)
for network in network_data.get('networks', []):
# remap IP address variable to facilitate further CLI usage
if network.get('type') == 'ipv4':
network['ipv4_address'] = network.pop('ip_address', '')
network['ipv4_netmask'] = network.pop('netmask', '')
elif network.get('type') == 'ipv6':
network['ipv6_address'] = network.pop('ip_address', '')
network['ipv6_netmask'] = network.pop('netmask', '')
subnet = subnets[network['link']]
subnet.update(network)
nics = collections.defaultdict(dict)
for link in network_data.get('links', []):
nd_dev = link['id']
nic = nics[nd_dev]
nic.update({'ND_L2_%s' % k.upper(): v
for k, v in link.items()})
nic.update(
{'ND_L3_%s' % k.upper(): v
for k, v in subnets.get(nd_dev, {}).items()})
# transpose into positional form
variables = collections.defaultdict(dict)
routes = collections.defaultdict(list)
services = collections.defaultdict(dict)
for index, nic_id in enumerate(nics):
nic = nics[nic_id]
for var, val in nic.items():
if isinstance(val, (str, int)):
variables[var][index] = val
# routing table is a special case
elif var == 'ND_L3_ROUTES':
for route in val:
for field in ('network', 'netmask', 'gateway'):
key = var + '_' + field.upper()
routes[key].append(route.get(field, ''))
routes[var + '_ETHERNET_MAC_ADDRESS'].append(nic.get(
'ND_L2_ETHERNET_MAC_ADDRESS', ''))
sr_count = 0
for index, service in enumerate(network_data.get('services', [])):
for var, val in service.items():
if isinstance(val, (str, int)):
var = 'ND_SERVICE_' + var.upper()
services[var][index] = val
sr_count = index + 1
# generate bash arrays of L2/L3 NIC info indexed by NIC number
nd_count = len(nics)
for var, values in variables.items():
print('%s=(%s)' % (
var, ' '.join(repr(values.get(idx, ''))
for idx in range(nd_count))))
print('ND_NIC_COUNT=%d' % nd_count)
# generate bash arrays of IPv4/v6 routing info indexed by route number
rt_count = 0
for var, values in routes.items():
print('%s=(%s)' % (
var, ' '.join(repr(v) for v in values)))
if not rt_count:
rt_count = len(values)
print('ND_L3_ROUTES_COUNT=%d' % rt_count)
# generate bash arrays of network service info indexed by service number
for var, values in services.items():
print('%s=(%s)' % (
var, ' '.join(repr(values.get(idx, ''))
for idx in range(sr_count))))
print('ND_L3_SERVICES_COUNT=%d' % sr_count)
if __name__ == '__main__':
sys.exit(main())