186 lines
5.3 KiB
Python
Executable File
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())
|