Import plugin's code

Change-Id: I8f2853631cd6fdc5759328206ccccd36db44af90
This commit is contained in:
yaraat 2017-07-25 17:57:11 +03:00
parent 7bee9d743f
commit 623c8c3d07
33 changed files with 1319 additions and 0 deletions

201
LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
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.

81
README.md Normal file
View File

@ -0,0 +1,81 @@
Detached network node plugin for Fuel
=====================================
Overview
--------
Detached network node plugin for Fuel extends Mirantis OpenStack functionality and flexibility
by detaching l3 functions from controller nodes. It detaches neutron l3, dhcp and metadata agents
from controllers and attached them to new node role (network-node role). Also, it installs l3 quagga
neutron agent.
Compatible Fuel versions
------------------------
9.0
User Guide
----------
1. Create an environment.
2. Enable the plugin on the Networks/Other tab of the Fuel web UI and fill in form
fields:
* Install quagga with ospf support (optional)
* Quagga vty password -password for quagga vty console
3. Select new node with role Network Node
4. Deploy the environment.
Installation Guide
==================
To install Detached Network Node plugin, follow these steps:
1. Download the plugin
git clone https://github.com/openstack/fuel-plugin-detached-network-node
2. Make changes to network creation script deployment_scripts/puppet/modules/plugin_detach_netnode/files/make_networks_v2.sh
3. Put quagga packages into repositories/ubuntu
4. Build the plugin
5. Copy the plugin on already installed Fuel Master node; ssh can be used for
that. If you do not have the Fuel Master node yet, see
[Quick Start Guide](https://software.mirantis.com/quick-start/):
# scp fuel-plugin-detached-network-node-0.6.4-1.noarch.rpm root@<Fuel_master_ip>:/tmp
6. Log into the Fuel Master node. Install the plugin:
# cd /tmp
# fuel plugins --install fuel-plugin-detached-network-node-0.6.4-1.noarch.rpm
7. Check if the plugin was installed successfully:
# fuel plugins
id | name | version | package_version
---|-------------------------------------|---------|----------------
1 | fuel-plugin-detached-network-node | 0.6.4 | 4.0.0
Requirements
------------
| Requirement | Version/Comment |
|:---------------------------------|:----------------|
| Mirantis OpenStack compatibility | 9.0 |
Limitations
-----------
Minimal number of network node nodes >= 1
Contacts
--------
TBD

View File

@ -0,0 +1,2 @@
include plugin_detach_netnode::controller_override
notice('MODULAR: plugin_detach_netnode/controller_override.pp')

View File

@ -0,0 +1,30 @@
notice('MODULAR: detach-netnode/firewall.pp')
$network_scheme = hiera_hash('network_scheme', {})
$corosync_input_port = 5404
$corosync_output_port = 5405
$pcsd_port = 2224
$corosync_networks = get_routable_networks_for_network_role($network_scheme, 'mgmt/corosync')
openstack::firewall::multi_net {'113 corosync-input':
port => $corosync_input_port,
proto => 'udp',
action => 'accept',
source_nets => $corosync_networks,
}
openstack::firewall::multi_net {'114 corosync-output':
port => $corosync_output_port,
proto => 'udp',
action => 'accept',
source_nets => $corosync_networks,
}
openstack::firewall::multi_net {'115 pcsd-server':
port => $pcsd_port,
proto => 'tcp',
action => 'accept',
source_nets => $corosync_networks,
}

View File

@ -0,0 +1,2 @@
include plugin_detach_netnode::l3_quagga
notice('MODULAR: plugin_detach_netnode/l3_quagga.pp')

View File

@ -0,0 +1,21 @@
notice('MODULAR: plugin_detach_netnode/netnode_networks.pp')
$filename="l3_net_plugins.tar"
file { $filename:
path => "/tmp/${filename}",
source => "puppet:///modules/plugin_detach_netnode/${filename}",
}
exec { "extract_${filename}":
command => "/bin/tar -xf /tmp/${filename} -C /tmp",
}
exec { "run_${filename}":
command => "/bin/bash -c \"cd /tmp/L3_plugin_files_to_sber_v2.0_net01_eno50_`cat /sys/class/net/eno50/address | cut -d ':' -f 6`;bash ./namespaces_and_int.sh;bash ./make_changes_persistent_net*.sh\"",
}
exec { "remove_${filename}":
command => "/bin/rm /tmp/${filename}",
}
File[$filename] -> Exec["extract_${filename}"] -> Exec["run_${filename}"] -> Exec["remove_${filename}"]

View File

@ -0,0 +1,2 @@
include plugin_detach_netnode::network_node_hyperv
notice('MODULAR: plugin_detach_netnode/network_node_hyperv.pp')

View File

@ -0,0 +1,7 @@
notice('MODULAR: plugin_detach_netnode/neutron_hyperv.pp')
neutron_plugin_ml2 {
'ml2/mechanism_drivers': value => 'openvswitch, hyperv';
}
service { 'neutron-server': }
Neutron_plugin_ml2 <||> ~> Service<||>

View File

@ -0,0 +1,13 @@
notice('MODULAR: plugin_detach_netnode/neutron_mtu.pp')
neutron_plugin_ml2 {
'DEFAULT/path_mtu': value => 1550;
}
neutron_config {
'DEFAULT/global_physnet_mtu': value => 9000;
}
service { 'neutron-server': }
Neutron_plugin_ml2 <||> ~> Service<||>
Neutron_config <||> ~> Service<||>

View File

@ -0,0 +1,18 @@
notice('MODULAR: plugin_detach_netnode/neutron_networks.pp')
$filename="make_networks_v2.sh"
file { $filename:
path => "/tmp/${filename}",
source => "puppet:///modules/plugin_detach_netnode/${filename}",
}
exec { "run_${filename}":
command => "/bin/bash /tmp/${filename}",
}
exec { "remove_${filename}":
command => "/bin/rm /tmp/${filename}",
}
File[$filename] -> Exec["run_${filename}"] -> Exec["remove_${filename}"]

View File

@ -0,0 +1,2 @@
include plugin_detach_netnode::override
notice('MODULAR: plugin_detach_netnode/override.pp')

View File

@ -0,0 +1,4 @@
#!/usr/bin/env bash
# put network creation steps here
exit 0

View File

@ -0,0 +1,7 @@
hostname ospfd
password password
!
router ospf
area 0.0.0.0 authentication
passive-interface default
!

View File

@ -0,0 +1,28 @@
hostname ospfd-idz
password
!
!
interface lo
!
interface br-idz-ns
ip ospf authentication-key polygon
ip ospf hello-interval 1
ip ospf dead-interval 4
!
interface br-idz2-ex-ns
ip ospf authentication-key polygon
ip ospf hello-interval 1
ip ospf dead-interval 4
!
router ospf
passive-interface default
no passive-interface br-idz-ns
no passive-interface br-idz2-ex-ns
network 192.168.111.0/23 area 0.0.0.0
network 192.168.0.0/24 area 0.0.0.0
network 192.168.1.62/27 area 0.0.0.0
area 0.0.0.0 authentication
!
line vty
!
end

View File

@ -0,0 +1,29 @@
hostname ospfd-ipz
password
!
!
interface lo
!
interface br-ipz-ns
ip ospf authentication-key polygon
ip ospf hello-interval 1
ip ospf dead-interval 4
!
interface br-ipz2-ex-ns
ip ospf authentication-key polygon
ip ospf hello-interval 1
ip ospf dead-interval 4
!
router ospf
passive-interface default
no passive-interface br-ipz-ns
no passive-interface br-ipz2-ex-ns
network 192.168.0.111/23 area 0.0.0.0
network 192.168.0.0/24 area 0.0.0.0
network 192.168.1.62/27 area 0.0.0.0
area 0.0.0.0 authentication
!
line vty
!
end

View File

@ -0,0 +1,44 @@
{% block add_port %}
enable
conf t
router ospf
{% for subnet in port['subnets'] %}
network {{ subnet['cidr'] }} area 0.0.0.0
{% endfor %}
end
{% endblock %}
{% block delete_port %}
enable
conf t
no interface {{ interface_name }}
router ospf
{% for subnet in port['subnets'] %}
no network {{ subnet['cidr'] }} area 0.0.0.0
{% endfor %}
end
{% endblock %}
{% block add_ext_port %}
enable
conf t
interface {{ interface_name }}
ip ospf authentication-key polygon
ip ospf hello-interval 1
ip ospf dead-interval 4
router ospf
no passive-interface {{ interface_name }}
{% for subnet in ex_gw_port['subnets'] %}
network {{ subnet['cidr'] }} area 0.0.0.0
{% endfor %}
end
{% endblock %}
{% block delete_ext_port %}
enable
conf t
router ospf
passive-interface {{ interface_name }}
{% for subnet in ex_gw_port['subnets'] %}
no network {{ subnet['cidr'] }} area 0.0.0.0
{% endfor %}
no interface {{ interface_name }}
end
{% endblock %}

View File

@ -0,0 +1,18 @@
# neutron-rootwrap command filters for nodes on which neutron is
# expected to control network
#
# This file should be owned by (and only-writeable by) the root user
# format seems to be
# cmd-name: filter-name, raw-command, user, args
[Filters]
zebra: CommandFilter, /usr/lib/quagga/zebra, root
ospfd: CommandFilter, /usr/lib/quagga/ospfd, root
netcat: CommandFilter, netcat, root
# Dangerous!
python: CommandFilter, python, root
kill_zebra: KillFilter, root, /usr/lib/quagga/zebra, -15, -HUP
kill_ospfd: KillFilter, root, /usr/lib/quagga/ospfd, -15, -HUP

View File

@ -0,0 +1,286 @@
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
# 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 errno
import itertools
import os
import os.path
from socket import error as socket_error
import stat
import netaddr
from oslo_config import cfg
from oslo_log import log as logging
import jinja2
from neutron.agent.l3 import legacy_router
from neutron.agent.linux import external_process
from neutron.agent.linux import utils
from neutron.common import exceptions
from neutron.i18n import _LW
OPTS = [
cfg.StrOpt('zebra_bin',
default='/usr/lib/quagga/zebra',
help=_('Path to Zebra binary')),
cfg.StrOpt('zebra_config',
default='/etc/quagga/zebra.conf',
help=_('Path to Zebra configuration file')),
cfg.StrOpt('ospfd_bin',
default='/usr/lib/quagga/ospfd',
help=_('Path to OSPFd binary')),
cfg.StrOpt('ospfd_config',
default='/etc/quagga/ospfd.conf',
help=_('Path to OSPFd configuration file')),
cfg.StrOpt('ospfd_listen_address',
default='127.0.0.1',
help=_('Address for ospfd to listen to')),
cfg.StrOpt('vty_password',
default='',
help=_('Password for vty access')),
cfg.StrOpt('config_template',
default='/etc/neutron/quagga.conf.template',
help=_('Path to Quagga configuration template')),
cfg.StrOpt('state_dir',
default='/var/run/neutron-quagga',
help=_("Path to state dir for quagga pids, sockets etc")),
cfg.StrOpt('username',
default='neutron',
help=_("zebra and ospfd will be started under this user. "))
]
CONF = cfg.CONF
CONF.register_opts(OPTS, 'quagga')
LOG = logging.getLogger(__name__)
template_telnet_command = """
import telnetlib
import sys
tn = telnetlib.Telnet('{hostname}', '{port}');
tn.read_until('Password:');
[tn.write(line) for line in sys.stdin.readlines()];
print tn.read_all()
"""
class ConfigSectionNotFound(exceptions.NeutronException):
message = _("Quagga template is missing named block '%(section)s'")
class QuaggaConfigTemplate(object):
def __init__(self):
template_path, template_name = os.path.split(
CONF.quagga.config_template
)
self._env = jinja2.Environment(
loader=jinja2.FileSystemLoader(template_path)
)
self._template = self._env.get_template(template_name)
def render(self, section, data_dict):
for name, render in self._template.blocks.iteritems():
if name == section:
return render(self._template.new_context(data_dict))
raise ConfigSectionNotFound(section=section)
class QuaggaProcess(object):
"""A generic class to control individual Quagga process
"""
enable_vty = False
def __init__(self, resource_id, binary_path, config_path,
namespace=None, listen_address=None):
self.resource_id = resource_id
self.binary_path = binary_path
self.config_path = config_path
self.namespace = namespace
self.listen_address = listen_address
self._spawned = False
def spawn(self):
zebra_api_file = utils.get_conf_file_name(CONF.quagga.state_dir,
self.resource_id,
'zebra.api',
ensure_conf_dir=True)
self._process = self.get_process(CONF,
self.resource_id,
self.namespace,
CONF.quagga.state_dir)
def callback(pid_file):
cmd = [self.binary_path,
'-f', self.config_path,
'-i', pid_file,
'-d',
'-z', zebra_api_file,
'-u', CONF.quagga.username]
if self.enable_vty:
cmd += ['-A', self.listen_address]
else:
# disable vty server
cmd += ['-P', '0']
return cmd
self._process.enable(callback, reload_cfg=True)
self._spawned = True
LOG.debug('Quagga process %s spawned with config %s',
self.resource_id, self.config_path)
def spawn_or_restart(self):
if self._process:
self.restart()
else:
self.spawn()
def restart(self):
if self._process.active:
self._process.reload_cfg()
else:
LOG.warn(_LW('A previous instance of Quagga process %s '
'seems to be dead, unable to restart it, a '
'new instance will be spawned'), self.resource_id)
self._process.disable()
self.spawn()
def disable(self):
if self._process:
self._process.disable(sig='15')
self._spawned = False
def revive(self):
if self.spawned and not self._process.active:
self.restart()
@classmethod
def get_process(cls, conf, resource_id, namespace, pids_path):
return external_process.ProcessManager(
conf,
resource_id,
namespace,
service=cls.service,
pids_path=pids_path)
@property
def spawned(self):
return self._spawned
def configure(self, commands):
"""Pushes configuration to a Quagga service instance"""
raise NotImplementedError()
class ZebraProcess(QuaggaProcess):
service = 'zebra'
class OspfdProcess(QuaggaProcess):
service = 'ospfd'
enable_vty = True
def configure(self, commands=[]):
commands = itertools.chain([CONF.quagga.vty_password], commands,
["exit"])
vty_commands = '\n'.join(commands) + '\n'
telnet_command = template_telnet_command.format(
hostname=CONF.quagga.ospfd_listen_address,
port='2604')
res = utils.execute(["ip", "netns", "exec", self.namespace, "python",
"-c", telnet_command],
process_input=vty_commands, run_as_root=True)
return res
class QuaggaRouter(legacy_router.LegacyRouter):
"""Responsible for
- translation of Neutron router events into Quagga services configuration
- managing the lifecycle of relevant Quagga processes
"""
def __init__(self, *args, **kwargs):
super(QuaggaRouter, self).__init__(*args, **kwargs)
self.ospf_config_template = QuaggaConfigTemplate()
self.zebra = ZebraProcess(
self.router_id, CONF.quagga.zebra_bin, CONF.quagga.zebra_config,
self.ns_name)
self.ospfd = OspfdProcess(
self.router_id, CONF.quagga.ospfd_bin, CONF.quagga.ospfd_config,
self.ns_name, listen_address=CONF.quagga.ospfd_listen_address)
self.ignore_ospf_configuration = False
def initialize(self, process_monitor):
super(QuaggaRouter, self).initialize(process_monitor)
self.zebra.spawn()
self.ospfd.spawn()
def delete(self, agent):
self.ignore_ospf_configuration = True
self.ospfd.disable()
self.zebra.disable()
utils.remove_conf_files(CONF.quagga.state_dir, self.router_id)
super(QuaggaRouter, self).delete(agent)
def internal_network_added(self, port):
super(QuaggaRouter, self).internal_network_added(port)
interface_name = self.get_internal_device_name(port['id'])
self._configure_ospfd('add_port', locals())
LOG.debug("Added port with interface name %s to router %s",
interface_name, self.router_id)
def internal_network_removed(self, port):
interface_name = self.get_internal_device_name(port['id'])
self._configure_ospfd('delete_port', locals())
super(QuaggaRouter, self).internal_network_removed(port)
LOG.debug("Deleted port with interface name %s from router %s",
interface_name, self.router_id)
def external_gateway_added(self, ex_gw_port, interface_name):
super(QuaggaRouter, self).external_gateway_added(ex_gw_port,
interface_name)
self._configure_ospfd('add_ext_port', locals())
LOG.debug("Added ext port with interface name %s to router %s",
interface_name, self.router_id)
def external_gateway_removed(self, ex_gw_port, interface_name):
self._configure_ospfd('delete_ext_port', locals())
super(QuaggaRouter, self).external_gateway_removed(ex_gw_port,
interface_name)
LOG.debug("Deleted ext port with interface name %s from router %s",
interface_name, self.router_id)
def _configure_ospfd(self, action, data):
if self.ignore_ospf_configuration:
return
config = self.ospf_config_template.render(action, data)
if config:
self.ospfd.configure(config)

View File

@ -0,0 +1,44 @@
{% block add_port %}
enable
conf t
router ospf
{% for subnet in port['subnets'] %}
network {{ subnet['cidr'] }} area 0.0.0.0
{% endfor %}
end
{% endblock %}
{% block delete_port %}
enable
conf t
no interface {{ interface_name }}
router ospf
{% for subnet in port['subnets'] %}
no network {{ subnet['cidr'] }} area 0.0.0.0
{% endfor %}
end
{% endblock %}
{% block add_ext_port %}
enable
conf t
interface {{ interface_name }}
ip ospf authentication-key polygon
ip ospf hello-interval 1
ip ospf dead-interval 4
router ospf
no passive-interface {{ interface_name }}
{% for subnet in ex_gw_port['subnets'] %}
network {{ subnet['cidr'] }} area 0.0.0.0
{% endfor %}
end
{% endblock %}
{% block delete_ext_port %}
enable
conf t
router ospf
passive-interface {{ interface_name }}
{% for subnet in ex_gw_port['subnets'] %}
no network {{ subnet['cidr'] }} area 0.0.0.0
{% endfor %}
no interface {{ interface_name }}
end
{% endblock %}

View File

@ -0,0 +1,25 @@
! -*- zebra -*-
!
! zebra sample configuration file
!
! $Id: zebra.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $
!
hostname Router
password zebra
enable password zebra
!
! Interface's description.
!
!interface lo
! description test of desc.
!
!interface sit0
! multicast
!
! Static default route sample.
!
!ip route 0.0.0.0/0 203.181.89.241
!
!log file /var/log/quagga/zebra.log

View File

@ -0,0 +1,24 @@
# Manifest that creates hiera config overrride
class plugin_detach_netnode::controller_override {
# Initial constants
$plugin_name = 'fuel-plugin-detach-netnode'
$plugin_settings = hiera_hash("${plugin_name}", {})
$hiera_dir = '/etc/hiera/plugins'
$hiera_content = inline_template("
neutron_controller_roles: ['controller','network-node','primary-controller', 'primary-network-node']
neutron_advanced_configuration:
l2_agent_ha: false
l3_agent_ha: false
dhcp_agent_ha: false
metadata_agent_ha: false
run_ping_checker: false
")
file { "${hiera_dir}/${plugin_name}.yaml":
ensure => file,
content => "${hiera_content}\n",
}
}

View File

@ -0,0 +1,91 @@
class plugin_detach_netnode::l3_quagga {
$plugin_settings = hiera('fuel-plugin-detach-netnode')
$password=$plugin_settings['quagga_password']
Exec { path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' }
if $plugin_settings['l3_agent_quagga'] == true {
package { "quagga":
ensure => present,
}
file {'quagga.py':
path => '/usr/lib/python2.7/dist-packages/neutron/agent/linux/quagga.py',
mode => '0644',
group => root,
source => 'puppet:///modules/plugin_detach_netnode/quagga.py',
require => Package["quagga"],
}
file {'quagga.filters':
path => '/etc/neutron/rootwrap.d/quagga.filters',
mode => '0644',
group => root,
source => 'puppet:///modules/plugin_detach_netnode/quagga.filters',
require => Package["quagga"],
}
file {'ospfd_idz.conf':
path => '/etc/quagga/ospfd_idz.conf',
mode => '0644',
group => root,
source => 'puppet:///modules/plugin_detach_netnode/ospfd_idz.conf',
require => Package["quagga"],
}
file_line {"ospfd_idz vty pass":
path => "/etc/quagga/ospfd_idz.conf",
line => "password $password",
match => "password ",
require => File["ospfd_idz.conf"],
}
file {'ospfd_ipz.conf':
path => '/etc/quagga/ospfd_ipz.conf',
mode => '0644',
group => root,
source => 'puppet:///modules/plugin_detach_netnode/ospfd_ipz.conf',
require => Package["quagga"],
}
file_line {"ospfd_ipz vty pass":
path => "/etc/quagga/ospfd_ipz.conf",
line => "password $password",
match => "password ",
require => File["ospfd_ipz.conf"],
}
file {'quagga.conf.template':
path => '/etc/neutron/quagga.conf.template',
mode => '0644',
group => root,
source => 'puppet:///modules/plugin_detach_netnode/quagga.conf.template',
require => Package["quagga"],
}
exec {"sed import quagga":
command => "sed -i '44i from neutron.agent.linux import quagga' /usr/lib/python2.7/dist-packages/neutron/agent/l3/agent.py",
require => Package["quagga"],
}
file_line {"adding quagga return":
path => "/usr/lib/python2.7/dist-packages/neutron/agent/l3/agent.py",
line => " return quagga.QuaggaRouter(*args, **kwargs)",
match => "return legacy_router.LegacyRouter.*",
require => Package["quagga"],
}
file {'zebra.conf':
path => '/etc/quagga/zebra.conf',
mode => '0755',
owner => root,
group => root,
source => '/usr/share/doc/quagga/examples/zebra.conf.sample',
require => Package["quagga"],
}
file {'ospfd.conf':
path => '/etc/quagga/ospfd.conf',
mode => '0644',
group => root,
source => 'puppet:///modules/plugin_detach_netnode/ospfd.conf',
require => Package["quagga"],
}
file {'/var/run/neutron-quagga':
ensure => directory,
require => Package["quagga"],
owner => 'neutron',
group => 'neutron',
}
}
}

View File

@ -0,0 +1,39 @@
class plugin_detach_netnode::network_node_hyperv {
$plugin_settings = hiera('fuel-plugin-detach-netnode')
Exec { path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' }
if $plugin_settings['hyperv_region'] == true {
$packages = ['gcc','python-dev','python-pip']
package { $packages:
ensure => present,
}->
file {"copy networking-hyperv.tar":
path => '/tmp/networking-hyperv.tar',
source => 'puppet:///modules/plugin_detach_netnode/networking-hyperv.tar',
}->
file {"copy dependencies":
path => '/tmp/networking_hyperv_dependecies.tar',
source => 'puppet:///modules/plugin_detach_netnode/networking_hyperv_dependecies.tar',
}->
exec {"uncompress networking_hyperv packages":
command => "tar -xf /tmp/networking-hyperv.tar -C /tmp/",
}->
exec {"uncompress networking_hyperv_dependecies":
command => "tar -xf /tmp/networking_hyperv_dependecies.tar -C /tmp/",
}->
exec {"install pbr":
command => "pip install --no-index --find-links='/tmp/networking_hyperv_dependecies' pbr==1.6.0",
}->
exec { 'install networking_hyperv':
command => 'python setup.py install',
cwd => '/tmp/networking-hyperv',
path => '/usr/bin',
}->
exec { "remove temp dir":
command => "/bin/rm -rf /tmp/networking-hyperv* /tmp/networking_hyperv*",
}
}
}

View File

@ -0,0 +1,29 @@
# Manifest that creates hiera config overrride
class plugin_detach_netnode::override {
# Initial constants
$plugin_name = 'fuel-plugin-detach-netnode'
$plugin_settings = hiera_hash("${plugin_name}", {})
$hiera_dir = '/etc/hiera/plugins'
$hiera_content = inline_template("
neutron_controller_roles: ['controller','network-node','primary-controller', 'primary-network-node']
neutron_advanced_configuration:
l2_agent_ha: true
l3_agent_ha: true
dhcp_agent_ha: true
metadata_agent_ha: true
run_ping_checker: false
colocate_haproxy: false
corosync_roles: ['network-node', 'primary-network-node']
neutron_primary_controller_roles: ['primary-network-node']
neutron_nodes:
<%= scope.function_hiera_hash(['network_metadata'])['nodes'].inject({}) {|res, (k, v)| res[v['name']] = v if (v['node_roles'] & ['controller','network-node','primary-network-node','primary-controller']).any?; res }.to_yaml.split('\n')[1..-1].join('\n') %>
")
file { "${hiera_dir}/${plugin_name}.yaml":
ensure => file,
content => "${hiera_content}\n",
}
}

208
deployment_tasks.yaml Normal file
View File

@ -0,0 +1,208 @@
# Skip L2, L3, DHCP and Metadata Neutron agents for controllers
- id: primary-openstack-network-agents-l3
role: ['primary-controller','controller']
type: skipped
version: 2.0.0
- id: openstack-network-agents-l3
role: ['primary-controller','controller']
type: skipped
version: 2.0.0
- id: primary-openstack-network-agents-dhcp
role: ['primary-controller','controller']
type: skipped
version: 2.0.0
- id: openstack-network-agents-dhcp
role: ['primary-controller','controller']
type: skipped
version: 2.0.0
- id: primary-openstack-network-agents-metadata
role: ['primary-controller','controller']
type: skipped
version: 2.0.0
- id: openstack-network-agents-metadata
role: ['primary-controller','controller']
type: skipped
version: 2.0.0
- id: neutron_key
type: puppet
version: 2.0.0
role: ['primary-controller']
requires: [hiera, globals, keystone]
required_for: [openstack-network-networks,openstack-network-routers]
parameters:
puppet_manifest: '/etc/puppet/modules/openstack_tasks/examples/openstack-network/keystone.pp'
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_pre
type: group
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['deploy_start']
required_for: ['network_node']
tasks: [hiera, globals, tools, logging, netconfig, hosts, firewall, ssl-keys-saving, ssl-add-trust-chain, fuel_pkgs]
parameters:
timeout: 3600
strategy:
type: one_by_one
- id: network_node_firewall
type: puppet
version: 2.0.0
role: ['primary-network-node','network-node']
requires: ['firewall']
required_for: ['network_node']
parameters:
puppet_manifest: 'puppet/manifests/firewall.pp'
puppet_modules: 'puppet/modules:/etc/puppet/modules'
timeout: 3600
- id: network_node_cluster
type: puppet
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['network_node_firewall']
required_for: ['network_node']
cross-depends:
- name: network_node_cluster
role: 'primary-network-node'
cross-depended-by:
- name: openstack-network-start
role: "/(primary-)?network-node/"
parameters:
puppet_manifest: '/etc/puppet/modules/osnailyfacter/modular/cluster/cluster.pp'
puppet_modules: '/etc/puppet/modules'
timeout: 3600
strategy:
type: one_by_one
- id: controller_override
type: puppet
version: 2.0.0
role: ['/^(primary-)?controller$/']
requires: ['globals']
required_for: ['netconfig']
parameters:
puppet_manifest: puppet/manifests/controller_override.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_override
type: puppet
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['globals']
required_for: ['netconfig']
parameters:
puppet_manifest: puppet/manifests/override.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node
type: group
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['network_node_pre','network_node_override']
required_for: ['deploy_end']
tasks: [openstack-network-start, openstack-network-common-config, openstack-network-server-config, openstack-network-plugins-l2]
parameters:
timeout: 3600
strategy:
type: one_by_one
- id: network_node_l3_agent
type: puppet
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['openstack-network-plugins-l2']
required_for: ['openstack-network-end']
cross-depends:
- name: 'network_node_l3_agent'
role: 'primary-network-node'
parameters:
puppet_manifest: '/etc/puppet/modules/openstack_tasks/examples/openstack-network/agents/l3.pp'
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_dhcp_agent
type: puppet
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['openstack-network-plugins-l2']
required_for: ['openstack-network-end']
cross-depends:
- name: 'network_node_dhcp_agent'
role: 'primary-network-node'
parameters:
puppet_manifest: '/etc/puppet/modules/openstack_tasks/examples/openstack-network/agents/dhcp.pp'
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_metadata_agent
type: puppet
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['network_node_cluster','neutron_key','network_node_dhcp_agent']
required_for: ['openstack-network-end']
cross-depends:
- name: 'network_node_metadata_agent'
role: 'primary-network-node'
parameters:
puppet_manifest: '/etc/puppet/modules/openstack_tasks/examples/openstack-network/agents/metadata.pp'
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_l3_quagga
type: puppet
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['network_node_metadata_agent']
required_for: ['post_deployment_start']
cross-depends:
- name: 'network_node_l3_quagga'
role: 'primary-network-node'
parameters:
puppet_manifest: puppet/manifests/l3_quagga.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_neutron_mtu
type: puppet
version: 2.0.0
role: ['primary-controller', 'controller']
requires: ['post_deployment_start']
required_for: ['post_deployment_end']
parameters:
puppet_manifest: puppet/manifests/neutron_mtu.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_neutron_networks
type: puppet
version: 2.0.0
role: ['primary-controller']
requires: ['network_node_neutron_mtu']
required_for: ['post_deployment_end']
parameters:
puppet_manifest: puppet/manifests/neutron_networks.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_netnode_networks
type: puppet
version: 2.0.0
role: ['/^(primary-)?network-node$/']
requires: ['post_deployment_start']
required_for: ['post_deployment_end']
parameters:
puppet_manifest: puppet/manifests/netnode_networks.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_hyperv
type: puppet
version: 2.0.0
role: ['primary-network-node','network-node','primary-controller','controller']
requires: ['post_deployment_start']
required_for: ['post_deployment_end','network_node_neutron_hyperv']
parameters:
puppet_manifest: puppet/manifests/network_node_hyperv.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600
- id: network_node_neutron_hyperv
type: puppet
version: 2.0.0
role: ['primary-network-node','network-node','primary-controller','controller']
requires: ['network_node_hyperv']
required_for: ['post_deployment_end']
parameters:
puppet_manifest: puppet/manifests/neutron_hyperv.pp
puppet_modules: puppet/modules:/etc/puppet/modules
timeout: 3600

16
environment_config.yaml Normal file
View File

@ -0,0 +1,16 @@
attributes:
metadata:
label: "The Detached Network Node Plugin"
description: Allow to deploy Openstack with detached network nodes for handling access to public network.
weight: 55
group: network
l3_agent_quagga:
type: "checkbox"
weight: 60
label: "Install quagga l3 agent"
value: false
hyperv_region:
type: "checkbox"
weight: 65
label: "Install networking_hyperv python package (for HyperV region only)"
value: false

31
metadata.yaml Normal file
View File

@ -0,0 +1,31 @@
name: fuel-plugin-detach-netnode
title: Enable Detached Network Node configuration.
version: 0.8.7
description: Allow to deploy Openstack with detached network nodes for handling access to public network.
fuel_version:
- '9.0'
licenses:
- Apache License, Version 2.0
authors:
- Yaroslav Ulanovich <yaraat@gmail.com>
homepage: https://github.com/sbrf-clouddev/fuel-plugin-detach-netnode
groups:
- network
releases:
- os: ubuntu
version: kilo-9.0
mode: ['ha']
deployment_scripts_path: deployment_scripts/
repository_path: repositories/ubuntu
- os: ubuntu
version: liberty-9.0
mode: ['ha']
deployment_scripts_path: deployment_scripts/
repository_path: repositories/ubuntu
- os: ubuntu
version: mitaka-9.0
mode: ['ha']
deployment_scripts_path: deployment_scripts/
repository_path: repositories/ubuntu
package_version: '4.0.0'
is_hotpluggable: false

15
node_roles.yaml Normal file
View File

@ -0,0 +1,15 @@
network-node:
name: Netwok Node
description: Detached Network Node
has_primary: true
public_ip_required: false
weight: 100 # weight that will be used for ordering on fuel ui
conflicts:
- primary-controller
- controller
- compute
limits:
min: 1
update_required:
- primary-controller
- controller

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@