The commit 4b329c345c added the file
and the imports did not adhere to the existing conventions.
Third party imports should be grouped together.
In addition to this it removes an unncesary new line.
TrivialFix
Change-Id: Ieeb4d20887ba8e90ea4f7850101b97ccd6e86658
183 lines
6.7 KiB
Python
183 lines
6.7 KiB
Python
# Copyright 2015 Cisco Systems
|
|
# 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 os
|
|
import shutil
|
|
|
|
import jinja2
|
|
from oslo_config import cfg
|
|
from oslo_log import log as logging
|
|
import six
|
|
|
|
from neutron.agent.linux import external_process
|
|
from neutron.agent.linux import pd
|
|
from neutron.agent.linux import pd_driver
|
|
from neutron.agent.linux import utils
|
|
from neutron.common import constants
|
|
from neutron.common import utils as common_utils
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
PD_SERVICE_NAME = 'dibbler'
|
|
CONFIG_TEMPLATE = jinja2.Template("""
|
|
# Config for dibbler-client.
|
|
|
|
# Use enterprise number based duid
|
|
duid-type duid-en {{ enterprise_number }} {{ va_id }}
|
|
|
|
# 8 (Debug) is most verbose. 7 (Info) is usually the best option
|
|
log-level 8
|
|
|
|
# No automatic downlink address assignment
|
|
downlink-prefix-ifaces "none"
|
|
|
|
# Use script to notify l3_agent of assigned prefix
|
|
script {{ script_path }}
|
|
|
|
# Ask for prefix over the external gateway interface
|
|
iface {{ interface_name }} {
|
|
# Bind to generated LLA
|
|
bind-to-address {{ bind_address }}
|
|
# ask for address
|
|
pd 1
|
|
}
|
|
""")
|
|
|
|
# The first line must be #!/usr/bin/env bash
|
|
SCRIPT_TEMPLATE = jinja2.Template("""#!/usr/bin/env bash
|
|
|
|
exec neutron-pd-notify $1 {{ prefix_path }} {{ l3_agent_pid }}
|
|
""")
|
|
|
|
|
|
class PDDibbler(pd_driver.PDDriverBase):
|
|
def __init__(self, router_id, subnet_id, ri_ifname):
|
|
super(PDDibbler, self).__init__(router_id, subnet_id, ri_ifname)
|
|
self.requestor_id = "%s:%s:%s" % (self.router_id,
|
|
self.subnet_id,
|
|
self.ri_ifname)
|
|
self.dibbler_client_working_area = "%s/%s" % (cfg.CONF.pd_confs,
|
|
self.requestor_id)
|
|
self.prefix_path = "%s/prefix" % self.dibbler_client_working_area
|
|
self.pid_path = "%s/client.pid" % self.dibbler_client_working_area
|
|
self.converted_subnet_id = self.subnet_id.replace('-', '')
|
|
|
|
def _is_dibbler_client_running(self):
|
|
return utils.get_value_from_file(self.pid_path)
|
|
|
|
def _generate_dibbler_conf(self, ex_gw_ifname, lla):
|
|
dcwa = self.dibbler_client_working_area
|
|
script_path = utils.get_conf_file_name(dcwa, 'notify', 'sh', True)
|
|
buf = six.StringIO()
|
|
buf.write('%s' % SCRIPT_TEMPLATE.render(
|
|
prefix_path=self.prefix_path,
|
|
l3_agent_pid=os.getpid()))
|
|
common_utils.replace_file(script_path, buf.getvalue())
|
|
os.chmod(script_path, 0o744)
|
|
|
|
dibbler_conf = utils.get_conf_file_name(dcwa, 'client', 'conf', False)
|
|
buf = six.StringIO()
|
|
buf.write('%s' % CONFIG_TEMPLATE.render(
|
|
enterprise_number=cfg.CONF.vendor_pen,
|
|
va_id='0x%s' % self.converted_subnet_id,
|
|
script_path='"%s/notify.sh"' % dcwa,
|
|
interface_name='"%s"' % ex_gw_ifname,
|
|
bind_address='%s' % lla))
|
|
|
|
common_utils.replace_file(dibbler_conf, buf.getvalue())
|
|
return dcwa
|
|
|
|
def _spawn_dibbler(self, pmon, router_ns, dibbler_conf):
|
|
def callback(pid_file):
|
|
dibbler_cmd = ['dibbler-client',
|
|
'start',
|
|
'-w', '%s' % dibbler_conf]
|
|
return dibbler_cmd
|
|
|
|
pm = external_process.ProcessManager(
|
|
uuid=self.requestor_id,
|
|
default_cmd_callback=callback,
|
|
namespace=router_ns,
|
|
service=PD_SERVICE_NAME,
|
|
conf=cfg.CONF,
|
|
pid_file=self.pid_path)
|
|
pm.enable(reload_cfg=False)
|
|
pmon.register(uuid=self.requestor_id,
|
|
service_name=PD_SERVICE_NAME,
|
|
monitored_process=pm)
|
|
|
|
def enable(self, pmon, router_ns, ex_gw_ifname, lla):
|
|
LOG.debug("Enable IPv6 PD for router %s subnet %s ri_ifname %s",
|
|
self.router_id, self.subnet_id, self.ri_ifname)
|
|
if not self._is_dibbler_client_running():
|
|
dibbler_conf = self._generate_dibbler_conf(ex_gw_ifname, lla)
|
|
self._spawn_dibbler(pmon, router_ns, dibbler_conf)
|
|
LOG.debug("dibbler client enabled for router %s subnet %s"
|
|
" ri_ifname %s",
|
|
self.router_id, self.subnet_id, self.ri_ifname)
|
|
|
|
def disable(self, pmon, router_ns):
|
|
LOG.debug("Disable IPv6 PD for router %s subnet %s ri_ifname %s",
|
|
self.router_id, self.subnet_id, self.ri_ifname)
|
|
dcwa = self.dibbler_client_working_area
|
|
|
|
def callback(pid_file):
|
|
dibbler_cmd = ['dibbler-client',
|
|
'stop',
|
|
'-w', '%s' % dcwa]
|
|
return dibbler_cmd
|
|
|
|
pmon.unregister(uuid=self.requestor_id,
|
|
service_name=PD_SERVICE_NAME)
|
|
pm = external_process.ProcessManager(
|
|
uuid=self.requestor_id,
|
|
namespace=router_ns,
|
|
service=PD_SERVICE_NAME,
|
|
conf=cfg.CONF,
|
|
pid_file=self.pid_path)
|
|
pm.disable(get_stop_command=callback)
|
|
shutil.rmtree(dcwa, ignore_errors=True)
|
|
LOG.debug("dibbler client disabled for router %s subnet %s "
|
|
"ri_ifname %s",
|
|
self.router_id, self.subnet_id, self.ri_ifname)
|
|
|
|
def get_prefix(self):
|
|
prefix = utils.get_value_from_file(self.prefix_path)
|
|
if not prefix:
|
|
prefix = constants.PROVISIONAL_IPV6_PD_PREFIX
|
|
return prefix
|
|
|
|
@staticmethod
|
|
def get_sync_data():
|
|
try:
|
|
requestor_ids = os.listdir(cfg.CONF.pd_confs)
|
|
except OSError:
|
|
return []
|
|
|
|
sync_data = []
|
|
requestors = (r.split(':') for r in requestor_ids if r.count(':') == 2)
|
|
for router_id, subnet_id, ri_ifname in requestors:
|
|
pd_info = pd.PDInfo()
|
|
pd_info.router_id = router_id
|
|
pd_info.subnet_id = subnet_id
|
|
pd_info.ri_ifname = ri_ifname
|
|
pd_info.driver = PDDibbler(router_id, subnet_id, ri_ifname)
|
|
pd_info.client_started = (
|
|
pd_info.driver._is_dibbler_client_running())
|
|
pd_info.prefix = pd_info.driver.get_prefix()
|
|
sync_data.append(pd_info)
|
|
|
|
return sync_data
|