239 lines
6.8 KiB
Python
239 lines
6.8 KiB
Python
# Copyright 2014 DreamHost, LLC
|
|
#
|
|
# Author: DreamHost, LLC
|
|
#
|
|
# 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 logging
|
|
import re
|
|
|
|
from oslo.config import cfg
|
|
|
|
from akanda.rug.openstack.common import jsonutils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
DEFAULT_AS = 64512
|
|
|
|
OPTIONS = [
|
|
cfg.StrOpt('provider_rules_path'),
|
|
cfg.IntOpt('asn', default=DEFAULT_AS),
|
|
cfg.IntOpt('neighbor_asn', default=DEFAULT_AS),
|
|
]
|
|
|
|
cfg.CONF.register_opts(OPTIONS)
|
|
|
|
EXTERNAL_NET = 'external'
|
|
INTERNAL_NET = 'internal'
|
|
MANAGEMENT_NET = 'management'
|
|
SERVICE_STATIC = 'static'
|
|
SERVICE_DHCP = 'dhcp'
|
|
SERVICE_RA = 'ra'
|
|
|
|
|
|
def build_config(client, router, interfaces):
|
|
provider_rules = load_provider_rules(cfg.CONF.provider_rules_path)
|
|
|
|
return {
|
|
'asn': cfg.CONF.asn,
|
|
'neighbor_asn': cfg.CONF.neighbor_asn,
|
|
'networks': generate_network_config(client, router, interfaces),
|
|
'address_book': generate_address_book_config(client, router),
|
|
'anchors': generate_anchor_config(client, provider_rules, router),
|
|
'labels': provider_rules.get('labels', {}),
|
|
'floating_ips': generate_floating_config(router),
|
|
'tenant_id': router.tenant_id
|
|
}
|
|
|
|
|
|
def load_provider_rules(path):
|
|
try:
|
|
return jsonutils.load(open(path))
|
|
except: # pragma nocover
|
|
LOG.exception('unable to open provider rules: %s' % path)
|
|
|
|
|
|
def generate_network_config(client, router, interfaces):
|
|
iface_map = dict((i['lladdr'], i['ifname']) for i in interfaces)
|
|
|
|
retval = [
|
|
_network_config(
|
|
client,
|
|
router.external_port,
|
|
iface_map[router.external_port.mac_address],
|
|
EXTERNAL_NET),
|
|
_management_network_config(
|
|
router.management_port,
|
|
iface_map[router.management_port.mac_address],
|
|
interfaces,
|
|
)]
|
|
|
|
retval.extend(
|
|
_network_config(
|
|
client,
|
|
p,
|
|
iface_map[p.mac_address],
|
|
INTERNAL_NET,
|
|
client.get_network_ports(p.network_id))
|
|
for p in router.internal_ports)
|
|
|
|
return retval
|
|
|
|
|
|
def _management_network_config(port, ifname, interfaces):
|
|
for iface in interfaces:
|
|
if iface['ifname'] == ifname:
|
|
return _make_network_config_dict(
|
|
iface, MANAGEMENT_NET, port.network_id)
|
|
|
|
|
|
def _network_config(client, port, ifname, network_type, network_ports=[]):
|
|
subnets = client.get_network_subnets(port.network_id)
|
|
subnets_dict = dict((s.id, s) for s in subnets)
|
|
return _make_network_config_dict(
|
|
_interface_config(ifname, port, subnets_dict),
|
|
network_type,
|
|
port.network_id,
|
|
subnets_dict=subnets_dict,
|
|
network_ports=network_ports)
|
|
|
|
|
|
def _make_network_config_dict(interface, network_type, network_id,
|
|
v4_conf=SERVICE_STATIC, v6_conf=SERVICE_STATIC,
|
|
subnets_dict={}, network_ports=[]):
|
|
return {'interface': interface,
|
|
'network_id': network_id,
|
|
'v4_conf_service': v4_conf,
|
|
'v6_conf_service': v6_conf,
|
|
'network_type': network_type,
|
|
'subnets': [_subnet_config(s) for s in subnets_dict.values()],
|
|
'allocations': _allocation_config(network_ports, subnets_dict)}
|
|
|
|
|
|
def _interface_config(ifname, port, subnets_dict):
|
|
def fmt(fixed):
|
|
return '%s/%s' % (fixed.ip_address,
|
|
subnets_dict[fixed.subnet_id].cidr.prefixlen)
|
|
|
|
return {'ifname': ifname,
|
|
'addresses': [fmt(fixed) for fixed in port.fixed_ips]}
|
|
|
|
|
|
def _subnet_config(subnet):
|
|
return {
|
|
'cidr': str(subnet.cidr),
|
|
'dhcp_enabled': subnet.enable_dhcp,
|
|
'dns_nameservers': subnet.dns_nameservers,
|
|
'host_routes': subnet.host_routes,
|
|
'gateway_ip': str(subnet.gateway_ip)
|
|
}
|
|
|
|
|
|
def _allocation_config(ports, subnets_dict):
|
|
r = re.compile('[:.]')
|
|
allocations = []
|
|
|
|
for port in ports:
|
|
addrs = {
|
|
str(fixed.ip_address): subnets_dict[fixed.subnet_id].enable_dhcp
|
|
for fixed in port.fixed_ips
|
|
}
|
|
|
|
if not addrs:
|
|
continue
|
|
|
|
allocations.append(
|
|
{
|
|
'ip_addresses': addrs,
|
|
'device_id': port.device_id,
|
|
'hostname': '%s.local' % r.sub('-', sorted(addrs.keys())[0]),
|
|
'mac_address': port.mac_address
|
|
}
|
|
)
|
|
|
|
return allocations
|
|
|
|
|
|
def generate_address_book_config(client, router):
|
|
return dict([(g.name, [str(e) for e in g.entries])
|
|
for g in client.get_addressgroups(router.tenant_id)])
|
|
|
|
|
|
def generate_anchor_config(client, provider_rules, router):
|
|
retval = provider_rules.get('preanchors', [])
|
|
|
|
retval.extend([
|
|
generate_tenant_port_forward_anchor(client, router),
|
|
generate_tenant_filter_rule_anchor(client, router)
|
|
])
|
|
retval.extend(provider_rules.get('postanchors', []))
|
|
|
|
return retval
|
|
|
|
|
|
def generate_tenant_port_forward_anchor(client, router):
|
|
to_ip = router.external_port.first_v4 or '127.0.0.1'
|
|
|
|
rules = [_format_port_forward_rule(to_ip, pf)
|
|
for pf in client.get_portforwards(router.tenant_id)]
|
|
|
|
return {
|
|
'name': 'tenant_v4_portforwards',
|
|
'rules': [r for r in rules if r]
|
|
}
|
|
|
|
|
|
def _format_port_forward_rule(to_ip, pf):
|
|
redirect_ip = pf.port.first_v4
|
|
|
|
if not redirect_ip:
|
|
return
|
|
|
|
return {
|
|
'action': 'pass',
|
|
'direction': 'in',
|
|
'family': 'inet',
|
|
'protocol': pf.protocol,
|
|
'destination': '%s/32' % to_ip,
|
|
'destination_port': pf.public_port,
|
|
'redirect': redirect_ip,
|
|
'redirect_port': pf.private_port
|
|
}
|
|
|
|
|
|
def generate_tenant_filter_rule_anchor(client, router):
|
|
return {
|
|
'name': 'tenant_filterrules',
|
|
'rules': [_format_filter_rule(r)
|
|
for r in client.get_filterrules(router.tenant_id)]
|
|
}
|
|
|
|
|
|
def _format_filter_rule(rule):
|
|
return {
|
|
'action': rule.action,
|
|
'protocol': rule.protocol,
|
|
'source': rule.source.name if rule.source else None,
|
|
'source_port': rule.source_port,
|
|
'destination': rule.destination.name if rule.destination else None,
|
|
'destination_port': rule.destination_port,
|
|
}
|
|
|
|
|
|
def generate_floating_config(router):
|
|
return [
|
|
{'floating_ip': str(fip.floating_ip), 'fixed_ip': str(fip.fixed_ip)}
|
|
for fip in router.floating_ips
|
|
]
|