Retire repo
This repo was created by accident, use deb-python-os-net-config instead. Needed-By: I1ac1a06931c8b6dd7c2e73620a0302c29e605f03 Change-Id: I81894aea69b9d09b0977039623c26781093a397a
This commit is contained in:
parent
9e1a613204
commit
b5418e5912
@ -1,7 +0,0 @@
|
||||
[run]
|
||||
branch = True
|
||||
source = os_net_config
|
||||
omit = os_net_config/tests/*,os_net_config/openstack/*
|
||||
|
||||
[report]
|
||||
ignore_errors = True
|
51
.gitignore
vendored
51
.gitignore
vendored
@ -1,51 +0,0 @@
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
parts
|
||||
bin
|
||||
var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
lib
|
||||
lib64
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
nosetests.xml
|
||||
.testrepository
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# Complexity
|
||||
output/*.html
|
||||
output/*/index.html
|
||||
|
||||
# Sphinx
|
||||
doc/build
|
||||
|
||||
# pbr generates these
|
||||
AUTHORS
|
||||
ChangeLog
|
||||
|
||||
# Editors
|
||||
*~
|
||||
.*.swp
|
@ -1,4 +0,0 @@
|
||||
[gerrit]
|
||||
host=review.openstack.org
|
||||
port=29418
|
||||
project=openstack/os-net-config.git
|
3
.mailmap
3
.mailmap
@ -1,3 +0,0 @@
|
||||
# Format is:
|
||||
# <preferred e-mail> <other e-mail 1>
|
||||
# <preferred e-mail> <other e-mail 2>
|
@ -1,7 +0,0 @@
|
||||
[DEFAULT]
|
||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
||||
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
|
||||
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
|
||||
${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
@ -1,16 +0,0 @@
|
||||
If you would like to contribute to the development of OpenStack,
|
||||
you must follow the steps in this page:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html
|
||||
|
||||
Once those steps have been completed, changes to OpenStack
|
||||
should be submitted for review via the Gerrit tool, following
|
||||
the workflow documented at:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html#development-workflow
|
||||
|
||||
Pull requests submitted through GitHub will be ignored.
|
||||
|
||||
Bugs should be filed on Launchpad, not GitHub:
|
||||
|
||||
https://bugs.launchpad.net/os-net-config
|
@ -1,4 +0,0 @@
|
||||
os-net-config Style Commandments
|
||||
===============================================
|
||||
|
||||
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
|
175
LICENSE
175
LICENSE
@ -1,175 +0,0 @@
|
||||
|
||||
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.
|
@ -1,6 +0,0 @@
|
||||
include AUTHORS
|
||||
include ChangeLog
|
||||
exclude .gitignore
|
||||
exclude .gitreview
|
||||
|
||||
global-exclude *.pyc
|
111
README.rst
111
README.rst
@ -1,111 +0,0 @@
|
||||
===============================
|
||||
os-net-config
|
||||
===============================
|
||||
|
||||
host network configuration tool
|
||||
|
||||
An implementation of the 'network configuration' spec @
|
||||
https://review.openstack.org/#/c/97859/.
|
||||
The intention is for this code to be moved under the tripleo project in due course.
|
||||
|
||||
* Free software: Apache license
|
||||
* Documentation: http://docs.openstack.org/developer/os-net-config
|
||||
* Source: http://git.openstack.org/cgit/openstack/os-net-config
|
||||
* Bugs: http://bugs.launchpad.net/os-net-config
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
The core aim of this project is to allow fine grained (but extendable)
|
||||
configuration of the networking parameters for a network host. The
|
||||
project consists of:
|
||||
|
||||
* A CLI (os-net-config) which provides configuration via a YAML or JSON
|
||||
file formats. By default os-net-config uses a YAML config file located
|
||||
at /etc/os-net-config/config.yaml. This can be customized via the
|
||||
--config-file CLI option.
|
||||
|
||||
* A python library which provides configuration via an object model.
|
||||
|
||||
YAML Config Examples
|
||||
--------------------
|
||||
* Configure an OVS bridge with a single attached interface (port)
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
ovs_extra:
|
||||
- br-set-external-id br-ctlplane bridge-id br-ctlplane
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
||||
|
||||
..
|
||||
|
||||
|
||||
* Configure an OVS bridge on top of an OVS bond
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: ovs_bond
|
||||
name: bond1
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
||||
-
|
||||
type: interface
|
||||
name: em2
|
||||
|
||||
..
|
||||
|
||||
* Configure a tagged VLAN interface on top of an OVS bridge
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
||||
-
|
||||
type: vlan
|
||||
vlan_id: 16
|
||||
addresses:
|
||||
-
|
||||
ip_netmask: 192.0.2.1/24
|
||||
|
||||
..
|
||||
|
||||
Provider Configuration
|
||||
----------------------
|
||||
Providers are use to apply (implement) the desired configuration on the
|
||||
host system. By default 3 providers are implemented:
|
||||
|
||||
* Ifcfg: persistent network config format stored in
|
||||
/etc/sysconfig/network-scripts
|
||||
|
||||
* ENI: persistent network config format stored in /etc/network/interfaces
|
||||
|
||||
* iproute2: non-persistent provider which implements the config using
|
||||
iproute2, vconfig, etc... (implementation in progress)
|
||||
|
||||
When using bin/os-net-config the provider is automatically selected based on
|
||||
the host systems perferred persistent network type (ifcfg or ENI). This can
|
||||
be customized via the --provider CLI option.
|
13
README.txt
Normal file
13
README.txt
Normal file
@ -0,0 +1,13 @@
|
||||
This project is no longer maintained.
|
||||
|
||||
The contents of this repository are still available in the Git
|
||||
source code management system. To see the contents of this
|
||||
repository before it reached its end of life, please check out the
|
||||
previous commit with "git checkout HEAD^1".
|
||||
|
||||
Use instead the project deb-python-os-net-config at
|
||||
http://git.openstack.org/cgit/openstack/deb-python-os-net-config .
|
||||
|
||||
For any further questions, please email
|
||||
openstack-dev@lists.openstack.org or join #openstack-dev on
|
||||
Freenode.
|
@ -1,75 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 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 sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
#'sphinx.ext.intersphinx',
|
||||
'oslosphinx'
|
||||
]
|
||||
|
||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||
# text edit cycles.
|
||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'os-net-config'
|
||||
copyright = u'2013, OpenStack Foundation'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
# html_theme_path = ["."]
|
||||
# html_theme = '_theme'
|
||||
# html_static_path = ['static']
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index',
|
||||
'%s.tex' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'OpenStack Foundation', 'manual'),
|
||||
]
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
@ -1,4 +0,0 @@
|
||||
============
|
||||
Contributing
|
||||
============
|
||||
.. include:: ../../CONTRIBUTING.rst
|
@ -1,24 +0,0 @@
|
||||
.. os-net-config documentation master file, created by
|
||||
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to os-net-config's documentation!
|
||||
========================================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
readme
|
||||
installation
|
||||
usage
|
||||
contributing
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
@ -1,12 +0,0 @@
|
||||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
At the command line::
|
||||
|
||||
$ pip install os-net-config
|
||||
|
||||
Or, if you have virtualenvwrapper installed::
|
||||
|
||||
$ mkvirtualenv os-net-config
|
||||
$ pip install os-net-config
|
@ -1 +0,0 @@
|
||||
.. include:: ../../README.rst
|
@ -1,7 +0,0 @@
|
||||
========
|
||||
Usage
|
||||
========
|
||||
|
||||
To use os-net-config in a project::
|
||||
|
||||
import os_net_config
|
@ -1,19 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "ovs_bridge",
|
||||
"name": "br-ctlplane",
|
||||
"use_dhcp": "true",
|
||||
"members": [
|
||||
{
|
||||
"type": "ovs_bond",
|
||||
"name": "bond1",
|
||||
"use_dhcp": "true",
|
||||
"members": [
|
||||
{ "type": "interface", "name": "em1" },
|
||||
{ "type": "interface", "name": "em2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: ovs_bond
|
||||
name: bond1
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
||||
-
|
||||
type: interface
|
||||
name: em2
|
@ -1,23 +0,0 @@
|
||||
# Example showing use of the optional nicN abstraction
|
||||
# for device naming, which defaults to an ordered
|
||||
# translation to biodev names based on which interfaces
|
||||
# are active on the system.
|
||||
# Optionally the default mapping may be overriden by
|
||||
# a mapping file via the -m option.
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: ovs_bond
|
||||
name: bond1
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: nic1
|
||||
-
|
||||
type: interface
|
||||
name: nic2
|
@ -1,17 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "ovs_bridge",
|
||||
"name": "br-ctlplane",
|
||||
"ovs_extra": [
|
||||
"br-set-external-id br-ctlplane bridge-id br-ctlplane"
|
||||
],
|
||||
"use_dhcp": "true",
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
ovs_extra:
|
||||
- br-set-external-id br-ctlplane bridge-id br-ctlplane
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
@ -1,25 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "ovs_bridge",
|
||||
"name": "br-ctlplane",
|
||||
"use_dhcp": "true",
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em1"
|
||||
},
|
||||
{
|
||||
"type": "vlan",
|
||||
"vlan_id": 16,
|
||||
"addresses": [{
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}]
|
||||
}
|
||||
],
|
||||
"routes": [{
|
||||
"next_hop": "192.0.2.1",
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
||||
-
|
||||
type: vlan
|
||||
vlan_id: 16
|
||||
addresses:
|
||||
-
|
||||
ip_netmask: 192.0.2.1/24
|
||||
routes:
|
||||
-
|
||||
next_hop: 192.0.2.1
|
||||
ip_netmask: 192.0.2.1/24
|
@ -1,26 +0,0 @@
|
||||
{"network_config": [
|
||||
{
|
||||
"type": "ib_interface",
|
||||
"name": "ib0",
|
||||
"use_dhcp": false,
|
||||
"addresses": [
|
||||
{
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"ip_netmask": "0.0.0.0/0",
|
||||
"next_hop": "192.0.2.254",
|
||||
"default": "true"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "ib_interface",
|
||||
"name": "ib1",
|
||||
"use_dhcp": true,
|
||||
"defroute": no
|
||||
}
|
||||
]
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: ib_interface
|
||||
name: ib0
|
||||
use_dhcp: false
|
||||
addresses:
|
||||
-
|
||||
ip_netmask: 192.0.2.1/24
|
||||
routes:
|
||||
-
|
||||
ip_netmask: 0.0.0.0/0
|
||||
next_hop: 192.0.2.254
|
||||
default: true
|
||||
-
|
||||
type: interface
|
||||
name: ib1
|
||||
use_dhcp: true
|
||||
defroute: no
|
@ -1,26 +0,0 @@
|
||||
{"network_config": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em1",
|
||||
"use_dhcp": false,
|
||||
"addresses": [
|
||||
{
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"ip_netmask": "0.0.0.0/0",
|
||||
"next_hop": "192.0.2.254",
|
||||
"default": "true"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em2",
|
||||
"use_dhcp": true,
|
||||
"defroute": no
|
||||
}
|
||||
]
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
||||
use_dhcp: false
|
||||
addresses:
|
||||
-
|
||||
ip_netmask: 192.0.2.1/24
|
||||
routes:
|
||||
-
|
||||
ip_netmask: 0.0.0.0/0
|
||||
next_hop: 192.0.2.254
|
||||
default: true
|
||||
-
|
||||
type: interface
|
||||
name: em2
|
||||
use_dhcp: true
|
||||
defroute: no
|
@ -1,37 +0,0 @@
|
||||
{
|
||||
"network_config": [
|
||||
{
|
||||
"type": "ivs_bridge",
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "nic2",
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "nic3"
|
||||
},
|
||||
{
|
||||
"type": "ivs_interface",
|
||||
"name": "api",
|
||||
"addresses": [
|
||||
{
|
||||
"ip_netmask": "172.16.2.7/24"
|
||||
}
|
||||
],
|
||||
"vlan_id": 201
|
||||
},
|
||||
{
|
||||
"type": "ivs_interface",
|
||||
"name": "storage",
|
||||
"addresses": [
|
||||
{
|
||||
"ip_netmask": "172.16.1.6/24"
|
||||
}
|
||||
],
|
||||
"vlan_id": 202
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: ivs_bridge
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: nic2
|
||||
-
|
||||
type: interface
|
||||
name: nic3
|
||||
-
|
||||
type: ivs_interface
|
||||
name: api
|
||||
vlan_id: 201
|
||||
addresses:
|
||||
-
|
||||
ip_netmask: 172.16.2.7/24
|
||||
-
|
||||
type: ivs_interface
|
||||
name: storage
|
||||
vlan_id: 202
|
||||
addresses:
|
||||
-
|
||||
ip_netmask: 172.16.1.6/24
|
@ -1,13 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: linux_bond
|
||||
name: bond1
|
||||
use_dhcp: true
|
||||
bonding_options: "mode=active-backup"
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
||||
-
|
||||
type: interface
|
||||
name: em2
|
@ -1,9 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: linux_bridge
|
||||
name: br-ctlplane
|
||||
use_dhcp: true
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
@ -1,12 +0,0 @@
|
||||
# This can be used with the -m option to override the
|
||||
# default mapping of the nicN aliases in configs
|
||||
# The mapping can specify either a device name or a mac address
|
||||
# If --persist-mapping is specified, we write the device aliases
|
||||
# config instead of the system names, e.g we actually configure
|
||||
# nic1 intead of em3. This is probably best used with --cleanup
|
||||
# to remove the stale configs e.g for em3
|
||||
interface_mapping:
|
||||
nic1: em3
|
||||
nic2: em1
|
||||
nic3: 12:34:56:de:f0:12
|
||||
nic4: 12:34:56:78:9a:bc
|
@ -1,38 +0,0 @@
|
||||
{
|
||||
"network_config": [
|
||||
{
|
||||
"type": "nfvswitch_bridge",
|
||||
"cpus": "2,3,4,5",
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "nic2",
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "nic3"
|
||||
},
|
||||
{
|
||||
"type": "nfvswitch_internal",
|
||||
"name": "api",
|
||||
"addresses": [
|
||||
{
|
||||
"ip_netmask": "172.16.2.7/24"
|
||||
}
|
||||
],
|
||||
"vlan_id": 201
|
||||
},
|
||||
{
|
||||
"type": "nfvswitch_internal",
|
||||
"name": "storage",
|
||||
"addresses": [
|
||||
{
|
||||
"ip_netmask": "172.16.1.6/24"
|
||||
}
|
||||
],
|
||||
"vlan_id": 202
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: nfvswitch_bridge
|
||||
cpus: "2,3,4,5"
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: nic2
|
||||
-
|
||||
type: interface
|
||||
name: nic3
|
||||
-
|
||||
type: nfvswitch_internal
|
||||
name: api
|
||||
vlan_id: 201
|
||||
addresses:
|
||||
-
|
||||
ip_netmask: 172.16.2.7/24
|
||||
-
|
||||
type: nfvswitch_internal
|
||||
name: storage
|
||||
vlan_id: 202
|
||||
addresses:
|
||||
-
|
||||
ip_netmask: 172.16.1.6/24
|
@ -1,37 +0,0 @@
|
||||
{
|
||||
"network_config": [
|
||||
{
|
||||
"name": "br-ctlplane",
|
||||
"type": "ovs_bridge",
|
||||
"members": [
|
||||
{
|
||||
"mtu": 1500,
|
||||
"primary": "true",
|
||||
"name": "eth1",
|
||||
"type": "interface"
|
||||
}
|
||||
],
|
||||
"ovs_extra": [
|
||||
"br-set-external-id br-ctlplane bridge-id br-ctlplane"
|
||||
],
|
||||
"mtu": 1500,
|
||||
"addresses": [
|
||||
{
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "br_pub-patch",
|
||||
"type": "ovs_patch_port",
|
||||
"bridge_name": "br-ctlplane",
|
||||
"peer": "br-ctlplane-patch"
|
||||
},
|
||||
{
|
||||
"name": "br-ctlplane-patch",
|
||||
"type": "ovs_patch_port",
|
||||
"bridge_name": "br_pub",
|
||||
"peer": "br_pub-patch"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
network_config:
|
||||
-
|
||||
type: ovs_bridge
|
||||
name: br-ctlplane
|
||||
mtu: 1500
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: eth1
|
||||
# force the MAC address of the bridge to this interface
|
||||
primary: true
|
||||
mtu: 1500
|
||||
ovs_extra: "br-set-external-id br-ctlplane bridge-id br-ctlplane"
|
||||
-
|
||||
type: ovs_patch_port
|
||||
name: br_pub-patch
|
||||
bridge_name: br-ctlplane
|
||||
peer: br-ctlplane-patch
|
||||
-
|
||||
type: ovs_patch_port
|
||||
name: br-ctlplane-patch
|
||||
bridge_name: br_pub
|
||||
peer: br_pub-patch
|
@ -1,13 +0,0 @@
|
||||
{ "network_config": [
|
||||
{
|
||||
"type": "team",
|
||||
"name": "team1",
|
||||
"use_dhcp": true,
|
||||
"bonding_options": "{\"runner\": {\"name\": \"activebackup\"}}",
|
||||
"members": [
|
||||
{ "type": "interface", "name": "em1", "primary": true },
|
||||
{ "type": "interface", "name": "em2" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
# Config for bonding with teamd. Bonding options are provided as a JSON
|
||||
# string. The following runners are available in teamd: broadcast,
|
||||
# roundrobin, activebackup, loadbalance, and lacp.
|
||||
# Please see the teamd.conf(5) man page for more information.
|
||||
network_config:
|
||||
-
|
||||
type: team
|
||||
name: team1
|
||||
use_dhcp: true
|
||||
bonding_options: '{"runner": {"name": "activebackup"}}'
|
||||
members:
|
||||
-
|
||||
type: interface
|
||||
name: em1
|
||||
primary: true
|
||||
-
|
||||
type: interface
|
||||
name: em2
|
@ -1,233 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014-2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 os
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from os_net_config import objects
|
||||
from os_net_config import utils
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NotImplemented(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NetConfig(object):
|
||||
"""Common network config methods class."""
|
||||
|
||||
def __init__(self, noop=False, root_dir=''):
|
||||
self.noop = noop
|
||||
self.log_prefix = "NOOP: " if noop else ""
|
||||
self.root_dir = root_dir
|
||||
|
||||
def add_object(self, obj):
|
||||
"""Convenience method to add any type of object to the network config.
|
||||
|
||||
See objects.py.
|
||||
|
||||
:param obj: The object to add.
|
||||
"""
|
||||
if isinstance(obj, objects.Interface):
|
||||
self.add_interface(obj)
|
||||
elif isinstance(obj, objects.Vlan):
|
||||
self.add_vlan(obj)
|
||||
elif isinstance(obj, objects.IvsInterface):
|
||||
self.add_ivs_interface(obj)
|
||||
elif isinstance(obj, objects.NfvswitchInternal):
|
||||
self.add_nfvswitch_internal(obj)
|
||||
elif isinstance(obj, objects.OvsBridge):
|
||||
self.add_bridge(obj)
|
||||
for member in obj.members:
|
||||
self.add_object(member)
|
||||
elif isinstance(obj, objects.LinuxBridge):
|
||||
self.add_linux_bridge(obj)
|
||||
for member in obj.members:
|
||||
self.add_object(member)
|
||||
elif isinstance(obj, objects.IvsBridge):
|
||||
self.add_ivs_bridge(obj)
|
||||
for member in obj.members:
|
||||
self.add_object(member)
|
||||
elif isinstance(obj, objects.NfvswitchBridge):
|
||||
self.add_nfvswitch_bridge(obj)
|
||||
for member in obj.members:
|
||||
self.add_object(member)
|
||||
elif isinstance(obj, objects.OvsBond):
|
||||
self.add_bond(obj)
|
||||
for member in obj.members:
|
||||
self.add_object(member)
|
||||
elif isinstance(obj, objects.LinuxBond):
|
||||
self.add_linux_bond(obj)
|
||||
for member in obj.members:
|
||||
self.add_object(member)
|
||||
elif isinstance(obj, objects.LinuxTeam):
|
||||
self.add_linux_team(obj)
|
||||
for member in obj.members:
|
||||
self.add_object(member)
|
||||
elif isinstance(obj, objects.OvsTunnel):
|
||||
self.add_ovs_tunnel(obj)
|
||||
elif isinstance(obj, objects.OvsPatchPort):
|
||||
self.add_ovs_patch_port(obj)
|
||||
elif isinstance(obj, objects.IbInterface):
|
||||
self.add_ib_interface(obj)
|
||||
|
||||
def add_interface(self, interface):
|
||||
"""Add an Interface object to the net config object.
|
||||
|
||||
:param interface: The Interface object to add.
|
||||
"""
|
||||
raise NotImplemented("add_interface is not implemented.")
|
||||
|
||||
def add_vlan(self, vlan):
|
||||
"""Add a Vlan object to the net config object.
|
||||
|
||||
:param vlan: The vlan object to add.
|
||||
"""
|
||||
raise NotImplemented("add_vlan is not implemented.")
|
||||
|
||||
def add_bridge(self, bridge):
|
||||
"""Add an OvsBridge object to the net config object.
|
||||
|
||||
:param bridge: The OvsBridge object to add.
|
||||
"""
|
||||
raise NotImplemented("add_bridge is not implemented.")
|
||||
|
||||
def add_linux_bridge(self, bridge):
|
||||
"""Add a LinuxBridge object to the net config object.
|
||||
|
||||
:param bridge: The LinuxBridge object to add.
|
||||
"""
|
||||
raise NotImplemented("add_linux_bridge is not implemented.")
|
||||
|
||||
def add_ivs_bridge(self, bridge):
|
||||
"""Add a IvsBridge object to the net config object.
|
||||
|
||||
:param bridge: The IvsBridge object to add.
|
||||
"""
|
||||
raise NotImplemented("add_ivs_bridge is not implemented.")
|
||||
|
||||
def add_nfvswitch_bridge(self, bridge):
|
||||
"""Add a NfvswitchBridge object to the net config object.
|
||||
|
||||
:param bridge: The NfvswitchBridge object to add.
|
||||
"""
|
||||
raise NotImplemented("add_nfvswitch_bridge is not implemented.")
|
||||
|
||||
def add_bond(self, bond):
|
||||
"""Add an OvsBond object to the net config object.
|
||||
|
||||
:param bond: The OvsBond object to add.
|
||||
"""
|
||||
raise NotImplemented("add_bond is not implemented.")
|
||||
|
||||
def add_linux_bond(self, bond):
|
||||
"""Add a LinuxBond object to the net config object.
|
||||
|
||||
:param bond: The LinuxBond object to add.
|
||||
"""
|
||||
raise NotImplemented("add_linux_bond is not implemented.")
|
||||
|
||||
def add_linux_team(self, team):
|
||||
"""Add a LinuxTeam object to the net config object.
|
||||
|
||||
:param team: The LinuxTeam object to add.
|
||||
"""
|
||||
raise NotImplemented("add_linux_team is not implemented.")
|
||||
|
||||
def add_ovs_tunnel(self, tunnel):
|
||||
"""Add a OvsTunnel object to the net config object.
|
||||
|
||||
:param tunnel: The OvsTunnel object to add.
|
||||
"""
|
||||
raise NotImplemented("add_ovs_tunnel is not implemented.")
|
||||
|
||||
def add_ovs_patch_port(self, ovs_patch_port):
|
||||
"""Add a OvsPatchPort object to the net config object.
|
||||
|
||||
:param ovs_patch_port: The OvsPatchPort object to add.
|
||||
"""
|
||||
raise NotImplemented("add_ovs_patch_port is not implemented.")
|
||||
|
||||
def add_ib_interface(self, ib_interface):
|
||||
"""Add an InfiniBand Interface object to the net config object.
|
||||
|
||||
:param interface: The InfiniBand Interface object to add.
|
||||
"""
|
||||
raise NotImplemented("add_ib_interface is not implemented.")
|
||||
|
||||
def apply(self, cleanup=False):
|
||||
"""Apply the network configuration.
|
||||
|
||||
:param cleanup: A boolean which indicates whether any undefined
|
||||
(existing but not present in the object model) interfaces
|
||||
should be disabled and deleted.
|
||||
:returns: a dict of the format: filename/data which contains info
|
||||
for each file that was changed (or would be changed if in --noop
|
||||
mode).
|
||||
"""
|
||||
raise NotImplemented("apply is not implemented.")
|
||||
|
||||
def execute(self, msg, cmd, *args, **kwargs):
|
||||
"""Print a message and run a command.
|
||||
|
||||
Print a message and run a command with processutils
|
||||
in noop mode, this just prints a message.
|
||||
"""
|
||||
logger.info('%s%s' % (self.log_prefix, msg))
|
||||
if not self.noop:
|
||||
processutils.execute(cmd, *args, **kwargs)
|
||||
|
||||
def write_config(self, filename, data, msg=None):
|
||||
msg = msg or "Writing config %s" % filename
|
||||
logger.info('%s%s' % (self.log_prefix, msg))
|
||||
if not self.noop:
|
||||
utils.write_config(filename, data)
|
||||
|
||||
def remove_config(self, filename, msg=None):
|
||||
msg = msg or "Removing config %s" % filename
|
||||
logger.info('%s%s' % (self.log_prefix, msg))
|
||||
if not self.noop:
|
||||
os.remove(filename)
|
||||
|
||||
def ifdown(self, interface, iftype='interface'):
|
||||
msg = 'running ifdown on %s: %s' % (iftype, interface)
|
||||
self.execute(msg, '/sbin/ifdown', interface, check_exit_code=False)
|
||||
|
||||
def ifup(self, interface, iftype='interface'):
|
||||
msg = 'running ifup on %s: %s' % (iftype, interface)
|
||||
self.execute(msg, '/sbin/ifup', interface)
|
||||
|
||||
def ifrename(self, oldname, newname):
|
||||
msg = 'renaming %s to %s: ' % (oldname, newname)
|
||||
# ifdown isn't enough when renaming, we need the link down
|
||||
for name in (oldname, newname):
|
||||
if utils._is_active_nic(name):
|
||||
self.execute(msg, '/sbin/ip',
|
||||
'link', 'set', 'dev', name, 'down')
|
||||
self.execute(msg, '/sbin/ip',
|
||||
'link', 'set', 'dev', name, 'link', 'down')
|
||||
self.execute(msg, '/sbin/ip',
|
||||
'link', 'set', 'dev', oldname, 'name', newname)
|
||||
self.execute(msg, '/sbin/ip',
|
||||
'link', 'set', 'dev', newname, 'up')
|
||||
|
||||
def ovs_appctl(self, action, *parameters):
|
||||
msg = 'Running ovs-appctl %s %s' % (action, parameters)
|
||||
self.execute(msg, '/bin/ovs-appctl', action, *parameters)
|
@ -1,201 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014-2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import yaml
|
||||
|
||||
from os_net_config import impl_eni
|
||||
from os_net_config import impl_ifcfg
|
||||
from os_net_config import impl_iproute
|
||||
from os_net_config import objects
|
||||
from os_net_config import version
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def parse_opts(argv):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Configure host network interfaces using a JSON'
|
||||
' config file format.')
|
||||
parser.add_argument('-c', '--config-file', metavar='CONFIG_FILE',
|
||||
help="""path to the configuration file.""",
|
||||
default='/etc/os-net-config/config.yaml')
|
||||
parser.add_argument('-m', '--mapping-file', metavar='MAPPING_FILE',
|
||||
help="""path to the interface mapping file.""",
|
||||
default='/etc/os-net-config/mapping.yaml')
|
||||
parser.add_argument('-p', '--provider', metavar='PROVIDER',
|
||||
help="""The provider to use."""
|
||||
"""One of: ifcfg, eni, iproute.""",
|
||||
default=None)
|
||||
parser.add_argument('-r', '--root-dir', metavar='ROOT_DIR',
|
||||
help="""The root directory of the filesystem.""",
|
||||
default='')
|
||||
parser.add_argument('--detailed-exit-codes',
|
||||
action='store_true',
|
||||
help="""Enable detailed exit codes. """
|
||||
"""If enabled an exit code of '2' means """
|
||||
"""that files were modified."""
|
||||
"""Disabled by default.""",
|
||||
default=False)
|
||||
parser.add_argument(
|
||||
'-d', '--debug',
|
||||
dest="debug",
|
||||
action='store_true',
|
||||
help="Print debugging output.",
|
||||
required=False)
|
||||
parser.add_argument(
|
||||
'-v', '--verbose',
|
||||
dest="verbose",
|
||||
action='store_true',
|
||||
help="Print verbose output.",
|
||||
required=False)
|
||||
|
||||
parser.add_argument('--version', action='version',
|
||||
version=version.version_info.version_string())
|
||||
parser.add_argument(
|
||||
'--noop',
|
||||
dest="noop",
|
||||
action='store_true',
|
||||
help="Return the configuration commands, without applying them.",
|
||||
required=False)
|
||||
|
||||
parser.add_argument(
|
||||
'--no-activate',
|
||||
dest="no_activate",
|
||||
action='store_true',
|
||||
help="Install the configuration but don't start/stop interfaces.",
|
||||
required=False)
|
||||
|
||||
parser.add_argument(
|
||||
'--cleanup',
|
||||
dest="cleanup",
|
||||
action='store_true',
|
||||
help="Cleanup unconfigured interfaces.",
|
||||
required=False)
|
||||
|
||||
parser.add_argument(
|
||||
'--persist-mapping',
|
||||
dest="persist_mapping",
|
||||
action='store_true',
|
||||
help="Make aliases defined in the mapping file permanent "
|
||||
"(WARNING, permanently renames nics).",
|
||||
required=False)
|
||||
|
||||
opts = parser.parse_args(argv[1:])
|
||||
|
||||
return opts
|
||||
|
||||
|
||||
def configure_logger(verbose=False, debug=False):
|
||||
LOG_FORMAT = '[%(asctime)s] [%(levelname)s] %(message)s'
|
||||
DATE_FORMAT = '%Y/%m/%d %I:%M:%S %p'
|
||||
log_level = logging.WARN
|
||||
|
||||
if debug:
|
||||
log_level = logging.DEBUG
|
||||
elif verbose:
|
||||
log_level = logging.INFO
|
||||
|
||||
logging.basicConfig(format=LOG_FORMAT, datefmt=DATE_FORMAT,
|
||||
level=log_level)
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
opts = parse_opts(argv)
|
||||
configure_logger(opts.verbose, opts.debug)
|
||||
logger.info('Using config file at: %s' % opts.config_file)
|
||||
if opts.mapping_file:
|
||||
logger.info('Using mapping file at: %s' % opts.mapping_file)
|
||||
iface_array = []
|
||||
|
||||
provider = None
|
||||
if opts.provider:
|
||||
if opts.provider == 'ifcfg':
|
||||
provider = impl_ifcfg.IfcfgNetConfig(noop=opts.noop,
|
||||
root_dir=opts.root_dir)
|
||||
elif opts.provider == 'eni':
|
||||
provider = impl_eni.ENINetConfig(noop=opts.noop,
|
||||
root_dir=opts.root_dir)
|
||||
elif opts.provider == 'iproute':
|
||||
provider = impl_iproute.IPRouteNetConfig(noop=opts.noop,
|
||||
root_dir=opts.root_dir)
|
||||
else:
|
||||
logger.error('Invalid provider specified.')
|
||||
return 1
|
||||
else:
|
||||
if os.path.exists('%s/etc/sysconfig/network-scripts/' % opts.root_dir):
|
||||
provider = impl_ifcfg.IfcfgNetConfig(noop=opts.noop,
|
||||
root_dir=opts.root_dir)
|
||||
elif os.path.exists('%s/etc/network/' % opts.root_dir):
|
||||
provider = impl_eni.ENINetConfig(noop=opts.noop,
|
||||
root_dir=opts.root_dir)
|
||||
else:
|
||||
logger.error('Unable to set provider for this operating system.')
|
||||
return 1
|
||||
|
||||
# Read config file containing network configs to apply
|
||||
if os.path.exists(opts.config_file):
|
||||
with open(opts.config_file) as cf:
|
||||
iface_array = yaml.load(cf.read()).get("network_config")
|
||||
logger.debug('network_config JSON: %s' % str(iface_array))
|
||||
else:
|
||||
logger.error('No config file exists at: %s' % opts.config_file)
|
||||
return 1
|
||||
|
||||
if not isinstance(iface_array, list):
|
||||
logger.error('No interfaces defined in config: %s' % opts.config_file)
|
||||
return 1
|
||||
|
||||
# Read the interface mapping file, if it exists
|
||||
# This allows you to override the default network naming abstraction
|
||||
# mappings by specifying a specific nicN->name or nicN->MAC mapping
|
||||
if os.path.exists(opts.mapping_file):
|
||||
with open(opts.mapping_file) as cf:
|
||||
iface_map = yaml.load(cf.read())
|
||||
iface_mapping = iface_map.get("interface_mapping")
|
||||
logger.debug('interface_mapping JSON: %s' % str(iface_mapping))
|
||||
persist_mapping = opts.persist_mapping
|
||||
logger.debug('persist_mapping: %s' % persist_mapping)
|
||||
else:
|
||||
iface_mapping = None
|
||||
persist_mapping = False
|
||||
|
||||
for iface_json in iface_array:
|
||||
iface_json.update({'nic_mapping': iface_mapping})
|
||||
iface_json.update({'persist_mapping': persist_mapping})
|
||||
obj = objects.object_from_json(iface_json)
|
||||
provider.add_object(obj)
|
||||
files_changed = provider.apply(cleanup=opts.cleanup,
|
||||
activate=not opts.no_activate)
|
||||
if opts.noop:
|
||||
for location, data in files_changed.iteritems():
|
||||
print("File: %s\n" % location)
|
||||
print(data)
|
||||
print("----")
|
||||
|
||||
if opts.detailed_exit_codes and len(files_changed) > 0:
|
||||
return 2
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -1,241 +0,0 @@
|
||||
# -*- Coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014-2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 netaddr
|
||||
import os_net_config
|
||||
from os_net_config import objects
|
||||
from os_net_config import utils
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO(?): should move to interfaces.d
|
||||
def _network_config_path(prefix=''):
|
||||
return prefix + "/etc/network/interfaces"
|
||||
|
||||
|
||||
class ENINetConfig(os_net_config.NetConfig):
|
||||
"""Debian/Ubuntu implementation for network config
|
||||
|
||||
Configure iface/bridge/routes using debian/ubuntu
|
||||
/etc/network/interfaces format.
|
||||
"""
|
||||
|
||||
def __init__(self, noop=False, root_dir=''):
|
||||
super(ENINetConfig, self).__init__(noop, root_dir)
|
||||
self.interfaces = {}
|
||||
self.routes = {}
|
||||
self.bridges = {}
|
||||
logger.info('ENI net config provider created.')
|
||||
|
||||
def _add_common(self, interface, static_addr=None, ip_version=4):
|
||||
|
||||
ovs_extra = []
|
||||
data = ""
|
||||
address_data = ""
|
||||
if static_addr:
|
||||
address_data += " address %s\n" % static_addr.ip
|
||||
if ip_version == 6:
|
||||
address_data += " netmask %s\n" % static_addr.prefixlen
|
||||
else:
|
||||
address_data += " netmask %s\n" % static_addr.netmask
|
||||
else:
|
||||
v4_addresses = interface.v4_addresses()
|
||||
if v4_addresses:
|
||||
for v4_address in v4_addresses:
|
||||
data += self._add_common(interface, v4_address)
|
||||
|
||||
v6_addresses = interface.v6_addresses()
|
||||
if v6_addresses:
|
||||
for v6_address in v6_addresses:
|
||||
data += self._add_common(interface, v6_address, 6)
|
||||
|
||||
if data:
|
||||
return data
|
||||
|
||||
if isinstance(interface, objects.Vlan):
|
||||
_iface = "iface vlan%i " % interface.vlan_id
|
||||
else:
|
||||
_iface = "iface %s " % interface.name
|
||||
if static_addr and static_addr.version == 6:
|
||||
_iface += "inet6 "
|
||||
else:
|
||||
_iface += "inet "
|
||||
if interface.use_dhcp:
|
||||
_iface += "dhcp\n"
|
||||
elif interface.addresses:
|
||||
_iface += "static\n"
|
||||
else:
|
||||
_iface += "manual\n"
|
||||
if isinstance(interface, objects.OvsBridge):
|
||||
data += "auto %s\n" % interface.name
|
||||
data += "allow-ovs %s\n" % interface.name
|
||||
data += _iface
|
||||
data += address_data
|
||||
data += " ovs_type OVSBridge\n"
|
||||
if interface.members:
|
||||
data += " ovs_ports"
|
||||
for i in interface.members:
|
||||
data += " %s" % i.name
|
||||
data += "\n"
|
||||
for mem in interface.members:
|
||||
if isinstance(mem, objects.Interface):
|
||||
data += " pre-up ip addr flush dev %s\n" % mem.name
|
||||
if interface.primary_interface_name:
|
||||
mac = utils.interface_mac(interface.primary_interface_name)
|
||||
ovs_extra.append("set bridge %s other-config:hwaddr=%s" %
|
||||
(interface.name, mac))
|
||||
ovs_extra.extend(interface.ovs_extra)
|
||||
elif interface.ovs_port:
|
||||
if isinstance(interface, objects.Vlan):
|
||||
data += "auto vlan%i\n" % interface.vlan_id
|
||||
data += "allow-%s vlan%i\n" % (interface.bridge_name,
|
||||
interface.vlan_id)
|
||||
data += _iface
|
||||
data += address_data
|
||||
data += " ovs_bridge %s\n" % interface.bridge_name
|
||||
data += " ovs_type OVSIntPort\n"
|
||||
data += " ovs_options tag=%s\n" % interface.vlan_id
|
||||
|
||||
else:
|
||||
data += "auto %s\n" % interface.name
|
||||
data += "allow-%s %s\n" % (interface.bridge_name,
|
||||
interface.name)
|
||||
data += _iface
|
||||
data += address_data
|
||||
data += " ovs_bridge %s\n" % interface.bridge_name
|
||||
data += " ovs_type OVSPort\n"
|
||||
elif isinstance(interface, objects.Vlan):
|
||||
data += "auto vlan%i\n" % interface.vlan_id
|
||||
data += _iface
|
||||
data += address_data
|
||||
data += " vlan-raw-device %s\n" % interface.device
|
||||
else:
|
||||
data += "auto %s\n" % interface.name
|
||||
data += _iface
|
||||
data += address_data
|
||||
if interface.mtu:
|
||||
data += " mtu %i\n" % interface.mtu
|
||||
|
||||
if interface.hwaddr:
|
||||
raise NotImplemented("hwaddr is not implemented.")
|
||||
|
||||
if ovs_extra:
|
||||
data += " ovs_extra %s\n" % " -- ".join(ovs_extra)
|
||||
|
||||
return data
|
||||
|
||||
def add_interface(self, interface):
|
||||
"""Add an Interface object to the net config object.
|
||||
|
||||
:param interface: The Interface object to add.
|
||||
"""
|
||||
logger.info('adding interface: %s' % interface.name)
|
||||
data = self._add_common(interface)
|
||||
logger.debug('interface data: %s' % data)
|
||||
self.interfaces[interface.name] = data
|
||||
if interface.routes:
|
||||
self._add_routes(interface.name, interface.routes)
|
||||
|
||||
def add_bridge(self, bridge):
|
||||
"""Add an OvsBridge object to the net config object.
|
||||
|
||||
:param bridge: The OvsBridge object to add.
|
||||
"""
|
||||
logger.info('adding bridge: %s' % bridge.name)
|
||||
data = self._add_common(bridge)
|
||||
logger.debug('bridge data: %s' % data)
|
||||
self.bridges[bridge.name] = data
|
||||
if bridge.routes:
|
||||
self._add_routes(bridge.name, bridge.routes)
|
||||
|
||||
def add_vlan(self, vlan):
|
||||
"""Add a Vlan object to the net config object.
|
||||
|
||||
:param vlan: The vlan object to add.
|
||||
"""
|
||||
logger.info('adding vlan: %s' % vlan.name)
|
||||
data = self._add_common(vlan)
|
||||
logger.debug('vlan data: %s' % data)
|
||||
self.interfaces[vlan.name] = data
|
||||
if vlan.routes:
|
||||
self._add_routes(vlan.name, vlan.routes)
|
||||
|
||||
def _add_routes(self, interface_name, routes=[]):
|
||||
logger.info('adding custom route for interface: %s' % interface_name)
|
||||
data = ""
|
||||
for route in routes:
|
||||
if route.default and not route.ip_netmask:
|
||||
rt = netaddr.IPNetwork("0.0.0.0/0")
|
||||
else:
|
||||
rt = netaddr.IPNetwork(route.ip_netmask)
|
||||
data += "up route add -net %s netmask %s gw %s\n" % (
|
||||
str(rt.ip), str(rt.netmask), route.next_hop)
|
||||
data += "down route del -net %s netmask %s gw %s\n" % (
|
||||
str(rt.ip), str(rt.netmask), route.next_hop)
|
||||
self.routes[interface_name] = data
|
||||
logger.debug('route data: %s' % self.routes[interface_name])
|
||||
|
||||
def apply(self, cleanup=False, activate=True):
|
||||
"""Apply the network configuration.
|
||||
|
||||
:param cleanup: A boolean which indicates whether any undefined
|
||||
(existing but not present in the object model) interface
|
||||
should be disabled and deleted.
|
||||
:param activate: A boolean which indicates if the config should
|
||||
be activated by stopping/starting interfaces
|
||||
:returns: a dict of the format: filename/data which contains info
|
||||
for each file that was changed (or would be changed if in --noop
|
||||
mode).
|
||||
Note the noop mode is set via the constructor noop boolean
|
||||
"""
|
||||
new_config = ""
|
||||
|
||||
# write out bridges first. This ensures that an ifup -a
|
||||
# on reboot brings them up first
|
||||
for bridge_name, bridge_data in self.bridges.iteritems():
|
||||
route_data = self.routes.get(bridge_name)
|
||||
bridge_data += (route_data or '')
|
||||
new_config += bridge_data
|
||||
|
||||
for interface_name, iface_data in self.interfaces.iteritems():
|
||||
route_data = self.routes.get(interface_name)
|
||||
iface_data += (route_data or '')
|
||||
new_config += iface_data
|
||||
|
||||
if utils.diff(_network_config_path(self.root_dir), new_config):
|
||||
if activate:
|
||||
for interface in self.interfaces.keys():
|
||||
self.ifdown(interface)
|
||||
|
||||
for bridge in self.bridges.keys():
|
||||
self.ifdown(bridge, iftype='bridge')
|
||||
|
||||
self.write_config(_network_config_path(self.root_dir), new_config)
|
||||
|
||||
if activate:
|
||||
for bridge in self.bridges.keys():
|
||||
self.ifup(bridge, iftype='bridge')
|
||||
|
||||
for interface in self.interfaces.keys():
|
||||
self.ifup(interface)
|
||||
else:
|
||||
logger.info('No interface changes are required.')
|
||||
|
||||
return {_network_config_path(self.root_dir): new_config}
|
@ -1,835 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014-2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 glob
|
||||
import logging
|
||||
import re
|
||||
|
||||
import os_net_config
|
||||
from os_net_config import objects
|
||||
from os_net_config import utils
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def ifcfg_config_path(name):
|
||||
return "/etc/sysconfig/network-scripts/ifcfg-%s" % name
|
||||
|
||||
|
||||
# NOTE(dprince): added here for testability
|
||||
def bridge_config_path(name):
|
||||
return ifcfg_config_path(name)
|
||||
|
||||
|
||||
def ivs_config_path():
|
||||
return "/etc/sysconfig/ivs"
|
||||
|
||||
|
||||
def nfvswitch_config_path():
|
||||
return "/etc/sysconfig/nfvswitch"
|
||||
|
||||
|
||||
def route_config_path(name):
|
||||
return "/etc/sysconfig/network-scripts/route-%s" % name
|
||||
|
||||
|
||||
def route6_config_path(name):
|
||||
return "/etc/sysconfig/network-scripts/route6-%s" % name
|
||||
|
||||
|
||||
def cleanup_pattern():
|
||||
return "/etc/sysconfig/network-scripts/ifcfg-*"
|
||||
|
||||
|
||||
class IfcfgNetConfig(os_net_config.NetConfig):
|
||||
"""Configure network interfaces using the ifcfg format."""
|
||||
|
||||
def __init__(self, noop=False, root_dir=''):
|
||||
super(IfcfgNetConfig, self).__init__(noop, root_dir)
|
||||
self.interface_data = {}
|
||||
self.ivsinterface_data = {}
|
||||
self.nfvswitch_intiface_data = {}
|
||||
self.nfvswitch_cpus = None
|
||||
self.vlan_data = {}
|
||||
self.route_data = {}
|
||||
self.route6_data = {}
|
||||
self.bridge_data = {}
|
||||
self.linuxbridge_data = {}
|
||||
self.linuxbond_data = {}
|
||||
self.ib_interface_data = {}
|
||||
self.linuxteam_data = {}
|
||||
self.member_names = {}
|
||||
self.renamed_interfaces = {}
|
||||
self.bond_primary_ifaces = {}
|
||||
logger.info('Ifcfg net config provider created.')
|
||||
|
||||
def child_members(self, name):
|
||||
children = set()
|
||||
try:
|
||||
for member in self.member_names[name]:
|
||||
children.add(member)
|
||||
children.update(self.child_members(member))
|
||||
except KeyError:
|
||||
pass
|
||||
return children
|
||||
|
||||
def _add_common(self, base_opt):
|
||||
|
||||
ovs_extra = []
|
||||
|
||||
data = "# This file is autogenerated by os-net-config\n"
|
||||
data += "DEVICE=%s\n" % base_opt.name
|
||||
data += "ONBOOT=yes\n"
|
||||
data += "HOTPLUG=no\n"
|
||||
data += "NM_CONTROLLED=no\n"
|
||||
if not base_opt.dns_servers and not base_opt.use_dhcp:
|
||||
data += "PEERDNS=no\n"
|
||||
if isinstance(base_opt, objects.Vlan):
|
||||
if not base_opt.ovs_port:
|
||||
# vlans on OVS bridges are internal ports (no device, etc)
|
||||
data += "VLAN=yes\n"
|
||||
if base_opt.device:
|
||||
data += "PHYSDEV=%s\n" % base_opt.device
|
||||
else:
|
||||
if base_opt.linux_bond_name:
|
||||
data += "PHYSDEV=%s\n" % base_opt.linux_bond_name
|
||||
elif isinstance(base_opt, objects.IvsInterface):
|
||||
data += "TYPE=IVSIntPort\n"
|
||||
elif isinstance(base_opt, objects.NfvswitchInternal):
|
||||
data += "TYPE=NFVSWITCHIntPort\n"
|
||||
elif isinstance(base_opt, objects.IbInterface):
|
||||
data += "TYPE=Infiniband\n"
|
||||
elif re.match('\w+\.\d+$', base_opt.name):
|
||||
data += "VLAN=yes\n"
|
||||
if base_opt.linux_bond_name:
|
||||
data += "MASTER=%s\n" % base_opt.linux_bond_name
|
||||
data += "SLAVE=yes\n"
|
||||
if base_opt.linux_team_name:
|
||||
data += "TEAM_MASTER=%s\n" % base_opt.linux_team_name
|
||||
if base_opt.primary:
|
||||
data += "TEAM_PORT_CONFIG='{\"prio\": 100}'\n"
|
||||
if base_opt.ivs_bridge_name:
|
||||
data += "DEVICETYPE=ivs\n"
|
||||
data += "IVS_BRIDGE=%s\n" % base_opt.ivs_bridge_name
|
||||
if base_opt.nfvswitch_bridge_name:
|
||||
data += "DEVICETYPE=nfvswitch\n"
|
||||
data += "NFVSWITCH_BRIDGE=%s\n" % base_opt.nfvswitch_bridge_name
|
||||
if base_opt.ovs_port:
|
||||
if not isinstance(base_opt, objects.LinuxTeam):
|
||||
data += "DEVICETYPE=ovs\n"
|
||||
if base_opt.bridge_name:
|
||||
if isinstance(base_opt, objects.Vlan):
|
||||
data += "TYPE=OVSIntPort\n"
|
||||
data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name
|
||||
data += "OVS_OPTIONS=\"tag=%s\"\n" % base_opt.vlan_id
|
||||
else:
|
||||
data += "TYPE=OVSPort\n"
|
||||
data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name
|
||||
if base_opt.linux_bridge_name:
|
||||
data += "BRIDGE=%s\n" % base_opt.linux_bridge_name
|
||||
if isinstance(base_opt, objects.OvsBridge):
|
||||
data += "DEVICETYPE=ovs\n"
|
||||
data += "TYPE=OVSBridge\n"
|
||||
if base_opt.use_dhcp:
|
||||
data += "OVSBOOTPROTO=dhcp\n"
|
||||
if base_opt.members:
|
||||
members = [member.name for member in base_opt.members]
|
||||
self.member_names[base_opt.name] = members
|
||||
if base_opt.use_dhcp:
|
||||
data += ("OVSDHCPINTERFACES=\"%s\"\n" % " ".join(members))
|
||||
if base_opt.primary_interface_name:
|
||||
mac = utils.interface_mac(base_opt.primary_interface_name)
|
||||
ovs_extra.append("set bridge %s other-config:hwaddr=%s" %
|
||||
(base_opt.name, mac))
|
||||
if base_opt.ovs_options:
|
||||
data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options
|
||||
ovs_extra.extend(base_opt.ovs_extra)
|
||||
elif isinstance(base_opt, objects.OvsBond):
|
||||
if base_opt.primary_interface_name:
|
||||
primary_name = base_opt.primary_interface_name
|
||||
self.bond_primary_ifaces[base_opt.name] = primary_name
|
||||
data += "DEVICETYPE=ovs\n"
|
||||
data += "TYPE=OVSBond\n"
|
||||
if base_opt.use_dhcp:
|
||||
data += "OVSBOOTPROTO=dhcp\n"
|
||||
if base_opt.members:
|
||||
members = [member.name for member in base_opt.members]
|
||||
self.member_names[base_opt.name] = members
|
||||
data += ("BOND_IFACES=\"%s\"\n" % " ".join(members))
|
||||
if base_opt.ovs_options:
|
||||
data += "OVS_OPTIONS=\"%s\"\n" % base_opt.ovs_options
|
||||
ovs_extra.extend(base_opt.ovs_extra)
|
||||
elif isinstance(base_opt, objects.LinuxBridge):
|
||||
data += "TYPE=Bridge\n"
|
||||
data += "DELAY=0\n"
|
||||
if base_opt.use_dhcp:
|
||||
data += "BOOTPROTO=dhcp\n"
|
||||
if base_opt.members:
|
||||
members = [member.name for member in base_opt.members]
|
||||
self.member_names[base_opt.name] = members
|
||||
if base_opt.primary_interface_name:
|
||||
primary_name = base_opt.primary_interface_name
|
||||
primary_mac = utils.interface_mac(primary_name)
|
||||
data += "MACADDR=\"%s\"\n" % primary_mac
|
||||
elif isinstance(base_opt, objects.LinuxBond):
|
||||
if base_opt.primary_interface_name:
|
||||
primary_name = base_opt.primary_interface_name
|
||||
primary_mac = utils.interface_mac(primary_name)
|
||||
data += "MACADDR=\"%s\"\n" % primary_mac
|
||||
if base_opt.use_dhcp:
|
||||
data += "BOOTPROTO=dhcp\n"
|
||||
if base_opt.members:
|
||||
members = [member.name for member in base_opt.members]
|
||||
self.member_names[base_opt.name] = members
|
||||
if base_opt.bonding_options:
|
||||
data += "BONDING_OPTS=\"%s\"\n" % base_opt.bonding_options
|
||||
elif isinstance(base_opt, objects.LinuxTeam):
|
||||
if base_opt.primary_interface_name:
|
||||
primary_name = base_opt.primary_interface_name
|
||||
primary_mac = utils.interface_mac(primary_name)
|
||||
data += "MACADDR=\"%s\"\n" % primary_mac
|
||||
if base_opt.use_dhcp:
|
||||
data += "BOOTPROTO=dhcp\n"
|
||||
if base_opt.members:
|
||||
members = [member.name for member in base_opt.members]
|
||||
self.member_names[base_opt.name] = members
|
||||
data += "DEVICETYPE=Team\n"
|
||||
if base_opt.bonding_options:
|
||||
data += "TEAM_CONFIG='%s'\n" % base_opt.bonding_options
|
||||
elif isinstance(base_opt, objects.OvsTunnel):
|
||||
ovs_extra.extend(base_opt.ovs_extra)
|
||||
data += "DEVICETYPE=ovs\n"
|
||||
data += "TYPE=OVSTunnel\n"
|
||||
data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name
|
||||
data += "OVS_TUNNEL_TYPE=%s\n" % base_opt.tunnel_type
|
||||
data += "OVS_TUNNEL_OPTIONS=\"%s\"\n" % \
|
||||
' '.join(base_opt.ovs_options)
|
||||
elif isinstance(base_opt, objects.OvsPatchPort):
|
||||
ovs_extra.extend(base_opt.ovs_extra)
|
||||
data += "DEVICETYPE=ovs\n"
|
||||
data += "TYPE=OVSPatchPort\n"
|
||||
data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name
|
||||
data += "OVS_PATCH_PEER=%s\n" % base_opt.peer
|
||||
else:
|
||||
if base_opt.use_dhcp:
|
||||
data += "BOOTPROTO=dhcp\n"
|
||||
elif not base_opt.addresses:
|
||||
data += "BOOTPROTO=none\n"
|
||||
|
||||
if base_opt.mtu:
|
||||
data += "MTU=%i\n" % base_opt.mtu
|
||||
if base_opt.use_dhcpv6 or base_opt.v6_addresses():
|
||||
data += "IPV6INIT=yes\n"
|
||||
if base_opt.mtu:
|
||||
data += "IPV6_MTU=%i\n" % base_opt.mtu
|
||||
if base_opt.use_dhcpv6:
|
||||
data += "DHCPV6C=yes\n"
|
||||
elif base_opt.addresses:
|
||||
v4_addresses = base_opt.v4_addresses()
|
||||
if v4_addresses:
|
||||
data += "BOOTPROTO=static\n"
|
||||
for i, address in enumerate(v4_addresses):
|
||||
num = '%s' % i if i else ''
|
||||
data += "IPADDR%s=%s\n" % (num, address.ip)
|
||||
data += "NETMASK%s=%s\n" % (num, address.netmask)
|
||||
|
||||
v6_addresses = base_opt.v6_addresses()
|
||||
if v6_addresses:
|
||||
first_v6 = v6_addresses[0]
|
||||
data += "IPV6_AUTOCONF=no\n"
|
||||
data += "IPV6ADDR=%s\n" % first_v6.ip_netmask
|
||||
if len(v6_addresses) > 1:
|
||||
secondaries_v6 = " ".join(map(lambda a: a.ip_netmask,
|
||||
v6_addresses[1:]))
|
||||
data += "IPV6ADDR_SECONDARIES=\"%s\"\n" % secondaries_v6
|
||||
|
||||
if base_opt.hwaddr:
|
||||
data += "HWADDR=%s\n" % base_opt.hwaddr
|
||||
if ovs_extra:
|
||||
data += "OVS_EXTRA=\"%s\"\n" % " -- ".join(ovs_extra)
|
||||
if not base_opt.defroute:
|
||||
data += "DEFROUTE=no\n"
|
||||
if base_opt.dhclient_args:
|
||||
data += "DHCLIENTARGS=%s\n" % base_opt.dhclient_args
|
||||
if base_opt.dns_servers:
|
||||
data += "DNS1=%s\n" % base_opt.dns_servers[0]
|
||||
if len(base_opt.dns_servers) == 2:
|
||||
data += "DNS2=%s\n" % base_opt.dns_servers[1]
|
||||
elif len(base_opt.dns_servers) > 2:
|
||||
logger.warning('ifcfg format supports a max of 2 dns servers.')
|
||||
return data
|
||||
|
||||
def _add_routes(self, interface_name, routes=[]):
|
||||
logger.info('adding custom route for interface: %s' % interface_name)
|
||||
data = ""
|
||||
first_line = ""
|
||||
data6 = ""
|
||||
first_line6 = ""
|
||||
for route in routes:
|
||||
if ":" not in route.next_hop:
|
||||
# Route is an IPv4 route
|
||||
if route.default:
|
||||
first_line = "default via %s dev %s\n" % (route.next_hop,
|
||||
interface_name)
|
||||
else:
|
||||
data += "%s via %s dev %s\n" % (route.ip_netmask,
|
||||
route.next_hop,
|
||||
interface_name)
|
||||
else:
|
||||
# Route is an IPv6 route
|
||||
if route.default:
|
||||
first_line6 = "default via %s dev %s\n" % (route.next_hop,
|
||||
interface_name)
|
||||
else:
|
||||
data6 += "%s via %s dev %s\n" % (route.ip_netmask,
|
||||
route.next_hop,
|
||||
interface_name)
|
||||
self.route_data[interface_name] = first_line + data
|
||||
self.route6_data[interface_name] = first_line6 + data6
|
||||
logger.debug('route data: %s' % self.route_data[interface_name])
|
||||
logger.debug('ipv6 route data: %s' % self.route6_data[interface_name])
|
||||
|
||||
def add_interface(self, interface):
|
||||
"""Add an Interface object to the net config object.
|
||||
|
||||
:param interface: The Interface object to add.
|
||||
"""
|
||||
logger.info('adding interface: %s' % interface.name)
|
||||
data = self._add_common(interface)
|
||||
logger.debug('interface data: %s' % data)
|
||||
self.interface_data[interface.name] = data
|
||||
if interface.routes:
|
||||
self._add_routes(interface.name, interface.routes)
|
||||
|
||||
if interface.renamed:
|
||||
logger.info("Interface %s being renamed to %s"
|
||||
% (interface.hwname, interface.name))
|
||||
self.renamed_interfaces[interface.hwname] = interface.name
|
||||
|
||||
def add_vlan(self, vlan):
|
||||
"""Add a Vlan object to the net config object.
|
||||
|
||||
:param vlan: The vlan object to add.
|
||||
"""
|
||||
logger.info('adding vlan: %s' % vlan.name)
|
||||
data = self._add_common(vlan)
|
||||
logger.debug('vlan data: %s' % data)
|
||||
self.vlan_data[vlan.name] = data
|
||||
if vlan.routes:
|
||||
self._add_routes(vlan.name, vlan.routes)
|
||||
|
||||
def add_ivs_interface(self, ivs_interface):
|
||||
"""Add a ivs_interface object to the net config object.
|
||||
|
||||
:param ivs_interface: The ivs_interface object to add.
|
||||
"""
|
||||
logger.info('adding ivs_interface: %s' % ivs_interface.name)
|
||||
data = self._add_common(ivs_interface)
|
||||
logger.debug('ivs_interface data: %s' % data)
|
||||
self.ivsinterface_data[ivs_interface.name] = data
|
||||
if ivs_interface.routes:
|
||||
self._add_routes(ivs_interface.name, ivs_interface.routes)
|
||||
|
||||
def add_nfvswitch_internal(self, nfvswitch_internal):
|
||||
"""Add a nfvswitch_internal interface object to the net config object.
|
||||
|
||||
:param nfvswitch_internal: The nfvswitch_internal object to add.
|
||||
"""
|
||||
iface_name = nfvswitch_internal.name
|
||||
logger.info('adding nfvswitch_internal interface: %s' % iface_name)
|
||||
data = self._add_common(nfvswitch_internal)
|
||||
logger.debug('nfvswitch_internal interface data: %s' % data)
|
||||
self.nfvswitch_intiface_data[iface_name] = data
|
||||
if nfvswitch_internal.routes:
|
||||
self._add_routes(iface_name, nfvswitch_internal.routes)
|
||||
|
||||
def add_bridge(self, bridge):
|
||||
"""Add an OvsBridge object to the net config object.
|
||||
|
||||
:param bridge: The OvsBridge object to add.
|
||||
"""
|
||||
logger.info('adding bridge: %s' % bridge.name)
|
||||
data = self._add_common(bridge)
|
||||
logger.debug('bridge data: %s' % data)
|
||||
self.bridge_data[bridge.name] = data
|
||||
if bridge.routes:
|
||||
self._add_routes(bridge.name, bridge.routes)
|
||||
|
||||
def add_linux_bridge(self, bridge):
|
||||
"""Add a LinuxBridge object to the net config object.
|
||||
|
||||
:param bridge: The LinuxBridge object to add.
|
||||
"""
|
||||
logger.info('adding linux bridge: %s' % bridge.name)
|
||||
data = self._add_common(bridge)
|
||||
logger.debug('bridge data: %s' % data)
|
||||
self.linuxbridge_data[bridge.name] = data
|
||||
if bridge.routes:
|
||||
self._add_routes(bridge.name, bridge.routes)
|
||||
|
||||
def add_ivs_bridge(self, bridge):
|
||||
"""Add a IvsBridge object to the net config object.
|
||||
|
||||
IVS can only support one virtual switch per node,
|
||||
using "ivs" as its name. As long as the ivs service
|
||||
is running, the ivs virtual switch will be there.
|
||||
It is impossible to add multiple ivs virtual switches
|
||||
per node.
|
||||
:param bridge: The IvsBridge object to add.
|
||||
"""
|
||||
pass
|
||||
|
||||
def add_nfvswitch_bridge(self, bridge):
|
||||
"""Add a NFVSwitchBridge object to the net config object.
|
||||
|
||||
NFVSwitch can only support one virtual switch per node,
|
||||
using "nfvswitch" as its name. As long as the nfvswitch service
|
||||
is running, the nfvswitch virtual switch will be available.
|
||||
:param bridge: The NfvswitchBridge object to add.
|
||||
"""
|
||||
self.nfvswitch_cpus = bridge.cpus
|
||||
|
||||
def add_bond(self, bond):
|
||||
"""Add an OvsBond object to the net config object.
|
||||
|
||||
:param bond: The OvsBond object to add.
|
||||
"""
|
||||
logger.info('adding bond: %s' % bond.name)
|
||||
data = self._add_common(bond)
|
||||
logger.debug('bond data: %s' % data)
|
||||
self.interface_data[bond.name] = data
|
||||
if bond.routes:
|
||||
self._add_routes(bond.name, bond.routes)
|
||||
|
||||
def add_linux_bond(self, bond):
|
||||
"""Add a LinuxBond object to the net config object.
|
||||
|
||||
:param bond: The LinuxBond object to add.
|
||||
"""
|
||||
logger.info('adding linux bond: %s' % bond.name)
|
||||
data = self._add_common(bond)
|
||||
logger.debug('bond data: %s' % data)
|
||||
self.linuxbond_data[bond.name] = data
|
||||
if bond.routes:
|
||||
self._add_routes(bond.name, bond.routes)
|
||||
|
||||
def add_linux_team(self, team):
|
||||
"""Add a LinuxTeam object to the net config object.
|
||||
|
||||
:param team: The LinuxTeam object to add.
|
||||
"""
|
||||
logger.info('adding linux team: %s' % team.name)
|
||||
data = self._add_common(team)
|
||||
logger.debug('team data: %s' % data)
|
||||
self.linuxteam_data[team.name] = data
|
||||
if team.routes:
|
||||
self._add_routes(team.name, team.routes)
|
||||
|
||||
def add_ovs_tunnel(self, tunnel):
|
||||
"""Add a OvsTunnel object to the net config object.
|
||||
|
||||
:param tunnel: The OvsTunnel object to add.
|
||||
"""
|
||||
logger.info('adding ovs tunnel: %s' % tunnel.name)
|
||||
data = self._add_common(tunnel)
|
||||
logger.debug('ovs tunnel data: %s' % data)
|
||||
self.interface_data[tunnel.name] = data
|
||||
|
||||
def add_ovs_patch_port(self, ovs_patch_port):
|
||||
"""Add a OvsPatchPort object to the net config object.
|
||||
|
||||
:param ovs_patch_port: The OvsPatchPort object to add.
|
||||
"""
|
||||
logger.info('adding ovs patch port: %s' % ovs_patch_port.name)
|
||||
data = self._add_common(ovs_patch_port)
|
||||
logger.debug('ovs patch port data: %s' % data)
|
||||
self.interface_data[ovs_patch_port.name] = data
|
||||
|
||||
def add_ib_interface(self, ib_interface):
|
||||
"""Add an InfiniBand interface object to the net config object.
|
||||
|
||||
:param ib_interface: The InfiniBand interface object to add.
|
||||
"""
|
||||
logger.info('adding ib_interface: %s' % ib_interface.name)
|
||||
data = self._add_common(ib_interface)
|
||||
logger.debug('ib_interface data: %s' % data)
|
||||
self.ib_interface_data[ib_interface.name] = data
|
||||
if ib_interface.routes:
|
||||
self._add_routes(ib_interface.name, ib_interface.routes)
|
||||
|
||||
if ib_interface.renamed:
|
||||
logger.info("InfiniBand interface %s being renamed to %s"
|
||||
% (ib_interface.hwname, ib_interface.name))
|
||||
self.renamed_interfaces[ib_interface.hwname] = ib_interface.name
|
||||
|
||||
def generate_ivs_config(self, ivs_uplinks, ivs_interfaces):
|
||||
"""Generate configuration content for ivs."""
|
||||
|
||||
intfs = []
|
||||
for intf in ivs_uplinks:
|
||||
intfs.append(' -u ')
|
||||
intfs.append(intf)
|
||||
uplink_str = ''.join(intfs)
|
||||
|
||||
intfs = []
|
||||
for intf in ivs_interfaces:
|
||||
intfs.append(' --internal-port=')
|
||||
intfs.append(intf)
|
||||
intf_str = ''.join(intfs)
|
||||
|
||||
data = ("DAEMON_ARGS=\"--hitless --certificate /etc/ivs "
|
||||
"--inband-vlan 4092%s%s\""
|
||||
% (uplink_str, intf_str))
|
||||
return data
|
||||
|
||||
def generate_nfvswitch_config(self, nfvswitch_ifaces,
|
||||
nfvswitch_internal_ifaces):
|
||||
"""Generate configuration content for nfvswitch."""
|
||||
|
||||
cpu_str = ""
|
||||
if self.nfvswitch_cpus:
|
||||
cpu_str = " -c " + self.nfvswitch_cpus
|
||||
|
||||
ifaces = []
|
||||
for iface in nfvswitch_ifaces:
|
||||
ifaces.append(' -u ')
|
||||
ifaces.append(iface)
|
||||
iface_str = ''.join(ifaces)
|
||||
|
||||
ifaces = []
|
||||
for iface in nfvswitch_internal_ifaces:
|
||||
ifaces.append(' -m ')
|
||||
ifaces.append(iface)
|
||||
internal_str = ''.join(ifaces)
|
||||
|
||||
data = ("SETUP_ARGS=\"%s%s%s\"" % (cpu_str, iface_str, internal_str))
|
||||
return data
|
||||
|
||||
def apply(self, cleanup=False, activate=True):
|
||||
"""Apply the network configuration.
|
||||
|
||||
:param cleanup: A boolean which indicates whether any undefined
|
||||
(existing but not present in the object model) interface
|
||||
should be disabled and deleted.
|
||||
:param activate: A boolean which indicates if the config should
|
||||
be activated by stopping/starting interfaces
|
||||
NOTE: if cleanup is specified we will deactivate interfaces even
|
||||
if activate is false
|
||||
:returns: a dict of the format: filename/data which contains info
|
||||
for each file that was changed (or would be changed if in --noop
|
||||
mode).
|
||||
Note the noop mode is set via the constructor noop boolean
|
||||
"""
|
||||
logger.info('applying network configs...')
|
||||
restart_interfaces = []
|
||||
restart_vlans = []
|
||||
restart_bridges = []
|
||||
restart_linux_bonds = []
|
||||
restart_linux_teams = []
|
||||
update_files = {}
|
||||
all_file_names = []
|
||||
ivs_uplinks = [] # ivs physical uplinks
|
||||
ivs_interfaces = [] # ivs internal ports
|
||||
nfvswitch_interfaces = [] # nfvswitch physical interfaces
|
||||
nfvswitch_internal_ifaces = [] # nfvswitch internal/management ports
|
||||
|
||||
for interface_name, iface_data in self.interface_data.iteritems():
|
||||
route_data = self.route_data.get(interface_name, '')
|
||||
route6_data = self.route6_data.get(interface_name, '')
|
||||
interface_path = self.root_dir + ifcfg_config_path(interface_name)
|
||||
route_path = self.root_dir + route_config_path(interface_name)
|
||||
route6_path = self.root_dir + route6_config_path(interface_name)
|
||||
all_file_names.append(interface_path)
|
||||
all_file_names.append(route_path)
|
||||
all_file_names.append(route6_path)
|
||||
if "IVS_BRIDGE" in iface_data:
|
||||
ivs_uplinks.append(interface_name)
|
||||
if "NFVSWITCH_BRIDGE" in iface_data:
|
||||
nfvswitch_interfaces.append(interface_name)
|
||||
all_file_names.append(route6_path)
|
||||
if (utils.diff(interface_path, iface_data) or
|
||||
utils.diff(route_path, route_data) or
|
||||
utils.diff(route6_path, route6_data)):
|
||||
restart_interfaces.append(interface_name)
|
||||
restart_interfaces.extend(self.child_members(interface_name))
|
||||
update_files[interface_path] = iface_data
|
||||
update_files[route_path] = route_data
|
||||
update_files[route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for interface: %s' %
|
||||
interface_name)
|
||||
|
||||
for interface_name, iface_data in self.ivsinterface_data.iteritems():
|
||||
route_data = self.route_data.get(interface_name, '')
|
||||
route6_data = self.route6_data.get(interface_name, '')
|
||||
interface_path = self.root_dir + ifcfg_config_path(interface_name)
|
||||
route_path = self.root_dir + route_config_path(interface_name)
|
||||
route6_path = self.root_dir + route6_config_path(interface_name)
|
||||
all_file_names.append(interface_path)
|
||||
all_file_names.append(route_path)
|
||||
all_file_names.append(route6_path)
|
||||
ivs_interfaces.append(interface_name)
|
||||
if (utils.diff(interface_path, iface_data) or
|
||||
utils.diff(route_path, route_data)):
|
||||
restart_interfaces.append(interface_name)
|
||||
restart_interfaces.extend(self.child_members(interface_name))
|
||||
update_files[interface_path] = iface_data
|
||||
update_files[route_path] = route_data
|
||||
update_files[route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for ivs interface: %s' %
|
||||
interface_name)
|
||||
|
||||
for iface_name, iface_data in self.nfvswitch_intiface_data.iteritems():
|
||||
route_data = self.route_data.get(iface_name, '')
|
||||
route6_data = self.route6_data.get(iface_name, '')
|
||||
iface_path = self.root_dir + ifcfg_config_path(iface_name)
|
||||
route_path = self.root_dir + route_config_path(iface_name)
|
||||
route6_path = self.root_dir + route6_config_path(iface_name)
|
||||
all_file_names.append(iface_path)
|
||||
all_file_names.append(route_path)
|
||||
all_file_names.append(route6_path)
|
||||
nfvswitch_internal_ifaces.append(iface_name)
|
||||
if (utils.diff(iface_path, iface_data) or
|
||||
utils.diff(route_path, route_data)):
|
||||
restart_interfaces.append(iface_name)
|
||||
restart_interfaces.extend(self.child_members(iface_name))
|
||||
update_files[iface_path] = iface_data
|
||||
update_files[route_path] = route_data
|
||||
update_files[route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for nfvswitch interface: %s' %
|
||||
iface_name)
|
||||
|
||||
for vlan_name, vlan_data in self.vlan_data.iteritems():
|
||||
route_data = self.route_data.get(vlan_name, '')
|
||||
route6_data = self.route6_data.get(vlan_name, '')
|
||||
vlan_path = self.root_dir + ifcfg_config_path(vlan_name)
|
||||
vlan_route_path = self.root_dir + route_config_path(vlan_name)
|
||||
vlan_route6_path = self.root_dir + route6_config_path(vlan_name)
|
||||
all_file_names.append(vlan_path)
|
||||
all_file_names.append(vlan_route_path)
|
||||
all_file_names.append(vlan_route6_path)
|
||||
if (utils.diff(vlan_path, vlan_data) or
|
||||
utils.diff(vlan_route_path, route_data)):
|
||||
restart_vlans.append(vlan_name)
|
||||
restart_vlans.extend(self.child_members(vlan_name))
|
||||
update_files[vlan_path] = vlan_data
|
||||
update_files[vlan_route_path] = route_data
|
||||
update_files[vlan_route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for vlan interface: %s' %
|
||||
vlan_name)
|
||||
|
||||
for bridge_name, bridge_data in self.bridge_data.iteritems():
|
||||
route_data = self.route_data.get(bridge_name, '')
|
||||
route6_data = self.route6_data.get(bridge_name, '')
|
||||
bridge_path = self.root_dir + bridge_config_path(bridge_name)
|
||||
br_route_path = self.root_dir + route_config_path(bridge_name)
|
||||
br_route6_path = self.root_dir + route6_config_path(bridge_name)
|
||||
all_file_names.append(bridge_path)
|
||||
all_file_names.append(br_route_path)
|
||||
all_file_names.append(br_route6_path)
|
||||
if (utils.diff(bridge_path, bridge_data) or
|
||||
utils.diff(br_route_path, route_data) or
|
||||
utils.diff(br_route6_path, route6_data)):
|
||||
restart_bridges.append(bridge_name)
|
||||
restart_interfaces.extend(self.child_members(bridge_name))
|
||||
update_files[bridge_path] = bridge_data
|
||||
update_files[br_route_path] = route_data
|
||||
update_files[br_route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for bridge: %s' % bridge_name)
|
||||
|
||||
for bridge_name, bridge_data in self.linuxbridge_data.iteritems():
|
||||
route_data = self.route_data.get(bridge_name, '')
|
||||
route6_data = self.route6_data.get(bridge_name, '')
|
||||
bridge_path = self.root_dir + bridge_config_path(bridge_name)
|
||||
br_route_path = self.root_dir + route_config_path(bridge_name)
|
||||
br_route6_path = self.root_dir + route6_config_path(bridge_name)
|
||||
all_file_names.append(bridge_path)
|
||||
all_file_names.append(br_route_path)
|
||||
all_file_names.append(br_route6_path)
|
||||
if (utils.diff(bridge_path, bridge_data) or
|
||||
utils.diff(br_route_path, route_data) or
|
||||
utils.diff(br_route6_path, route6_data)):
|
||||
restart_bridges.append(bridge_name)
|
||||
restart_interfaces.extend(self.child_members(bridge_name))
|
||||
update_files[bridge_path] = bridge_data
|
||||
update_files[br_route_path] = route_data
|
||||
update_files[br_route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for bridge: %s' % bridge_name)
|
||||
|
||||
for team_name, team_data in self.linuxteam_data.iteritems():
|
||||
route_data = self.route_data.get(team_name, '')
|
||||
route6_data = self.route6_data.get(team_name, '')
|
||||
team_path = self.root_dir + bridge_config_path(team_name)
|
||||
team_route_path = self.root_dir + route_config_path(team_name)
|
||||
team_route6_path = self.root_dir + route6_config_path(team_name)
|
||||
all_file_names.append(team_path)
|
||||
all_file_names.append(team_route_path)
|
||||
all_file_names.append(team_route6_path)
|
||||
if (utils.diff(team_path, team_data) or
|
||||
utils.diff(team_route_path, route_data) or
|
||||
utils.diff(team_route6_path, route6_data)):
|
||||
restart_linux_teams.append(team_name)
|
||||
restart_interfaces.extend(self.child_members(team_name))
|
||||
update_files[team_path] = team_data
|
||||
update_files[team_route_path] = route_data
|
||||
update_files[team_route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for linux team: %s' %
|
||||
team_name)
|
||||
|
||||
for bond_name, bond_data in self.linuxbond_data.iteritems():
|
||||
route_data = self.route_data.get(bond_name, '')
|
||||
route6_data = self.route6_data.get(bond_name, '')
|
||||
bond_path = self.root_dir + bridge_config_path(bond_name)
|
||||
bond_route_path = self.root_dir + route_config_path(bond_name)
|
||||
bond_route6_path = self.root_dir + route6_config_path(bond_name)
|
||||
all_file_names.append(bond_path)
|
||||
all_file_names.append(bond_route_path)
|
||||
all_file_names.append(bond_route6_path)
|
||||
if (utils.diff(bond_path, bond_data) or
|
||||
utils.diff(bond_route_path, route_data) or
|
||||
utils.diff(bond_route6_path, route6_data)):
|
||||
restart_linux_bonds.append(bond_name)
|
||||
restart_interfaces.extend(self.child_members(bond_name))
|
||||
update_files[bond_path] = bond_data
|
||||
update_files[bond_route_path] = route_data
|
||||
update_files[bond_route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for linux bond: %s' %
|
||||
bond_name)
|
||||
|
||||
# Infiniband interfaces are handled similarly to Ethernet interfaces
|
||||
for interface_name, iface_data in self.ib_interface_data.iteritems():
|
||||
route_data = self.route_data.get(interface_name, '')
|
||||
route6_data = self.route6_data.get(interface_name, '')
|
||||
interface_path = self.root_dir + ifcfg_config_path(interface_name)
|
||||
route_path = self.root_dir + route_config_path(interface_name)
|
||||
route6_path = self.root_dir + route6_config_path(interface_name)
|
||||
all_file_names.append(interface_path)
|
||||
all_file_names.append(route_path)
|
||||
all_file_names.append(route6_path)
|
||||
# TODO(dsneddon) determine if InfiniBand can be used with IVS
|
||||
if "IVS_BRIDGE" in iface_data:
|
||||
ivs_uplinks.append(interface_name)
|
||||
all_file_names.append(route6_path)
|
||||
if (utils.diff(interface_path, iface_data) or
|
||||
utils.diff(route_path, route_data) or
|
||||
utils.diff(route6_path, route6_data)):
|
||||
restart_interfaces.append(interface_name)
|
||||
restart_interfaces.extend(self.child_members(interface_name))
|
||||
update_files[interface_path] = iface_data
|
||||
update_files[route_path] = route_data
|
||||
update_files[route6_path] = route6_data
|
||||
else:
|
||||
logger.info('No changes required for InfiniBand iface: %s' %
|
||||
interface_name)
|
||||
|
||||
if cleanup:
|
||||
for ifcfg_file in glob.iglob(cleanup_pattern()):
|
||||
if ifcfg_file not in all_file_names:
|
||||
interface_name = ifcfg_file[len(cleanup_pattern()) - 1:]
|
||||
if interface_name != 'lo':
|
||||
logger.info('cleaning up interface: %s'
|
||||
% interface_name)
|
||||
self.ifdown(interface_name)
|
||||
self.remove_config(ifcfg_file)
|
||||
|
||||
if activate:
|
||||
for vlan in restart_vlans:
|
||||
self.ifdown(vlan)
|
||||
|
||||
for interface in restart_interfaces:
|
||||
self.ifdown(interface)
|
||||
|
||||
for linux_bond in restart_linux_bonds:
|
||||
self.ifdown(linux_bond)
|
||||
|
||||
for linux_team in restart_linux_teams:
|
||||
self.ifdown(linux_team)
|
||||
|
||||
for bridge in restart_bridges:
|
||||
self.ifdown(bridge, iftype='bridge')
|
||||
|
||||
for oldname, newname in self.renamed_interfaces.iteritems():
|
||||
self.ifrename(oldname, newname)
|
||||
|
||||
for location, data in update_files.iteritems():
|
||||
self.write_config(location, data)
|
||||
|
||||
if ivs_uplinks or ivs_interfaces:
|
||||
location = ivs_config_path()
|
||||
data = self.generate_ivs_config(ivs_uplinks, ivs_interfaces)
|
||||
self.write_config(location, data)
|
||||
|
||||
if nfvswitch_interfaces or nfvswitch_internal_ifaces:
|
||||
location = nfvswitch_config_path()
|
||||
data = self.generate_nfvswitch_config(nfvswitch_interfaces,
|
||||
nfvswitch_internal_ifaces)
|
||||
self.write_config(location, data)
|
||||
|
||||
if activate:
|
||||
for linux_team in restart_linux_teams:
|
||||
self.ifup(linux_team)
|
||||
|
||||
for bridge in restart_bridges:
|
||||
self.ifup(bridge, iftype='bridge')
|
||||
|
||||
for interface in restart_interfaces:
|
||||
self.ifup(interface)
|
||||
|
||||
for linux_bond in restart_linux_bonds:
|
||||
self.ifup(linux_bond)
|
||||
|
||||
for bond in self.bond_primary_ifaces:
|
||||
self.ovs_appctl('bond/set-active-slave', bond,
|
||||
self.bond_primary_ifaces[bond])
|
||||
|
||||
if ivs_uplinks or ivs_interfaces:
|
||||
logger.info("Attach to ivs with "
|
||||
"uplinks: %s, "
|
||||
"interfaces: %s" %
|
||||
(ivs_uplinks, ivs_interfaces))
|
||||
for ivs_uplink in ivs_uplinks:
|
||||
self.ifup(ivs_uplink)
|
||||
for ivs_interface in ivs_interfaces:
|
||||
self.ifup(ivs_interface)
|
||||
msg = "Restart ivs"
|
||||
self.execute(msg, '/usr/bin/systemctl',
|
||||
'restart', 'ivs')
|
||||
|
||||
if nfvswitch_interfaces or nfvswitch_internal_ifaces:
|
||||
logger.info("Attach to nfvswitch with "
|
||||
"interfaces: %s, "
|
||||
"internal interfaces: %s" %
|
||||
(nfvswitch_interfaces, nfvswitch_internal_ifaces))
|
||||
for nfvswitch_interface in nfvswitch_interfaces:
|
||||
self.ifup(nfvswitch_interface)
|
||||
for nfvswitch_internal in nfvswitch_internal_ifaces:
|
||||
self.ifup(nfvswitch_internal)
|
||||
msg = "Restart nfvswitch"
|
||||
self.execute(msg, '/usr/bin/systemctl',
|
||||
'restart', 'nfvswitch')
|
||||
|
||||
for vlan in restart_vlans:
|
||||
self.ifup(vlan)
|
||||
|
||||
return update_files
|
@ -1,21 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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_net_config
|
||||
|
||||
|
||||
class IprouteNetConfig(os_net_config.NetConfig):
|
||||
"""Configure network interfaces using iproute2."""
|
@ -1,875 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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 netaddr
|
||||
from oslo_utils import strutils
|
||||
|
||||
from os_net_config import utils
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_NUMBERED_NICS = None
|
||||
|
||||
|
||||
class InvalidConfigException(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
def object_from_json(json):
|
||||
obj_type = json.get("type")
|
||||
if obj_type == "interface":
|
||||
return Interface.from_json(json)
|
||||
elif obj_type == "vlan":
|
||||
return Vlan.from_json(json)
|
||||
elif obj_type == "ovs_bridge":
|
||||
return OvsBridge.from_json(json)
|
||||
elif obj_type == "ovs_bond":
|
||||
return OvsBond.from_json(json)
|
||||
elif obj_type == "linux_bond":
|
||||
return LinuxBond.from_json(json)
|
||||
elif obj_type == "team":
|
||||
return LinuxTeam.from_json(json)
|
||||
elif obj_type == "linux_bridge":
|
||||
return LinuxBridge.from_json(json)
|
||||
elif obj_type == "ivs_bridge":
|
||||
return IvsBridge.from_json(json)
|
||||
elif obj_type == "ivs_interface":
|
||||
return IvsInterface.from_json(json)
|
||||
elif obj_type == "nfvswitch_bridge":
|
||||
return NfvswitchBridge.from_json(json)
|
||||
elif obj_type == "nfvswitch_internal":
|
||||
return NfvswitchInternal.from_json(json)
|
||||
elif obj_type == "ovs_tunnel":
|
||||
return OvsTunnel.from_json(json)
|
||||
elif obj_type == "ovs_patch_port":
|
||||
return OvsPatchPort.from_json(json)
|
||||
elif obj_type == "ib_interface":
|
||||
return IbInterface.from_json(json)
|
||||
|
||||
|
||||
def _get_required_field(json, name, object_name):
|
||||
field = json.get(name)
|
||||
if not field:
|
||||
msg = '%s JSON objects require \'%s\' to be configured.' \
|
||||
% (object_name, name)
|
||||
raise InvalidConfigException(msg)
|
||||
return field
|
||||
|
||||
|
||||
def _numbered_nics(nic_mapping=None):
|
||||
mapping = nic_mapping or {}
|
||||
global _NUMBERED_NICS
|
||||
if _NUMBERED_NICS:
|
||||
return _NUMBERED_NICS
|
||||
_NUMBERED_NICS = {}
|
||||
count = 0
|
||||
active_nics = utils.ordered_active_nics()
|
||||
for nic in active_nics:
|
||||
count += 1
|
||||
nic_alias = "nic%i" % count
|
||||
nic_mapped = mapping.get(nic_alias, nic)
|
||||
|
||||
# The mapping is either invalid, or specifies a mac
|
||||
if nic_mapped not in active_nics:
|
||||
for active in active_nics:
|
||||
try:
|
||||
active_mac = utils.interface_mac(active)
|
||||
except IOError:
|
||||
continue
|
||||
if nic_mapped == active_mac:
|
||||
logger.debug("%s matches device %s" % (nic_mapped, active))
|
||||
nic_mapped = active
|
||||
break
|
||||
else:
|
||||
# The mapping can't specify a non-active or non-existent nic
|
||||
logger.warning('interface %s is not in an active nic (%s)'
|
||||
% (nic_mapped, ', '.join(active_nics)))
|
||||
continue
|
||||
|
||||
# Duplicate mappings are not allowed
|
||||
if nic_mapped in _NUMBERED_NICS.values():
|
||||
msg = ('interface %s already mapped, '
|
||||
'check mapping file for duplicates'
|
||||
% nic_mapped)
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
_NUMBERED_NICS[nic_alias] = nic_mapped
|
||||
logger.info("%s mapped to: %s" % (nic_alias, nic_mapped))
|
||||
if not _NUMBERED_NICS:
|
||||
logger.warning('No active nics found.')
|
||||
return _NUMBERED_NICS
|
||||
|
||||
|
||||
class Route(object):
|
||||
"""Base class for network routes."""
|
||||
|
||||
def __init__(self, next_hop, ip_netmask="", default=False):
|
||||
self.next_hop = next_hop
|
||||
self.ip_netmask = ip_netmask
|
||||
self.default = default
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
next_hop = _get_required_field(json, 'next_hop', 'Route')
|
||||
ip_netmask = json.get('ip_netmask', "")
|
||||
default = strutils.bool_from_string(str(json.get('default', False)))
|
||||
return Route(next_hop, ip_netmask, default)
|
||||
|
||||
|
||||
class Address(object):
|
||||
"""Base class for network addresses."""
|
||||
|
||||
def __init__(self, ip_netmask):
|
||||
self.ip_netmask = ip_netmask
|
||||
ip_nw = netaddr.IPNetwork(self.ip_netmask)
|
||||
self.ip = str(ip_nw.ip)
|
||||
self.netmask = str(ip_nw.netmask)
|
||||
self.prefixlen = ip_nw.prefixlen
|
||||
self.version = ip_nw.version
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
ip_netmask = _get_required_field(json, 'ip_netmask', 'Address')
|
||||
return Address(ip_netmask)
|
||||
|
||||
|
||||
class _BaseOpts(object):
|
||||
"""Base abstraction for logical port options."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, primary=False, nic_mapping=None,
|
||||
persist_mapping=False, defroute=True, dhclient_args=None,
|
||||
dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
dns_servers = dns_servers or []
|
||||
numbered_nic_names = _numbered_nics(nic_mapping)
|
||||
self.hwaddr = None
|
||||
self.hwname = None
|
||||
self.renamed = False
|
||||
if name in numbered_nic_names:
|
||||
if persist_mapping:
|
||||
self.name = name
|
||||
self.hwname = numbered_nic_names[name]
|
||||
self.hwaddr = utils.interface_mac(self.hwname)
|
||||
self.renamed = True
|
||||
else:
|
||||
self.name = numbered_nic_names[name]
|
||||
else:
|
||||
self.name = name
|
||||
|
||||
self.mtu = mtu
|
||||
self.use_dhcp = use_dhcp
|
||||
self.use_dhcpv6 = use_dhcpv6
|
||||
self.addresses = addresses
|
||||
self.routes = routes
|
||||
self.primary = primary
|
||||
self.defroute = defroute
|
||||
self.dhclient_args = dhclient_args
|
||||
self.dns_servers = dns_servers
|
||||
self.bridge_name = None # internal
|
||||
self.linux_bridge_name = None # internal
|
||||
self.ivs_bridge_name = None # internal
|
||||
self.nfvswitch_bridge_name = None # internal
|
||||
self.linux_bond_name = None # internal
|
||||
self.linux_team_name = None # internal
|
||||
self.ovs_port = False # internal
|
||||
self.primary_interface_name = None # internal
|
||||
|
||||
def v4_addresses(self):
|
||||
v4_addresses = []
|
||||
for addr in self.addresses:
|
||||
if addr.version == 4:
|
||||
v4_addresses.append(addr)
|
||||
|
||||
return v4_addresses
|
||||
|
||||
def v6_addresses(self):
|
||||
v6_addresses = []
|
||||
for addr in self.addresses:
|
||||
if addr.version == 6:
|
||||
v6_addresses.append(addr)
|
||||
|
||||
return v6_addresses
|
||||
|
||||
@staticmethod
|
||||
def base_opts_from_json(json, include_primary=True):
|
||||
use_dhcp = strutils.bool_from_string(str(json.get('use_dhcp', False)))
|
||||
use_dhcpv6 = strutils.bool_from_string(str(json.get('use_dhcpv6',
|
||||
False)))
|
||||
defroute = strutils.bool_from_string(str(json.get('defroute',
|
||||
True)))
|
||||
mtu = json.get('mtu', None)
|
||||
dhclient_args = json.get('dhclient_args')
|
||||
dns_servers = json.get('dns_servers')
|
||||
primary = strutils.bool_from_string(str(json.get('primary', False)))
|
||||
addresses = []
|
||||
routes = []
|
||||
|
||||
# addresses
|
||||
addresses_json = json.get('addresses')
|
||||
if addresses_json:
|
||||
if isinstance(addresses_json, list):
|
||||
for address in addresses_json:
|
||||
addresses.append(Address.from_json(address))
|
||||
else:
|
||||
msg = 'Addresses must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
# routes
|
||||
routes_json = json.get('routes')
|
||||
if routes_json:
|
||||
if isinstance(routes_json, list):
|
||||
for route in routes_json:
|
||||
routes.append(Route.from_json(route))
|
||||
else:
|
||||
msg = 'Routes must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
nic_mapping = json.get('nic_mapping')
|
||||
persist_mapping = json.get('persist_mapping')
|
||||
|
||||
if include_primary:
|
||||
return (use_dhcp, use_dhcpv6, addresses, routes, mtu, primary,
|
||||
nic_mapping, persist_mapping, defroute, dhclient_args,
|
||||
dns_servers)
|
||||
else:
|
||||
return (use_dhcp, use_dhcpv6, addresses, routes, mtu,
|
||||
nic_mapping, persist_mapping, defroute, dhclient_args,
|
||||
dns_servers)
|
||||
|
||||
|
||||
class Interface(_BaseOpts):
|
||||
"""Base class for network interfaces."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, primary=False, nic_mapping=None,
|
||||
persist_mapping=False, defroute=True, dhclient_args=None,
|
||||
dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
dns_servers = dns_servers or []
|
||||
super(Interface, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping, defroute,
|
||||
dhclient_args, dns_servers)
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'Interface')
|
||||
opts = _BaseOpts.base_opts_from_json(json)
|
||||
return Interface(name, *opts)
|
||||
|
||||
|
||||
class Vlan(_BaseOpts):
|
||||
"""Base class for VLANs.
|
||||
|
||||
NOTE: the name parameter must be formated w/ vlan<num> where <num>
|
||||
matches the vlan ID being used. Example: vlan5
|
||||
"""
|
||||
|
||||
def __init__(self, device, vlan_id, use_dhcp=False, use_dhcpv6=False,
|
||||
addresses=None, routes=None, mtu=None, primary=False,
|
||||
nic_mapping=None, persist_mapping=False, defroute=True,
|
||||
dhclient_args=None, dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
dns_servers = dns_servers or []
|
||||
name = 'vlan%i' % vlan_id
|
||||
super(Vlan, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping, defroute, dhclient_args,
|
||||
dns_servers)
|
||||
self.vlan_id = int(vlan_id)
|
||||
|
||||
numbered_nic_names = _numbered_nics(nic_mapping)
|
||||
if device in numbered_nic_names:
|
||||
self.device = numbered_nic_names[device]
|
||||
else:
|
||||
self.device = device
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
# A vlan on an OVS bridge won't require a device (OVS Int Port)
|
||||
device = json.get('device')
|
||||
vlan_id = _get_required_field(json, 'vlan_id', 'Vlan')
|
||||
opts = _BaseOpts.base_opts_from_json(json)
|
||||
return Vlan(device, vlan_id, *opts)
|
||||
|
||||
|
||||
class IvsInterface(_BaseOpts):
|
||||
"""Base class for ivs interfaces."""
|
||||
|
||||
def __init__(self, vlan_id, name='ivs', use_dhcp=False, use_dhcpv6=False,
|
||||
addresses=None, routes=None, mtu=1500, primary=False,
|
||||
nic_mapping=None, persist_mapping=False, defroute=True,
|
||||
dhclient_args=None, dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
dns_servers = dns_servers or []
|
||||
name_vlan = '%s%i' % (name, vlan_id)
|
||||
super(IvsInterface, self).__init__(name_vlan, use_dhcp, use_dhcpv6,
|
||||
addresses, routes, mtu, primary,
|
||||
nic_mapping, persist_mapping,
|
||||
defroute, dhclient_args,
|
||||
dns_servers)
|
||||
self.vlan_id = int(vlan_id)
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = json.get('name')
|
||||
vlan_id = _get_required_field(json, 'vlan_id', 'IvsInterface')
|
||||
opts = _BaseOpts.base_opts_from_json(json)
|
||||
return IvsInterface(vlan_id, name, *opts)
|
||||
|
||||
|
||||
class NfvswitchInternal(_BaseOpts):
|
||||
"""Base class for nfvswitch internal interfaces."""
|
||||
|
||||
def __init__(self, vlan_id, name='nfvswitch', use_dhcp=False,
|
||||
use_dhcpv6=False, addresses=None, routes=None, mtu=1500,
|
||||
primary=False, nic_mapping=None, persist_mapping=False,
|
||||
defroute=True, dhclient_args=None, dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
dns_servers = dns_servers or []
|
||||
name_vlan = '%s%i' % (name, vlan_id)
|
||||
super(NfvswitchInternal, self).__init__(name_vlan, use_dhcp,
|
||||
use_dhcpv6, addresses, routes,
|
||||
mtu, primary, nic_mapping,
|
||||
persist_mapping, defroute,
|
||||
dhclient_args, dns_servers)
|
||||
self.vlan_id = int(vlan_id)
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = json.get('name')
|
||||
vlan_id = _get_required_field(json, 'vlan_id', 'NfvswitchInternal')
|
||||
opts = _BaseOpts.base_opts_from_json(json)
|
||||
return NfvswitchInternal(vlan_id, name, *opts)
|
||||
|
||||
|
||||
class OvsBridge(_BaseOpts):
|
||||
"""Base class for OVS bridges."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, members=None, ovs_options=None,
|
||||
ovs_extra=None, nic_mapping=None, persist_mapping=False,
|
||||
defroute=True, dhclient_args=None, dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
members = members or []
|
||||
ovs_extra = ovs_extra or []
|
||||
dns_servers = dns_servers or []
|
||||
super(OvsBridge, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, False, nic_mapping,
|
||||
persist_mapping, defroute,
|
||||
dhclient_args, dns_servers)
|
||||
self.members = members
|
||||
self.ovs_options = ovs_options
|
||||
self.ovs_extra = ovs_extra
|
||||
for member in self.members:
|
||||
member.bridge_name = name
|
||||
if not isinstance(member, OvsTunnel):
|
||||
member.ovs_port = True
|
||||
if member.primary:
|
||||
if self.primary_interface_name:
|
||||
msg = 'Only one primary interface allowed per bridge.'
|
||||
raise InvalidConfigException(msg)
|
||||
if member.primary_interface_name:
|
||||
self.primary_interface_name = member.primary_interface_name
|
||||
else:
|
||||
self.primary_interface_name = member.name
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'OvsBridge')
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping, defroute,
|
||||
dhclient_args, dns_servers) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
ovs_options = json.get('ovs_options')
|
||||
ovs_extra = json.get('ovs_extra', [])
|
||||
members = []
|
||||
|
||||
# members
|
||||
members_json = json.get('members')
|
||||
if members_json:
|
||||
if isinstance(members_json, list):
|
||||
for member in members_json:
|
||||
members.append(object_from_json(member))
|
||||
else:
|
||||
msg = 'Members must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
return OvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, ovs_options=ovs_options,
|
||||
ovs_extra=ovs_extra, nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping, defroute=defroute,
|
||||
dhclient_args=dhclient_args, dns_servers=dns_servers)
|
||||
|
||||
|
||||
class LinuxBridge(_BaseOpts):
|
||||
"""Base class for Linux bridges."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, members=None, nic_mapping=None,
|
||||
persist_mapping=False, defroute=True, dhclient_args=None,
|
||||
dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
members = members or []
|
||||
dns_servers = dns_servers or []
|
||||
super(LinuxBridge, self).__init__(name, use_dhcp, use_dhcpv6,
|
||||
addresses, routes, mtu, False,
|
||||
nic_mapping, persist_mapping,
|
||||
defroute, dhclient_args, dns_servers)
|
||||
self.members = members
|
||||
for member in self.members:
|
||||
member.linux_bridge_name = name
|
||||
member.ovs_port = False
|
||||
if member.primary:
|
||||
if self.primary_interface_name:
|
||||
msg = 'Only one primary interface allowed per bridge.'
|
||||
raise InvalidConfigException(msg)
|
||||
if member.primary_interface_name:
|
||||
self.primary_interface_name = member.primary_interface_name
|
||||
else:
|
||||
self.primary_interface_name = member.name
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'LinuxBridge')
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping, defroute, dhclient_args,
|
||||
dns_servers) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
members = []
|
||||
|
||||
# members
|
||||
members_json = json.get('members')
|
||||
if members_json:
|
||||
if isinstance(members_json, list):
|
||||
for member in members_json:
|
||||
members.append(object_from_json(member))
|
||||
else:
|
||||
msg = 'Members must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
return LinuxBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping, defroute=defroute,
|
||||
dhclient_args=dhclient_args,
|
||||
dns_servers=dns_servers)
|
||||
|
||||
|
||||
class IvsBridge(_BaseOpts):
|
||||
"""Base class for IVS bridges.
|
||||
|
||||
Indigo Virtual Switch (IVS) is a virtual switch for Linux.
|
||||
It is compatible with the KVM hypervisor and leveraging the
|
||||
Open vSwitch kernel module for packet forwarding. There are
|
||||
three major differences between IVS and OVS:
|
||||
1. Each node can have at most one ivs, no name required.
|
||||
2. Bond is not allowed to attach to an ivs. It is the SDN
|
||||
controller's job to dynamically form bonds on ivs.
|
||||
3. IP address can only be statically assigned.
|
||||
"""
|
||||
|
||||
def __init__(self, name='ivs', use_dhcp=False, use_dhcpv6=False,
|
||||
addresses=None, routes=None, mtu=1500, members=None,
|
||||
nic_mapping=None, persist_mapping=False, defroute=True,
|
||||
dhclient_args=None, dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
members = members or []
|
||||
dns_servers = dns_servers or []
|
||||
super(IvsBridge, self).__init__(name, use_dhcp, use_dhcpv6,
|
||||
addresses, routes, mtu, False,
|
||||
nic_mapping, persist_mapping,
|
||||
defroute, dhclient_args, dns_servers)
|
||||
self.members = members
|
||||
for member in self.members:
|
||||
if isinstance(member, OvsBond) or isinstance(member, LinuxBond):
|
||||
msg = 'IVS does not support bond interfaces.'
|
||||
raise InvalidConfigException(msg)
|
||||
member.ivs_bridge_name = name
|
||||
member.ovs_port = False
|
||||
self.primary_interface_name = None # ivs doesn't use primary intf
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = 'ivs'
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping, defroute, dhclient_args,
|
||||
dns_servers) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
members = []
|
||||
|
||||
# members
|
||||
members_json = json.get('members')
|
||||
if members_json:
|
||||
if isinstance(members_json, list):
|
||||
for member in members_json:
|
||||
members.append(object_from_json(member))
|
||||
else:
|
||||
msg = 'Members must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
return IvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping, defroute=defroute,
|
||||
dhclient_args=dhclient_args,
|
||||
dns_servers=dns_servers)
|
||||
|
||||
|
||||
class NfvswitchBridge(_BaseOpts):
|
||||
"""Base class for NFVSwitch bridges.
|
||||
|
||||
NFVSwitch is a virtual switch for Linux.
|
||||
It is compatible with the KVM hypervisor and uses DPDK for packet
|
||||
forwarding.
|
||||
"""
|
||||
|
||||
def __init__(self, name='nfvswitch', use_dhcp=False, use_dhcpv6=False,
|
||||
addresses=None, routes=None, mtu=1500, members=None,
|
||||
nic_mapping=None, persist_mapping=False, defroute=True,
|
||||
dhclient_args=None, dns_servers=None, cpus=""):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
members = members or []
|
||||
dns_servers = dns_servers or []
|
||||
super(NfvswitchBridge, self).__init__(name, use_dhcp, use_dhcpv6,
|
||||
addresses, routes, mtu, False,
|
||||
nic_mapping, persist_mapping,
|
||||
defroute, dhclient_args,
|
||||
dns_servers)
|
||||
self.cpus = cpus
|
||||
self.members = members
|
||||
for member in self.members:
|
||||
if isinstance(member, OvsBond) or isinstance(member, LinuxBond):
|
||||
msg = 'NFVSwitch does not support bond interfaces.'
|
||||
raise InvalidConfigException(msg)
|
||||
member.nfvswitch_bridge_name = name
|
||||
member.ovs_port = False
|
||||
self.primary_interface_name = None
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = 'nfvswitch'
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping, defroute, dhclient_args,
|
||||
dns_servers) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
|
||||
# members
|
||||
members = []
|
||||
members_json = json.get('members')
|
||||
if members_json:
|
||||
if isinstance(members_json, list):
|
||||
for member in members_json:
|
||||
members.append(object_from_json(member))
|
||||
else:
|
||||
msg = 'Members must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
cpus = ''
|
||||
cpus_json = json.get('cpus')
|
||||
if cpus_json:
|
||||
if isinstance(cpus_json, basestring):
|
||||
cpus = cpus_json
|
||||
else:
|
||||
msg = '"cpus" must be a string of numbers separated by commas.'
|
||||
raise InvalidConfigException(msg)
|
||||
else:
|
||||
msg = 'Config "cpus" is mandatory.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
return NfvswitchBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping,
|
||||
defroute=defroute, dhclient_args=dhclient_args,
|
||||
dns_servers=dns_servers, cpus=cpus)
|
||||
|
||||
|
||||
class LinuxTeam(_BaseOpts):
|
||||
"""Base class for Linux bonds using teamd."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, primary=False, members=None,
|
||||
bonding_options=None, nic_mapping=None, persist_mapping=False,
|
||||
defroute=True, dhclient_args=None, dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
members = members or []
|
||||
dns_servers = dns_servers or []
|
||||
super(LinuxTeam, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping, defroute,
|
||||
dhclient_args, dns_servers)
|
||||
self.members = members
|
||||
self.bonding_options = bonding_options
|
||||
for member in self.members:
|
||||
member.linux_team_name = name
|
||||
if member.primary:
|
||||
if self.primary_interface_name:
|
||||
msg = 'Only one primary interface allowed per team.'
|
||||
raise InvalidConfigException(msg)
|
||||
if member.primary_interface_name:
|
||||
self.primary_interface_name = member.primary_interface_name
|
||||
else:
|
||||
self.primary_interface_name = member.name
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'LinuxTeam')
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping, defroute, dhclient_args,
|
||||
dns_servers) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
bonding_options = json.get('bonding_options')
|
||||
members = []
|
||||
|
||||
# members
|
||||
members_json = json.get('members')
|
||||
if members_json:
|
||||
if isinstance(members_json, list):
|
||||
for member in members_json:
|
||||
members.append(object_from_json(member))
|
||||
else:
|
||||
msg = 'Members must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
return LinuxTeam(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, bonding_options=bonding_options,
|
||||
nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping, defroute=defroute,
|
||||
dhclient_args=dhclient_args, dns_servers=dns_servers)
|
||||
|
||||
|
||||
class LinuxBond(_BaseOpts):
|
||||
"""Base class for Linux bonds."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, primary=False, members=None,
|
||||
bonding_options=None, nic_mapping=None, persist_mapping=False,
|
||||
defroute=True, dhclient_args=None, dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
members = members or []
|
||||
dns_servers = dns_servers or []
|
||||
super(LinuxBond, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping, defroute,
|
||||
dhclient_args, dns_servers)
|
||||
self.members = members
|
||||
self.bonding_options = bonding_options
|
||||
for member in self.members:
|
||||
member.linux_bond_name = name
|
||||
if member.primary:
|
||||
if self.primary_interface_name:
|
||||
msg = 'Only one primary interface allowed per bond.'
|
||||
raise InvalidConfigException(msg)
|
||||
if member.primary_interface_name:
|
||||
self.primary_interface_name = member.primary_interface_name
|
||||
else:
|
||||
self.primary_interface_name = member.name
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'LinuxBond')
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping, defroute, dhclient_args,
|
||||
dns_servers) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
bonding_options = json.get('bonding_options')
|
||||
members = []
|
||||
|
||||
# members
|
||||
members_json = json.get('members')
|
||||
if members_json:
|
||||
if isinstance(members_json, list):
|
||||
for member in members_json:
|
||||
members.append(object_from_json(member))
|
||||
else:
|
||||
msg = 'Members must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
return LinuxBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, bonding_options=bonding_options,
|
||||
nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping, defroute=defroute,
|
||||
dhclient_args=dhclient_args, dns_servers=dns_servers)
|
||||
|
||||
|
||||
class OvsBond(_BaseOpts):
|
||||
"""Base class for OVS bonds."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, primary=False, members=None,
|
||||
ovs_options=None, ovs_extra=None, nic_mapping=None,
|
||||
persist_mapping=False, defroute=True, dhclient_args=None,
|
||||
dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
members = members or []
|
||||
ovs_extra = ovs_extra or []
|
||||
dns_servers = dns_servers or []
|
||||
super(OvsBond, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping, defroute, dhclient_args,
|
||||
dns_servers)
|
||||
self.members = members
|
||||
self.ovs_options = ovs_options
|
||||
self.ovs_extra = ovs_extra
|
||||
for member in self.members:
|
||||
if member.primary:
|
||||
if self.primary_interface_name:
|
||||
msg = 'Only one primary interface allowed per bond.'
|
||||
raise InvalidConfigException(msg)
|
||||
if member.primary_interface_name:
|
||||
self.primary_interface_name = member.primary_interface_name
|
||||
else:
|
||||
self.primary_interface_name = member.name
|
||||
if not self.primary_interface_name:
|
||||
bond_members = list(self.members)
|
||||
bond_members.sort(key=lambda x: x.name)
|
||||
self.primary_interface_name = bond_members[0].name
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'OvsBond')
|
||||
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
||||
persist_mapping, defroute, dhclient_args,
|
||||
dns_servers) = _BaseOpts.base_opts_from_json(
|
||||
json, include_primary=False)
|
||||
ovs_options = json.get('ovs_options')
|
||||
ovs_extra = json.get('ovs_extra', [])
|
||||
members = []
|
||||
|
||||
# members
|
||||
members_json = json.get('members')
|
||||
if members_json:
|
||||
if isinstance(members_json, list):
|
||||
for member in members_json:
|
||||
members.append(object_from_json(member))
|
||||
else:
|
||||
msg = 'Members must be a list.'
|
||||
raise InvalidConfigException(msg)
|
||||
|
||||
return OvsBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
||||
addresses=addresses, routes=routes, mtu=mtu,
|
||||
members=members, ovs_options=ovs_options,
|
||||
ovs_extra=ovs_extra, nic_mapping=nic_mapping,
|
||||
persist_mapping=persist_mapping, defroute=defroute,
|
||||
dhclient_args=dhclient_args, dns_servers=dns_servers)
|
||||
|
||||
|
||||
class OvsTunnel(_BaseOpts):
|
||||
"""Base class for OVS Tunnels."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, primary=False, nic_mapping=None,
|
||||
persist_mapping=False, defroute=True, dhclient_args=None,
|
||||
dns_servers=None, tunnel_type=None, ovs_options=None,
|
||||
ovs_extra=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
ovs_extra = ovs_extra or []
|
||||
dns_servers = dns_servers or []
|
||||
super(OvsTunnel, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
||||
routes, mtu, primary, nic_mapping,
|
||||
persist_mapping, defroute,
|
||||
dhclient_args, dns_servers)
|
||||
self.tunnel_type = tunnel_type
|
||||
self.ovs_options = ovs_options or []
|
||||
self.ovs_extra = ovs_extra or []
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'OvsTunnel')
|
||||
tunnel_type = _get_required_field(json, 'tunnel_type', 'OvsTunnel')
|
||||
ovs_options = json.get('ovs_options', [])
|
||||
ovs_options = ['options:%s' % opt for opt in ovs_options]
|
||||
ovs_extra = json.get('ovs_extra', [])
|
||||
opts = _BaseOpts.base_opts_from_json(json)
|
||||
return OvsTunnel(name, *opts, tunnel_type=tunnel_type,
|
||||
ovs_options=ovs_options, ovs_extra=ovs_extra)
|
||||
|
||||
|
||||
class OvsPatchPort(_BaseOpts):
|
||||
"""Base class for OVS Patch Ports."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, primary=False, nic_mapping=None,
|
||||
persist_mapping=False, defroute=True, dhclient_args=None,
|
||||
dns_servers=None, bridge_name=None, peer=None,
|
||||
ovs_options=None, ovs_extra=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
ovs_extra = ovs_extra or []
|
||||
dns_servers = dns_servers or []
|
||||
super(OvsPatchPort, self).__init__(name, use_dhcp, use_dhcpv6,
|
||||
addresses, routes, mtu, primary,
|
||||
nic_mapping, persist_mapping,
|
||||
defroute, dhclient_args,
|
||||
dns_servers)
|
||||
self.bridge_name = bridge_name
|
||||
self.peer = peer
|
||||
self.ovs_options = ovs_options or []
|
||||
self.ovs_extra = ovs_extra or []
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'OvsPatchPort')
|
||||
bridge_name = _get_required_field(json, 'bridge_name', 'OvsPatchPort')
|
||||
peer = _get_required_field(json, 'peer', 'OvsPatchPort')
|
||||
ovs_options = json.get('ovs_options', [])
|
||||
ovs_options = ['options:%s' % opt for opt in ovs_options]
|
||||
ovs_extra = json.get('ovs_extra', [])
|
||||
opts = _BaseOpts.base_opts_from_json(json)
|
||||
return OvsPatchPort(name, *opts, bridge_name=bridge_name, peer=peer,
|
||||
ovs_options=ovs_options, ovs_extra=ovs_extra)
|
||||
|
||||
|
||||
class IbInterface(_BaseOpts):
|
||||
"""Base class for InfiniBand network interfaces."""
|
||||
|
||||
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
||||
routes=None, mtu=None, primary=False, nic_mapping=None,
|
||||
persist_mapping=False, defroute=True, dhclient_args=None,
|
||||
dns_servers=None):
|
||||
addresses = addresses or []
|
||||
routes = routes or []
|
||||
dns_servers = dns_servers or []
|
||||
super(IbInterface, self).__init__(name, use_dhcp, use_dhcpv6,
|
||||
addresses, routes, mtu, primary,
|
||||
nic_mapping, persist_mapping,
|
||||
defroute, dhclient_args, dns_servers)
|
||||
|
||||
@staticmethod
|
||||
def from_json(json):
|
||||
name = _get_required_field(json, 'name', 'IbInterface')
|
||||
opts = _BaseOpts.base_opts_from_json(json)
|
||||
return IbInterface(name, *opts)
|
@ -1,70 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2010-2011 OpenStack Foundation
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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 fixtures
|
||||
import stubout
|
||||
import testtools
|
||||
|
||||
from os_net_config import objects
|
||||
|
||||
_TRUE_VALUES = ('True', 'true', '1', 'yes')
|
||||
|
||||
|
||||
class TestCase(testtools.TestCase):
|
||||
|
||||
"""Test case base class for all unit tests."""
|
||||
stub_numbered_nics = True
|
||||
|
||||
def setUp(self):
|
||||
"""Run before each test method to initialize test environment."""
|
||||
|
||||
super(TestCase, self).setUp()
|
||||
self.stubs = stubout.StubOutForTesting()
|
||||
self.stubbed_numbered_nics = {}
|
||||
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return self.stubbed_numbered_nics
|
||||
if self.stub_numbered_nics:
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
|
||||
try:
|
||||
test_timeout = int(test_timeout)
|
||||
except ValueError:
|
||||
# If timeout value is invalid do not set a timeout.
|
||||
test_timeout = 0
|
||||
if test_timeout > 0:
|
||||
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
|
||||
|
||||
self.useFixture(fixtures.NestedTempfile())
|
||||
self.useFixture(fixtures.TempHomeDir())
|
||||
|
||||
if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES:
|
||||
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
|
||||
if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES:
|
||||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
|
||||
self.log_fixture = self.useFixture(fixtures.FakeLogger())
|
||||
|
||||
def tearDown(self):
|
||||
self.stubs.UnsetAll()
|
||||
self.stubs.SmartUnsetAll()
|
||||
super(TestCase, self).tearDown()
|
@ -1,166 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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.path
|
||||
import sys
|
||||
|
||||
import os_net_config
|
||||
from os_net_config import cli
|
||||
from os_net_config import impl_ifcfg
|
||||
from os_net_config.tests import base
|
||||
import six
|
||||
|
||||
|
||||
REALPATH = os.path.dirname(os.path.realpath(__file__))
|
||||
SAMPLE_BASE = os.path.join(REALPATH, '../../', 'etc',
|
||||
'os-net-config', 'samples')
|
||||
|
||||
|
||||
class TestCli(base.TestCase):
|
||||
|
||||
def run_cli(self, argstr, exitcodes=(0,)):
|
||||
orig = sys.stdout
|
||||
orig_stderr = sys.stderr
|
||||
|
||||
sys.stdout = six.StringIO()
|
||||
sys.stderr = six.StringIO()
|
||||
ret = cli.main(argstr.split())
|
||||
self.assertIn(ret, exitcodes)
|
||||
|
||||
stdout = sys.stdout.getvalue()
|
||||
sys.stdout.close()
|
||||
sys.stdout = orig
|
||||
stderr = sys.stderr.getvalue()
|
||||
sys.stderr.close()
|
||||
sys.stderr = orig_stderr
|
||||
return (stdout, stderr)
|
||||
|
||||
def test_bond_noop_output(self):
|
||||
bond_yaml = os.path.join(SAMPLE_BASE, 'bond.yaml')
|
||||
bond_json = os.path.join(SAMPLE_BASE, 'bond.json')
|
||||
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
|
||||
'-c %s' % bond_yaml)
|
||||
self.assertEqual('', stderr)
|
||||
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
|
||||
'-c %s' % bond_json)
|
||||
self.assertEqual('', stderr)
|
||||
sanity_devices = ['DEVICE=br-ctlplane',
|
||||
'DEVICE=em2',
|
||||
'DEVICE=em1',
|
||||
'DEVICE=bond1',
|
||||
'DEVICETYPE=ovs']
|
||||
for dev in sanity_devices:
|
||||
self.assertIn(dev, stdout_yaml)
|
||||
self.assertEqual(stdout_yaml, stdout_json)
|
||||
|
||||
def test_bridge_noop_output(self):
|
||||
bridge_yaml = os.path.join(SAMPLE_BASE, 'bridge_dhcp.yaml')
|
||||
bridge_json = os.path.join(SAMPLE_BASE, 'bridge_dhcp.json')
|
||||
stdout_yaml, stderr = self.run_cli('ARG0 --provider=eni --noop -c %s' %
|
||||
bridge_yaml)
|
||||
self.assertEqual('', stderr)
|
||||
stdout_json, stderr = self.run_cli('ARG0 --provider=eni --noop -c %s' %
|
||||
bridge_json)
|
||||
self.assertEqual('', stderr)
|
||||
sanity_devices = ['iface br-ctlplane inet dhcp',
|
||||
'iface em1',
|
||||
'ovs_type OVSBridge']
|
||||
for dev in sanity_devices:
|
||||
self.assertIn(dev, stdout_yaml)
|
||||
self.assertEqual(stdout_yaml, stdout_json)
|
||||
|
||||
def test_vlan_noop_output(self):
|
||||
vlan_yaml = os.path.join(SAMPLE_BASE, 'bridge_vlan.yaml')
|
||||
vlan_json = os.path.join(SAMPLE_BASE, 'bridge_vlan.json')
|
||||
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop -c %s'
|
||||
% vlan_yaml)
|
||||
self.assertEqual('', stderr)
|
||||
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop -c %s'
|
||||
% vlan_json)
|
||||
self.assertEqual('', stderr)
|
||||
sanity_devices = ['DEVICE=br-ctlplane',
|
||||
'DEVICE=em1',
|
||||
'DEVICE=vlan16',
|
||||
'DEVICETYPE=ovs']
|
||||
for dev in sanity_devices:
|
||||
self.assertIn(dev, stdout_yaml)
|
||||
self.assertEqual(stdout_yaml, stdout_json)
|
||||
|
||||
def test_interface_noop_output(self):
|
||||
interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml')
|
||||
interface_json = os.path.join(SAMPLE_BASE, 'interface.json')
|
||||
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop -c %s'
|
||||
% interface_yaml)
|
||||
self.assertEqual('', stderr)
|
||||
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop -c %s'
|
||||
% interface_json)
|
||||
self.assertEqual('', stderr)
|
||||
sanity_devices = ['DEVICE=em1',
|
||||
'BOOTPROTO=static',
|
||||
'IPADDR=192.0.2.1']
|
||||
for dev in sanity_devices:
|
||||
self.assertIn(dev, stdout_yaml)
|
||||
self.assertEqual(stdout_yaml, stdout_json)
|
||||
|
||||
def test_bridge_noop_rootfs(self):
|
||||
for provider in ('ifcfg', 'eni'):
|
||||
bond_yaml = os.path.join(SAMPLE_BASE, 'bridge_dhcp.yaml')
|
||||
stdout_yaml, stderr = self.run_cli('ARG0 --provider=%s --noop '
|
||||
'--root-dir=/rootfs '
|
||||
'-c %s' % (provider, bond_yaml))
|
||||
self.assertEqual('', stderr)
|
||||
self.assertIn('File: /rootfs/', stdout_yaml)
|
||||
|
||||
def test_interface_noop_detailed_exit_codes(self):
|
||||
interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml')
|
||||
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
|
||||
'-c %s --detailed-exit-codes'
|
||||
% interface_yaml, exitcodes=(2,))
|
||||
|
||||
def test_interface_noop_detailed_exit_codes_no_changes(self):
|
||||
interface_yaml = os.path.join(SAMPLE_BASE, 'interface.yaml')
|
||||
|
||||
class TestImpl(os_net_config.NetConfig):
|
||||
|
||||
def add_interface(self, interface):
|
||||
pass
|
||||
|
||||
def apply(self, cleanup=False, activate=True):
|
||||
# this fake implementation returns no changes
|
||||
return {}
|
||||
|
||||
self.stubs.Set(impl_ifcfg, 'IfcfgNetConfig', TestImpl)
|
||||
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
|
||||
'-c %s --detailed-exit-codes'
|
||||
% interface_yaml, exitcodes=(0,))
|
||||
|
||||
def test_nfvswitch_noop_output(self):
|
||||
nfvswitch_yaml = os.path.join(SAMPLE_BASE, 'nfvswitch.yaml')
|
||||
nfvswitch_json = os.path.join(SAMPLE_BASE, 'nfvswitch.json')
|
||||
stdout_yaml, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
|
||||
'-c %s' % nfvswitch_yaml)
|
||||
self.assertEqual('', stderr)
|
||||
stdout_json, stderr = self.run_cli('ARG0 --provider=ifcfg --noop '
|
||||
'-c %s' % nfvswitch_json)
|
||||
self.assertEqual('', stderr)
|
||||
sanity_devices = ['DEVICE=nic2',
|
||||
'DEVICE=nic3',
|
||||
'DEVICE=api201',
|
||||
'DEVICE=storage202',
|
||||
'DEVICETYPE=nfvswitch']
|
||||
for dev in sanity_devices:
|
||||
self.assertIn(dev, stdout_yaml)
|
||||
self.assertEqual(stdout_yaml, stdout_json)
|
@ -1,297 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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 tempfile
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from os_net_config import impl_eni
|
||||
from os_net_config import objects
|
||||
from os_net_config.tests import base
|
||||
from os_net_config import utils
|
||||
|
||||
_AUTO = "auto eth0\n"
|
||||
|
||||
_v4_IFACE_NO_IP = _AUTO + "iface eth0 inet manual\n"
|
||||
|
||||
_V4_IFACE_STATIC_IP = _AUTO + """iface eth0 inet static
|
||||
address 192.168.1.2
|
||||
netmask 255.255.255.0
|
||||
"""
|
||||
|
||||
_V4_IFACE_STATIC_IP_MULTIPLE = (_V4_IFACE_STATIC_IP + _AUTO +
|
||||
"""iface eth0 inet static
|
||||
address 10.0.0.2
|
||||
netmask 255.0.0.0
|
||||
""")
|
||||
|
||||
_V6_IFACE_STATIC_IP = _AUTO + """iface eth0 inet6 static
|
||||
address fe80::2677:3ff:fe7d:4c
|
||||
netmask 128
|
||||
"""
|
||||
|
||||
_V6_IFACE_STATIC_IP_MULTIPLE = (_V6_IFACE_STATIC_IP + _AUTO +
|
||||
"""iface eth0 inet6 static
|
||||
address 2001:abcd::2
|
||||
netmask 64
|
||||
""")
|
||||
|
||||
_IFACE_DHCP = _AUTO + "iface eth0 inet dhcp\n"
|
||||
|
||||
_OVS_PORT_BASE = _AUTO + "allow-br0 eth0\n"
|
||||
|
||||
_OVS_PORT_IFACE = _OVS_PORT_BASE + """iface eth0 inet manual
|
||||
ovs_bridge br0
|
||||
ovs_type OVSPort
|
||||
"""
|
||||
|
||||
_OVS_BRIDGE_DHCP = """auto br0
|
||||
allow-ovs br0
|
||||
iface br0 inet dhcp
|
||||
ovs_type OVSBridge
|
||||
ovs_ports eth0
|
||||
pre-up ip addr flush dev eth0
|
||||
"""
|
||||
|
||||
_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE = _OVS_BRIDGE_DHCP + \
|
||||
" ovs_extra set bridge br0 other-config:hwaddr=a1:b2:c3:d4:e5\n"
|
||||
|
||||
|
||||
_OVS_BRIDGE_DHCP_OVS_EXTRA = _OVS_BRIDGE_DHCP + \
|
||||
" ovs_extra set bridge br0 other-config:hwaddr=a1:b2:c3:d4:e5" + \
|
||||
" -- br-set-external-id br-ctlplane bridge-id br-ctlplane\n"
|
||||
|
||||
|
||||
_VLAN_NO_IP = """auto vlan5
|
||||
iface vlan5 inet manual
|
||||
vlan-raw-device eth0
|
||||
"""
|
||||
|
||||
_VLAN_OVS_PORT = """auto vlan5
|
||||
allow-br0 vlan5
|
||||
iface vlan5 inet manual
|
||||
ovs_bridge br0
|
||||
ovs_type OVSIntPort
|
||||
ovs_options tag=5
|
||||
"""
|
||||
|
||||
_RTS = """up route add -net 172.19.0.0 netmask 255.255.255.0 gw 192.168.1.1
|
||||
down route del -net 172.19.0.0 netmask 255.255.255.0 gw 192.168.1.1
|
||||
"""
|
||||
|
||||
|
||||
class TestENINetConfig(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestENINetConfig, self).setUp()
|
||||
|
||||
self.provider = impl_eni.ENINetConfig()
|
||||
self.if_name = 'eth0'
|
||||
|
||||
def tearDown(self):
|
||||
super(TestENINetConfig, self).tearDown()
|
||||
|
||||
def get_interface_config(self, name="eth0"):
|
||||
return self.provider.interfaces[name]
|
||||
|
||||
def get_route_config(self):
|
||||
return self.provider.routes[self.if_name]
|
||||
|
||||
def _default_interface(self, addr=[], rts=[]):
|
||||
return objects.Interface(self.if_name, addresses=addr, routes=rts)
|
||||
|
||||
def test_interface_no_ip(self):
|
||||
interface = self._default_interface()
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_v4_IFACE_NO_IP, self.get_interface_config())
|
||||
|
||||
def test_add_interface_with_v4(self):
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = self._default_interface([v4_addr])
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFACE_STATIC_IP, self.get_interface_config())
|
||||
|
||||
def test_add_interface_with_v4_multiple(self):
|
||||
v4_addresses = [objects.Address('192.168.1.2/24'),
|
||||
objects.Address('10.0.0.2/8')]
|
||||
interface = self._default_interface(v4_addresses)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFACE_STATIC_IP_MULTIPLE,
|
||||
self.get_interface_config())
|
||||
|
||||
def test_add_interface_with_v6(self):
|
||||
v6_addr = objects.Address('fe80::2677:3ff:fe7d:4c')
|
||||
interface = self._default_interface([v6_addr])
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V6_IFACE_STATIC_IP, self.get_interface_config())
|
||||
|
||||
def test_add_interface_with_v6_multiple(self):
|
||||
v6_addresses = [objects.Address('fe80::2677:3ff:fe7d:4c'),
|
||||
objects.Address('2001:abcd::2/64')]
|
||||
interface = self._default_interface(v6_addresses)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V6_IFACE_STATIC_IP_MULTIPLE,
|
||||
self.get_interface_config())
|
||||
|
||||
def test_add_interface_dhcp(self):
|
||||
interface = self._default_interface()
|
||||
interface.use_dhcp = True
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_IFACE_DHCP, self.get_interface_config())
|
||||
|
||||
def test_add_interface_with_both_v4_and_v6(self):
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
v6_addr = objects.Address('fe80::2677:3ff:fe7d:4c')
|
||||
interface = self._default_interface([v4_addr, v6_addr])
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFACE_STATIC_IP + _V6_IFACE_STATIC_IP,
|
||||
self.get_interface_config())
|
||||
|
||||
def test_add_ovs_port_interface(self):
|
||||
interface = self._default_interface()
|
||||
interface.ovs_port = True
|
||||
interface.bridge_name = 'br0'
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
|
||||
|
||||
def test_network_with_routes(self):
|
||||
route1 = objects.Route('192.168.1.1', '172.19.0.0/24')
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = self._default_interface([v4_addr], [route1])
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFACE_STATIC_IP, self.get_interface_config())
|
||||
self.assertEqual(_RTS, self.get_route_config())
|
||||
|
||||
def test_network_ovs_bridge_with_dhcp(self):
|
||||
interface = self._default_interface()
|
||||
bridge = objects.OvsBridge('br0', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
|
||||
self.assertEqual(_OVS_BRIDGE_DHCP, self.provider.bridges['br0'])
|
||||
|
||||
def test_network_ovs_bridge_with_dhcp_and_primary_interface(self):
|
||||
|
||||
def test_interface_mac(name):
|
||||
return "a1:b2:c3:d4:e5"
|
||||
self.stubs.Set(utils, 'interface_mac', test_interface_mac)
|
||||
|
||||
interface = objects.Interface(self.if_name, primary=True)
|
||||
bridge = objects.OvsBridge('br0', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
|
||||
self.assertEqual(_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE,
|
||||
self.provider.bridges['br0'])
|
||||
|
||||
def test_network_ovs_bridge_with_dhcp_and_primary_with_ovs_extra(self):
|
||||
|
||||
def test_interface_mac(name):
|
||||
return "a1:b2:c3:d4:e5"
|
||||
self.stubs.Set(utils, 'interface_mac', test_interface_mac)
|
||||
|
||||
interface = objects.Interface(self.if_name, primary=True)
|
||||
ovs_extra = "br-set-external-id br-ctlplane bridge-id br-ctlplane"
|
||||
bridge = objects.OvsBridge('br0', use_dhcp=True,
|
||||
members=[interface],
|
||||
ovs_extra=[ovs_extra])
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_OVS_PORT_IFACE, self.get_interface_config())
|
||||
self.assertEqual(_OVS_BRIDGE_DHCP_OVS_EXTRA,
|
||||
self.provider.bridges['br0'])
|
||||
|
||||
def test_vlan(self):
|
||||
vlan = objects.Vlan('eth0', 5)
|
||||
self.provider.add_vlan(vlan)
|
||||
self.assertEqual(_VLAN_NO_IP, self.get_interface_config('vlan5'))
|
||||
|
||||
def test_vlan_mtu_1500(self):
|
||||
vlan = objects.Vlan('eth0', 5, mtu=1500)
|
||||
self.provider.add_vlan(vlan)
|
||||
expected = _VLAN_NO_IP + ' mtu 1500\n'
|
||||
self.assertEqual(expected, self.get_interface_config('vlan5'))
|
||||
|
||||
def test_vlan_ovs_bridge_int_port(self):
|
||||
vlan = objects.Vlan('eth0', 5)
|
||||
bridge = objects.OvsBridge('br0', use_dhcp=True,
|
||||
members=[vlan])
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.add_vlan(vlan)
|
||||
self.assertEqual(_VLAN_OVS_PORT, self.get_interface_config('vlan5'))
|
||||
|
||||
|
||||
class TestENINetConfigApply(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestENINetConfigApply, self).setUp()
|
||||
self.temp_config_file = tempfile.NamedTemporaryFile()
|
||||
self.ifup_interface_names = []
|
||||
|
||||
def test_config_path(prefix):
|
||||
return self.temp_config_file.name
|
||||
self.stubs.Set(impl_eni, '_network_config_path', test_config_path)
|
||||
|
||||
def test_execute(*args, **kwargs):
|
||||
if args[0] == '/sbin/ifup':
|
||||
self.ifup_interface_names.append(args[1])
|
||||
pass
|
||||
|
||||
self.stubs.Set(processutils, 'execute', test_execute)
|
||||
|
||||
self.provider = impl_eni.ENINetConfig()
|
||||
|
||||
def tearDown(self):
|
||||
self.temp_config_file.close()
|
||||
super(TestENINetConfigApply, self).tearDown()
|
||||
|
||||
def test_network_apply(self):
|
||||
route = objects.Route('192.168.1.1', '172.19.0.0/24')
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('eth0', addresses=[v4_addr],
|
||||
routes=[route])
|
||||
self.provider.add_interface(interface)
|
||||
|
||||
self.provider.apply()
|
||||
iface_data = utils.get_file_data(self.temp_config_file.name)
|
||||
self.assertEqual((_V4_IFACE_STATIC_IP + _RTS), iface_data)
|
||||
self.assertIn('eth0', self.ifup_interface_names)
|
||||
|
||||
def test_apply_noactivate(self):
|
||||
route = objects.Route('192.168.1.1', '172.19.0.0/24')
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('eth0', addresses=[v4_addr],
|
||||
routes=[route])
|
||||
self.provider.add_interface(interface)
|
||||
|
||||
self.provider.apply(activate=False)
|
||||
iface_data = utils.get_file_data(self.temp_config_file.name)
|
||||
self.assertEqual((_V4_IFACE_STATIC_IP + _RTS), iface_data)
|
||||
self.assertEqual([], self.ifup_interface_names)
|
||||
|
||||
def test_dhcp_ovs_bridge_network_apply(self):
|
||||
interface = objects.Interface('eth0')
|
||||
bridge = objects.OvsBridge('br0', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply()
|
||||
iface_data = utils.get_file_data(self.temp_config_file.name)
|
||||
self.assertEqual((_OVS_BRIDGE_DHCP + _OVS_PORT_IFACE), iface_data)
|
||||
self.assertIn('eth0', self.ifup_interface_names)
|
||||
self.assertIn('br0', self.ifup_interface_names)
|
@ -1,976 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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.path
|
||||
import tempfile
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from os_net_config import impl_ifcfg
|
||||
from os_net_config import objects
|
||||
from os_net_config.tests import base
|
||||
from os_net_config import utils
|
||||
|
||||
|
||||
_BASE_IFCFG = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
"""
|
||||
|
||||
_NO_IP = _BASE_IFCFG + "BOOTPROTO=none\n"
|
||||
|
||||
_V4_IFCFG = _BASE_IFCFG + """BOOTPROTO=static
|
||||
IPADDR=192.168.1.2
|
||||
NETMASK=255.255.255.0
|
||||
"""
|
||||
|
||||
_V4_V6_IFCFG = _BASE_IFCFG + """IPV6INIT=yes
|
||||
BOOTPROTO=static
|
||||
IPADDR=192.168.1.2
|
||||
NETMASK=255.255.255.0
|
||||
IPV6_AUTOCONF=no
|
||||
IPV6ADDR=2001:abc:a::/64
|
||||
"""
|
||||
|
||||
_IFCFG_VLAN = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1.120
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
VLAN=yes
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
_V4_IFCFG_MAPPED = _V4_IFCFG.replace('em1', 'nic1') + "HWADDR=a1:b2:c3:d4:e5\n"
|
||||
|
||||
|
||||
_BASE_IB_IFCFG = """# This file is autogenerated by os-net-config
|
||||
DEVICE=ib0
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
TYPE=Infiniband
|
||||
"""
|
||||
|
||||
_V4_IB_IFCFG = _BASE_IB_IFCFG + """BOOTPROTO=static
|
||||
IPADDR=192.168.1.2
|
||||
NETMASK=255.255.255.0
|
||||
"""
|
||||
|
||||
_V4_IFCFG_MULTIPLE = _V4_IFCFG + """IPADDR1=192.168.1.3
|
||||
NETMASK1=255.255.255.255
|
||||
IPADDR2=10.0.0.2
|
||||
NETMASK2=255.0.0.0
|
||||
"""
|
||||
|
||||
_IB_V4_IFCFG_MULTIPLE = _V4_IB_IFCFG + """IPADDR1=192.168.1.3
|
||||
NETMASK1=255.255.255.255
|
||||
IPADDR2=10.0.0.2
|
||||
NETMASK2=255.0.0.0
|
||||
"""
|
||||
|
||||
_V6_IFCFG = _BASE_IFCFG + """IPV6INIT=yes
|
||||
IPV6_AUTOCONF=no
|
||||
IPV6ADDR=2001:abc:a::/64
|
||||
"""
|
||||
|
||||
_V6_IFCFG_MULTIPLE = (_V6_IFCFG + "IPV6ADDR_SECONDARIES=\"2001:abc:b::1/64 " +
|
||||
"2001:abc:c::2/96\"\n")
|
||||
|
||||
_OVS_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\nBOOTPROTO=none\n"
|
||||
|
||||
_OVS_IFCFG_TUNNEL = """# This file is autogenerated by os-net-config
|
||||
DEVICE=tun0
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
DEVICETYPE=ovs
|
||||
TYPE=OVSTunnel
|
||||
OVS_BRIDGE=br-ctlplane
|
||||
OVS_TUNNEL_TYPE=gre
|
||||
OVS_TUNNEL_OPTIONS="options:remote_ip=192.168.1.1"
|
||||
"""
|
||||
|
||||
|
||||
_OVS_BRIDGE_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\n"
|
||||
|
||||
_LINUX_BRIDGE_IFCFG = _BASE_IFCFG + "BRIDGE=br-ctlplane\nBOOTPROTO=none\n"
|
||||
|
||||
_ROUTES = """default via 192.168.1.1 dev em1
|
||||
172.19.0.0/24 via 192.168.1.1 dev em1
|
||||
"""
|
||||
|
||||
_ROUTES_V6 = """default via 2001:db8::1 dev em1
|
||||
2001:db8:dead:beef:cafe::/56 via fd00:fd00:2000::1 dev em1
|
||||
"""
|
||||
|
||||
|
||||
_OVS_INTERFACE = _BASE_IFCFG + """DEVICETYPE=ovs
|
||||
TYPE=OVSPort
|
||||
OVS_BRIDGE=br-ctlplane
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
_OVS_BRIDGE_DHCP = """# This file is autogenerated by os-net-config
|
||||
DEVICE=br-ctlplane
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
DEVICETYPE=ovs
|
||||
TYPE=OVSBridge
|
||||
OVSBOOTPROTO=dhcp
|
||||
OVSDHCPINTERFACES="em1"
|
||||
"""
|
||||
|
||||
_LINUX_BRIDGE_DHCP = """# This file is autogenerated by os-net-config
|
||||
DEVICE=br-ctlplane
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
TYPE=Bridge
|
||||
DELAY=0
|
||||
BOOTPROTO=dhcp
|
||||
"""
|
||||
|
||||
_OVS_BRIDGE_STATIC = """# This file is autogenerated by os-net-config
|
||||
DEVICE=br-ctlplane
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
DEVICETYPE=ovs
|
||||
TYPE=OVSBridge
|
||||
BOOTPROTO=static
|
||||
IPADDR=192.168.1.2
|
||||
NETMASK=255.255.255.0
|
||||
"""
|
||||
|
||||
_LINUX_BRIDGE_STATIC = """# This file is autogenerated by os-net-config
|
||||
DEVICE=br-ctlplane
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
TYPE=Bridge
|
||||
DELAY=0
|
||||
BOOTPROTO=static
|
||||
IPADDR=192.168.1.2
|
||||
NETMASK=255.255.255.0
|
||||
"""
|
||||
|
||||
_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE = _OVS_BRIDGE_DHCP + \
|
||||
"OVS_EXTRA=\"set bridge br-ctlplane other-config:hwaddr=a1:b2:c3:d4:e5\"\n"
|
||||
|
||||
|
||||
_OVS_BRIDGE_DHCP_OVS_EXTRA = _OVS_BRIDGE_DHCP + \
|
||||
"OVS_EXTRA=\"set bridge br-ctlplane other-config:hwaddr=a1:b2:c3:d4:e5" + \
|
||||
" -- br-set-external-id br-ctlplane bridge-id br-ctlplane\"\n"
|
||||
|
||||
|
||||
_BASE_VLAN = """# This file is autogenerated by os-net-config
|
||||
DEVICE=vlan5
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
VLAN=yes
|
||||
PHYSDEV=em1
|
||||
"""
|
||||
|
||||
# vlans on an OVS bridge do not set VLAN=yes or PHYSDEV
|
||||
_BASE_VLAN_OVS = """# This file is autogenerated by os-net-config
|
||||
DEVICE=vlan5
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
"""
|
||||
|
||||
_VLAN_NO_IP = _BASE_VLAN + "BOOTPROTO=none\n"
|
||||
|
||||
|
||||
_VLAN_OVS = _BASE_VLAN_OVS + "DEVICETYPE=ovs\nBOOTPROTO=none\n"
|
||||
|
||||
|
||||
_VLAN_OVS_BRIDGE = _BASE_VLAN_OVS + """DEVICETYPE=ovs
|
||||
TYPE=OVSIntPort
|
||||
OVS_BRIDGE=br-ctlplane
|
||||
OVS_OPTIONS="tag=5"
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
_VLAN_LINUX_BRIDGE = _BASE_VLAN_OVS + """VLAN=yes
|
||||
PHYSDEV=em1
|
||||
BRIDGE=br-ctlplane
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
_OVS_BOND_DHCP = """# This file is autogenerated by os-net-config
|
||||
DEVICE=bond0
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
DEVICETYPE=ovs
|
||||
TYPE=OVSBond
|
||||
OVSBOOTPROTO=dhcp
|
||||
BOND_IFACES="em1 em2"
|
||||
"""
|
||||
|
||||
_LINUX_BOND_DHCP = """# This file is autogenerated by os-net-config
|
||||
DEVICE=bond0
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
BOOTPROTO=dhcp
|
||||
"""
|
||||
|
||||
|
||||
_LINUX_TEAM_DHCP = """# This file is autogenerated by os-net-config
|
||||
DEVICE=team0
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
BOOTPROTO=dhcp
|
||||
DEVICETYPE=Team
|
||||
"""
|
||||
|
||||
|
||||
_LINUX_BOND_INTERFACE = _BASE_IFCFG + """MASTER=bond0
|
||||
SLAVE=yes
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
_LINUX_TEAM_INTERFACE = _BASE_IFCFG + """TEAM_MASTER=team0
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
_IVS_UPLINK = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
DEVICETYPE=ivs
|
||||
IVS_BRIDGE=ivs
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
_IVS_INTERFACE = """# This file is autogenerated by os-net-config
|
||||
DEVICE=storage5
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
TYPE=IVSIntPort
|
||||
DEVICETYPE=ivs
|
||||
IVS_BRIDGE=ivs
|
||||
MTU=1500
|
||||
BOOTPROTO=static
|
||||
IPADDR=172.16.2.7
|
||||
NETMASK=255.255.255.0
|
||||
"""
|
||||
|
||||
_IVS_CONFIG = ('DAEMON_ARGS=\"--hitless --certificate /etc/ivs '
|
||||
'--inband-vlan 4092 -u em1 --internal-port=storage5\"')
|
||||
|
||||
_NFVSWITCH_INTERFACE = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
DEVICETYPE=nfvswitch
|
||||
NFVSWITCH_BRIDGE=nfvswitch
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
_NFVSWITCH_INTERNAL = """# This file is autogenerated by os-net-config
|
||||
DEVICE=storage5
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
TYPE=NFVSWITCHIntPort
|
||||
DEVICETYPE=nfvswitch
|
||||
NFVSWITCH_BRIDGE=nfvswitch
|
||||
MTU=1500
|
||||
BOOTPROTO=static
|
||||
IPADDR=172.16.2.7
|
||||
NETMASK=255.255.255.0
|
||||
"""
|
||||
|
||||
_NFVSWITCH_CONFIG = ('SETUP_ARGS=\" -c 2,3,4,5 -u em1 -m storage5\"')
|
||||
|
||||
_OVS_IFCFG_PATCH_PORT = """# This file is autogenerated by os-net-config
|
||||
DEVICE=br-pub-patch
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
DEVICETYPE=ovs
|
||||
TYPE=OVSPatchPort
|
||||
OVS_BRIDGE=br-ex
|
||||
OVS_PATCH_PEER=br-ex-patch
|
||||
"""
|
||||
|
||||
_LINUX_TEAM_PRIMARY_IFACE = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
TEAM_MASTER=team1
|
||||
TEAM_PORT_CONFIG='{"prio": 100}'
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
|
||||
|
||||
class TestIfcfgNetConfig(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestIfcfgNetConfig, self).setUp()
|
||||
|
||||
self.provider = impl_ifcfg.IfcfgNetConfig()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestIfcfgNetConfig, self).tearDown()
|
||||
|
||||
def get_interface_config(self, name='em1'):
|
||||
return self.provider.interface_data[name]
|
||||
|
||||
def get_vlan_config(self, name='vlan1'):
|
||||
return self.provider.vlan_data[name]
|
||||
|
||||
def get_linux_bond_config(self, name='bond0'):
|
||||
return self.provider.linuxbond_data[name]
|
||||
|
||||
def get_linux_team_config(self, name='team0'):
|
||||
return self.provider.linuxteam_data[name]
|
||||
|
||||
def get_route_config(self, name='em1'):
|
||||
return self.provider.route_data.get(name, '')
|
||||
|
||||
def get_route6_config(self, name='em1'):
|
||||
return self.provider.route6_data.get(name, '')
|
||||
|
||||
def test_add_base_interface(self):
|
||||
interface = objects.Interface('em1')
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_NO_IP, self.get_interface_config())
|
||||
|
||||
def test_add_base_interface_vlan(self):
|
||||
interface = objects.Interface('em1.120')
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_IFCFG_VLAN, self.get_interface_config('em1.120'))
|
||||
|
||||
def test_add_ovs_interface(self):
|
||||
interface = objects.Interface('em1')
|
||||
interface.ovs_port = True
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_OVS_IFCFG, self.get_interface_config())
|
||||
|
||||
def test_add_ovs_tunnel(self):
|
||||
interface = objects.OvsTunnel('tun0')
|
||||
interface.type = 'ovs_tunnel'
|
||||
interface.tunnel_type = 'gre'
|
||||
interface.ovs_options = ['options:remote_ip=192.168.1.1']
|
||||
interface.bridge_name = 'br-ctlplane'
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_OVS_IFCFG_TUNNEL, self.get_interface_config('tun0'))
|
||||
|
||||
def test_add_ovs_patch_port(self):
|
||||
patch_port = objects.OvsPatchPort("br-pub-patch")
|
||||
patch_port.type = 'ovs_patch_port'
|
||||
patch_port.bridge_name = 'br-ex'
|
||||
patch_port.peer = 'br-ex-patch'
|
||||
self.provider.add_interface(patch_port)
|
||||
self.assertEqual(_OVS_IFCFG_PATCH_PORT,
|
||||
self.get_interface_config('br-pub-patch'))
|
||||
|
||||
def test_add_interface_with_v4(self):
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('em1', addresses=[v4_addr])
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFCFG, self.get_interface_config())
|
||||
self.assertEqual('', self.get_route_config())
|
||||
|
||||
def test_add_interface_with_v4_multiple(self):
|
||||
addresses = [objects.Address('192.168.1.2/24'),
|
||||
objects.Address('192.168.1.3/32'),
|
||||
objects.Address('10.0.0.2/8')]
|
||||
interface = objects.Interface('em1', addresses=addresses)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFCFG_MULTIPLE, self.get_interface_config())
|
||||
self.assertEqual('', self.get_route_config())
|
||||
|
||||
def test_add_interface_map_persisted(self):
|
||||
def test_interface_mac(name):
|
||||
macs = {'em1': 'a1:b2:c3:d4:e5'}
|
||||
return macs[name]
|
||||
self.stubs.Set(utils, 'interface_mac', test_interface_mac)
|
||||
|
||||
nic_mapping = {'nic1': 'em1'}
|
||||
self.stubbed_numbered_nics = nic_mapping
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('nic1', addresses=[v4_addr],
|
||||
nic_mapping=nic_mapping,
|
||||
persist_mapping=True)
|
||||
self.assertEqual('a1:b2:c3:d4:e5', interface.hwaddr)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFCFG_MAPPED, self.get_interface_config('nic1'))
|
||||
self.assertEqual('', self.get_route_config('nic1'))
|
||||
|
||||
def test_add_interface_with_v6(self):
|
||||
v6_addr = objects.Address('2001:abc:a::/64')
|
||||
interface = objects.Interface('em1', addresses=[v6_addr])
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V6_IFCFG, self.get_interface_config())
|
||||
|
||||
def test_add_interface_with_v6_multiple(self):
|
||||
addresses = [objects.Address('2001:abc:a::/64'),
|
||||
objects.Address('2001:abc:b::1/64'),
|
||||
objects.Address('2001:abc:c::2/96')]
|
||||
interface = objects.Interface('em1', addresses=addresses)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V6_IFCFG_MULTIPLE, self.get_interface_config())
|
||||
|
||||
def test_network_with_routes(self):
|
||||
route1 = objects.Route('192.168.1.1', default=True)
|
||||
route2 = objects.Route('192.168.1.1', '172.19.0.0/24')
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('em1', addresses=[v4_addr],
|
||||
routes=[route1, route2])
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_IFCFG, self.get_interface_config())
|
||||
self.assertEqual(_ROUTES, self.get_route_config())
|
||||
|
||||
def test_network_with_ipv6_routes(self):
|
||||
route1 = objects.Route('192.168.1.1', default=True)
|
||||
route2 = objects.Route('192.168.1.1', '172.19.0.0/24')
|
||||
route3 = objects.Route('2001:db8::1', default=True)
|
||||
route4 = objects.Route('fd00:fd00:2000::1',
|
||||
'2001:db8:dead:beef:cafe::/56')
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
v6_addr = objects.Address('2001:abc:a::/64')
|
||||
interface = objects.Interface('em1', addresses=[v4_addr, v6_addr],
|
||||
routes=[route1, route2, route3, route4])
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_V4_V6_IFCFG, self.get_interface_config())
|
||||
self.assertEqual(_ROUTES_V6, self.get_route6_config())
|
||||
|
||||
def test_network_ovs_bridge_with_dhcp(self):
|
||||
interface = objects.Interface('em1')
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.assertEqual(_OVS_INTERFACE, self.get_interface_config())
|
||||
self.assertEqual(_OVS_BRIDGE_DHCP,
|
||||
self.provider.bridge_data['br-ctlplane'])
|
||||
|
||||
def test_network_linux_bridge_with_dhcp(self):
|
||||
interface = objects.Interface('em1')
|
||||
bridge = objects.LinuxBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_linux_bridge(bridge)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_LINUX_BRIDGE_IFCFG, self.get_interface_config())
|
||||
self.assertEqual(_LINUX_BRIDGE_DHCP,
|
||||
self.provider.linuxbridge_data['br-ctlplane'])
|
||||
|
||||
def test_network_ovs_bridge_static(self):
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('em1')
|
||||
bridge = objects.OvsBridge('br-ctlplane', members=[interface],
|
||||
addresses=[v4_addr])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.assertEqual(_OVS_INTERFACE, self.get_interface_config())
|
||||
self.assertEqual(_OVS_BRIDGE_STATIC,
|
||||
self.provider.bridge_data['br-ctlplane'])
|
||||
|
||||
def test_network_ovs_bridge_with_tunnel(self):
|
||||
interface = objects.OvsTunnel('tun0')
|
||||
interface.type = 'ovs_tunnel'
|
||||
interface.tunnel_type = 'gre'
|
||||
interface.ovs_options = ['options:remote_ip=192.168.1.1']
|
||||
interface.bridge_name = 'br-ctlplane'
|
||||
self.provider.add_interface(interface)
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
bridge = objects.OvsBridge('br-ctlplane', members=[interface],
|
||||
addresses=[v4_addr])
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.add_interface(interface)
|
||||
self.assertEqual(_OVS_IFCFG_TUNNEL, self.get_interface_config('tun0'))
|
||||
self.assertEqual(_OVS_BRIDGE_STATIC,
|
||||
self.provider.bridge_data['br-ctlplane'])
|
||||
|
||||
def test_network_linux_bridge_static(self):
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('em1')
|
||||
bridge = objects.LinuxBridge('br-ctlplane', members=[interface],
|
||||
addresses=[v4_addr])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.assertEqual(_LINUX_BRIDGE_IFCFG, self.get_interface_config())
|
||||
self.assertEqual(_LINUX_BRIDGE_STATIC,
|
||||
self.provider.bridge_data['br-ctlplane'])
|
||||
|
||||
def test_network_ovs_bridge_with_dhcp_primary_interface(self):
|
||||
def test_interface_mac(name):
|
||||
return "a1:b2:c3:d4:e5"
|
||||
self.stubs.Set(utils, 'interface_mac', test_interface_mac)
|
||||
|
||||
interface = objects.Interface('em1', primary=True)
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.assertEqual(_OVS_INTERFACE, self.get_interface_config())
|
||||
self.assertEqual(_OVS_BRIDGE_DHCP_PRIMARY_INTERFACE,
|
||||
self.provider.bridge_data['br-ctlplane'])
|
||||
|
||||
def test_network_ovs_bridge_with_dhcp_primary_interface_with_extra(self):
|
||||
def test_interface_mac(name):
|
||||
return "a1:b2:c3:d4:e5"
|
||||
self.stubs.Set(utils, 'interface_mac', test_interface_mac)
|
||||
|
||||
interface = objects.Interface('em1', primary=True)
|
||||
ovs_extra = "br-set-external-id br-ctlplane bridge-id br-ctlplane"
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[interface],
|
||||
ovs_extra=[ovs_extra])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.assertEqual(_OVS_INTERFACE, self.get_interface_config())
|
||||
self.assertEqual(_OVS_BRIDGE_DHCP_OVS_EXTRA,
|
||||
self.provider.bridge_data['br-ctlplane'])
|
||||
|
||||
def test_network_ivs_with_uplink_and_interface(self):
|
||||
interface = objects.Interface('em1')
|
||||
v4_addr = objects.Address('172.16.2.7/24')
|
||||
ivs_interface = objects.IvsInterface(vlan_id=5,
|
||||
name='storage',
|
||||
addresses=[v4_addr])
|
||||
bridge = objects.IvsBridge(members=[interface, ivs_interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_ivs_interface(ivs_interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.assertEqual(_IVS_UPLINK, self.get_interface_config())
|
||||
self.assertEqual(_IVS_INTERFACE,
|
||||
self.provider.ivsinterface_data[ivs_interface.name])
|
||||
data = self.provider.generate_ivs_config(['em1'], ['storage5'])
|
||||
self.assertEqual(_IVS_CONFIG, data)
|
||||
|
||||
def test_network_nfvswitch_with_interfaces_and_internal_interfaces(self):
|
||||
interface = objects.Interface('em1')
|
||||
v4_addr = objects.Address('172.16.2.7/24')
|
||||
nfvswitch_internal = objects.NfvswitchInternal(vlan_id=5,
|
||||
name='storage',
|
||||
addresses=[v4_addr])
|
||||
iface_name = nfvswitch_internal.name
|
||||
bridge = objects.NfvswitchBridge(members=[interface,
|
||||
nfvswitch_internal],
|
||||
cpus="2,3,4,5")
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_nfvswitch_internal(nfvswitch_internal)
|
||||
self.provider.add_nfvswitch_bridge(bridge)
|
||||
self.assertEqual(_NFVSWITCH_INTERFACE, self.get_interface_config())
|
||||
self.assertEqual(_NFVSWITCH_INTERNAL,
|
||||
self.provider.nfvswitch_intiface_data[iface_name])
|
||||
data = self.provider.generate_nfvswitch_config(['em1'], ['storage5'])
|
||||
self.assertEqual(_NFVSWITCH_CONFIG, data)
|
||||
|
||||
def test_add_ib_interface_with_v4_multiple(self):
|
||||
addresses = [objects.Address('192.168.1.2/24'),
|
||||
objects.Address('192.168.1.3/32'),
|
||||
objects.Address('10.0.0.2/8')]
|
||||
ib_interface = objects.IbInterface('ib0', addresses=addresses)
|
||||
self.provider.add_interface(ib_interface)
|
||||
self.assertEqual(_IB_V4_IFCFG_MULTIPLE,
|
||||
self.get_interface_config('ib0'))
|
||||
self.assertEqual('', self.get_route_config())
|
||||
|
||||
def test_add_vlan(self):
|
||||
vlan = objects.Vlan('em1', 5)
|
||||
self.provider.add_vlan(vlan)
|
||||
self.assertEqual(_VLAN_NO_IP, self.get_vlan_config('vlan5'))
|
||||
|
||||
def test_add_vlan_ovs(self):
|
||||
vlan = objects.Vlan('em1', 5)
|
||||
vlan.ovs_port = True
|
||||
self.provider.add_vlan(vlan)
|
||||
self.assertEqual(_VLAN_OVS, self.get_vlan_config('vlan5'))
|
||||
|
||||
def test_add_vlan_mtu_1500(self):
|
||||
vlan = objects.Vlan('em1', 5, mtu=1500)
|
||||
self.provider.add_vlan(vlan)
|
||||
expected = _VLAN_NO_IP + 'MTU=1500\n'
|
||||
self.assertEqual(expected, self.get_vlan_config('vlan5'))
|
||||
|
||||
def test_add_ovs_bridge_with_vlan(self):
|
||||
vlan = objects.Vlan('em1', 5)
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[vlan])
|
||||
self.provider.add_vlan(vlan)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.assertEqual(_VLAN_OVS_BRIDGE, self.get_vlan_config('vlan5'))
|
||||
|
||||
def test_add_linux_bridge_with_vlan(self):
|
||||
vlan = objects.Vlan('em1', 5)
|
||||
bridge = objects.LinuxBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[vlan])
|
||||
self.provider.add_vlan(vlan)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.assertEqual(_VLAN_LINUX_BRIDGE, self.get_vlan_config('vlan5'))
|
||||
|
||||
def test_ovs_bond(self):
|
||||
interface1 = objects.Interface('em1')
|
||||
interface2 = objects.Interface('em2')
|
||||
bond = objects.OvsBond('bond0', use_dhcp=True,
|
||||
members=[interface1, interface2])
|
||||
self.provider.add_interface(interface1)
|
||||
self.provider.add_interface(interface2)
|
||||
self.provider.add_bond(bond)
|
||||
self.assertEqual(_NO_IP, self.get_interface_config('em1'))
|
||||
|
||||
em2_config = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em2
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
self.assertEqual(em2_config, self.get_interface_config('em2'))
|
||||
self.assertEqual(_OVS_BOND_DHCP,
|
||||
self.get_interface_config('bond0'))
|
||||
|
||||
def test_linux_bond(self):
|
||||
interface1 = objects.Interface('em1')
|
||||
interface2 = objects.Interface('em2')
|
||||
bond = objects.LinuxBond('bond0', use_dhcp=True,
|
||||
members=[interface1, interface2])
|
||||
self.provider.add_linux_bond(bond)
|
||||
self.provider.add_interface(interface1)
|
||||
self.provider.add_interface(interface2)
|
||||
self.assertEqual(_LINUX_BOND_DHCP,
|
||||
self.get_linux_bond_config('bond0'))
|
||||
self.assertEqual(_LINUX_BOND_INTERFACE,
|
||||
self.get_interface_config('em1'))
|
||||
|
||||
def test_linux_team(self):
|
||||
interface1 = objects.Interface('em1')
|
||||
interface2 = objects.Interface('em2')
|
||||
team = objects.LinuxTeam('team0', use_dhcp=True,
|
||||
members=[interface1, interface2])
|
||||
self.provider.add_linux_team(team)
|
||||
self.provider.add_interface(interface1)
|
||||
self.provider.add_interface(interface2)
|
||||
self.assertEqual(_LINUX_TEAM_DHCP,
|
||||
self.get_linux_team_config('team0'))
|
||||
self.assertEqual(_LINUX_TEAM_INTERFACE,
|
||||
self.get_interface_config('em1'))
|
||||
|
||||
def test_interface_defroute(self):
|
||||
interface1 = objects.Interface('em1')
|
||||
interface2 = objects.Interface('em2', defroute=False)
|
||||
self.provider.add_interface(interface1)
|
||||
self.provider.add_interface(interface2)
|
||||
em1_config = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
BOOTPROTO=none
|
||||
"""
|
||||
em2_config = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em2
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
BOOTPROTO=none
|
||||
DEFROUTE=no
|
||||
"""
|
||||
self.assertEqual(em1_config, self.get_interface_config('em1'))
|
||||
self.assertEqual(em2_config, self.get_interface_config('em2'))
|
||||
|
||||
def test_interface_dhclient_opts(self):
|
||||
interface1 = objects.Interface('em1', dhclient_args='--foobar')
|
||||
self.provider.add_interface(interface1)
|
||||
em1_config = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
PEERDNS=no
|
||||
BOOTPROTO=none
|
||||
DHCLIENTARGS=--foobar
|
||||
"""
|
||||
self.assertEqual(em1_config, self.get_interface_config('em1'))
|
||||
|
||||
def test_interface_single_dns_server(self):
|
||||
interface1 = objects.Interface('em1', dns_servers=['1.2.3.4'])
|
||||
self.provider.add_interface(interface1)
|
||||
em1_config = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
BOOTPROTO=none
|
||||
DNS1=1.2.3.4
|
||||
"""
|
||||
self.assertEqual(em1_config, self.get_interface_config('em1'))
|
||||
|
||||
def test_interface_dns_servers(self):
|
||||
interface1 = objects.Interface('em1', dns_servers=['1.2.3.4',
|
||||
'5.6.7.8'])
|
||||
self.provider.add_interface(interface1)
|
||||
em1_config = """# This file is autogenerated by os-net-config
|
||||
DEVICE=em1
|
||||
ONBOOT=yes
|
||||
HOTPLUG=no
|
||||
NM_CONTROLLED=no
|
||||
BOOTPROTO=none
|
||||
DNS1=1.2.3.4
|
||||
DNS2=5.6.7.8
|
||||
"""
|
||||
self.assertEqual(em1_config, self.get_interface_config('em1'))
|
||||
|
||||
|
||||
class TestIfcfgNetConfigApply(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestIfcfgNetConfigApply, self).setUp()
|
||||
self.temp_ifcfg_file = tempfile.NamedTemporaryFile()
|
||||
self.temp_route_file = tempfile.NamedTemporaryFile()
|
||||
self.temp_route6_file = tempfile.NamedTemporaryFile()
|
||||
self.temp_bridge_file = tempfile.NamedTemporaryFile()
|
||||
self.temp_cleanup_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
self.ifup_interface_names = []
|
||||
self.ovs_appctl_cmds = []
|
||||
|
||||
def test_ifcfg_path(name):
|
||||
return self.temp_ifcfg_file.name
|
||||
self.stubs.Set(impl_ifcfg, 'ifcfg_config_path', test_ifcfg_path)
|
||||
|
||||
def test_routes_path(name):
|
||||
return self.temp_route_file.name
|
||||
self.stubs.Set(impl_ifcfg, 'route_config_path', test_routes_path)
|
||||
|
||||
def test_routes6_path(name):
|
||||
return self.temp_route6_file.name
|
||||
self.stubs.Set(impl_ifcfg, 'route6_config_path', test_routes6_path)
|
||||
|
||||
def test_bridge_path(name):
|
||||
return self.temp_bridge_file.name
|
||||
self.stubs.Set(impl_ifcfg, 'bridge_config_path', test_bridge_path)
|
||||
|
||||
def test_cleanup_pattern():
|
||||
return self.temp_cleanup_file.name
|
||||
self.stubs.Set(impl_ifcfg, 'cleanup_pattern', test_cleanup_pattern)
|
||||
|
||||
def test_execute(*args, **kwargs):
|
||||
if args[0] == '/sbin/ifup':
|
||||
self.ifup_interface_names.append(args[1])
|
||||
elif args[0] == '/bin/ovs-appctl':
|
||||
self.ovs_appctl_cmds.append(' '.join(args))
|
||||
pass
|
||||
self.stubs.Set(processutils, 'execute', test_execute)
|
||||
|
||||
self.provider = impl_ifcfg.IfcfgNetConfig()
|
||||
|
||||
def tearDown(self):
|
||||
self.temp_ifcfg_file.close()
|
||||
self.temp_route_file.close()
|
||||
self.temp_route6_file.close()
|
||||
self.temp_bridge_file.close()
|
||||
if os.path.exists(self.temp_cleanup_file.name):
|
||||
self.temp_cleanup_file.close()
|
||||
super(TestIfcfgNetConfigApply, self).tearDown()
|
||||
|
||||
def test_network_apply(self):
|
||||
route1 = objects.Route('192.168.1.1', default=True)
|
||||
route2 = objects.Route('192.168.1.1', '172.19.0.0/24')
|
||||
v4_addr = objects.Address('192.168.1.2/24')
|
||||
interface = objects.Interface('em1', addresses=[v4_addr],
|
||||
routes=[route1, route2])
|
||||
self.provider.add_interface(interface)
|
||||
|
||||
self.provider.apply()
|
||||
|
||||
ifcfg_data = utils.get_file_data(self.temp_ifcfg_file.name)
|
||||
self.assertEqual(_V4_IFCFG, ifcfg_data)
|
||||
route_data = utils.get_file_data(self.temp_route_file.name)
|
||||
self.assertEqual(_ROUTES, route_data)
|
||||
|
||||
def test_dhcp_ovs_bridge_network_apply(self):
|
||||
interface = objects.Interface('em1')
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply()
|
||||
|
||||
ifcfg_data = utils.get_file_data(self.temp_ifcfg_file.name)
|
||||
self.assertEqual(_OVS_INTERFACE, ifcfg_data)
|
||||
bridge_data = utils.get_file_data(self.temp_bridge_file.name)
|
||||
self.assertEqual(_OVS_BRIDGE_DHCP, bridge_data)
|
||||
route_data = utils.get_file_data(self.temp_route_file.name)
|
||||
self.assertEqual("", route_data)
|
||||
|
||||
def test_apply_noactivate(self):
|
||||
interface = objects.Interface('em1')
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply(activate=False)
|
||||
self.assertEqual([], self.ifup_interface_names)
|
||||
|
||||
def test_bond_active_slave(self):
|
||||
# setup and apply a bond
|
||||
interface1 = objects.Interface('em1')
|
||||
interface2 = objects.Interface('em2', primary=True)
|
||||
bond = objects.OvsBond('bond1', use_dhcp=True,
|
||||
members=[interface1, interface2])
|
||||
self.provider.add_interface(interface1)
|
||||
self.provider.add_interface(interface2)
|
||||
self.provider.add_bond(bond)
|
||||
self.provider.apply()
|
||||
ovs_appctl_cmds = '/bin/ovs-appctl bond/set-active-slave bond1 em2'
|
||||
self.assertIn(ovs_appctl_cmds, self.ovs_appctl_cmds)
|
||||
|
||||
def test_bond_active_ordering(self):
|
||||
# setup and apply a bond
|
||||
interface1 = objects.Interface('em1')
|
||||
interface2 = objects.Interface('em2')
|
||||
bond = objects.OvsBond('bond1', use_dhcp=True,
|
||||
members=[interface1, interface2])
|
||||
self.provider.add_interface(interface1)
|
||||
self.provider.add_interface(interface2)
|
||||
self.provider.add_bond(bond)
|
||||
self.provider.apply()
|
||||
ovs_appctl_cmds = '/bin/ovs-appctl bond/set-active-slave bond1 em1'
|
||||
self.assertIn(ovs_appctl_cmds, self.ovs_appctl_cmds)
|
||||
|
||||
def test_restart_children_on_change(self):
|
||||
# setup and apply a bridge
|
||||
interface = objects.Interface('em1')
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply()
|
||||
self.assertIn('em1', self.ifup_interface_names)
|
||||
self.assertIn('br-ctlplane', self.ifup_interface_names)
|
||||
|
||||
# changing the bridge should restart the interface too
|
||||
self.ifup_interface_names = []
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=False,
|
||||
members=[interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply()
|
||||
self.assertIn('em1', self.ifup_interface_names)
|
||||
|
||||
# test infiniband interfaces act as proper bridge members
|
||||
ib_interface = objects.IbInterface('ib0')
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[ib_interface])
|
||||
self.provider.add_interface(ib_interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply()
|
||||
self.assertIn('ib0', self.ifup_interface_names)
|
||||
self.assertIn('br-ctlplane', self.ifup_interface_names)
|
||||
|
||||
# changing the bridge should restart the interface too
|
||||
self.ifup_interface_names = []
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=False,
|
||||
members=[ib_interface])
|
||||
self.provider.add_interface(interface)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply()
|
||||
self.assertIn('ib0', self.ifup_interface_names)
|
||||
|
||||
# setup and apply a bond on a bridge
|
||||
self.ifup_interface_names = []
|
||||
interface1 = objects.Interface('em1')
|
||||
interface2 = objects.Interface('em2')
|
||||
bond = objects.OvsBond('bond0',
|
||||
members=[interface1, interface2])
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=True,
|
||||
members=[bond])
|
||||
self.provider.add_interface(interface1)
|
||||
self.provider.add_interface(interface2)
|
||||
self.provider.add_bond(bond)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply()
|
||||
|
||||
# changing the bridge should restart everything
|
||||
self.ifup_interface_names = []
|
||||
bridge = objects.OvsBridge('br-ctlplane', use_dhcp=False,
|
||||
members=[bond])
|
||||
self.provider.add_interface(interface1)
|
||||
self.provider.add_interface(interface2)
|
||||
self.provider.add_bond(bond)
|
||||
self.provider.add_bridge(bridge)
|
||||
self.provider.apply()
|
||||
self.assertIn('br-ctlplane', self.ifup_interface_names)
|
||||
self.assertIn('bond0', self.ifup_interface_names)
|
||||
self.assertIn('em1', self.ifup_interface_names)
|
||||
self.assertIn('em2', self.ifup_interface_names)
|
||||
|
||||
def test_restart_interface_counts(self):
|
||||
interface = objects.Interface('em1')
|
||||
self.provider.add_interface(interface)
|
||||
interface2 = objects.Interface('em2')
|
||||
self.provider.add_interface(interface2)
|
||||
self.provider.apply()
|
||||
self.assertEqual(1, self.ifup_interface_names.count("em1"))
|
||||
self.assertEqual(1, self.ifup_interface_names.count("em2"))
|
||||
|
||||
def test_vlan_apply(self):
|
||||
vlan = objects.Vlan('em1', 5)
|
||||
self.provider.add_vlan(vlan)
|
||||
self.provider.apply()
|
||||
|
||||
ifcfg_data = utils.get_file_data(self.temp_ifcfg_file.name)
|
||||
self.assertEqual(_VLAN_NO_IP, ifcfg_data)
|
||||
|
||||
def test_cleanup(self):
|
||||
self.provider.apply(cleanup=True)
|
||||
self.assertTrue(not os.path.exists(self.temp_cleanup_file.name))
|
||||
|
||||
def test_cleanup_not_loopback(self):
|
||||
tmp_lo_file = '%s-lo' % self.temp_cleanup_file.name
|
||||
utils.write_config(tmp_lo_file, 'foo')
|
||||
|
||||
def test_cleanup_pattern():
|
||||
return '%s-*' % self.temp_cleanup_file.name
|
||||
self.stubs.Set(impl_ifcfg, 'cleanup_pattern', test_cleanup_pattern)
|
||||
|
||||
self.provider.apply(cleanup=True)
|
||||
self.assertTrue(os.path.exists(tmp_lo_file))
|
||||
os.remove(tmp_lo_file)
|
@ -1,819 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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 json
|
||||
import six
|
||||
|
||||
from os_net_config import objects
|
||||
from os_net_config.tests import base
|
||||
from os_net_config import utils
|
||||
|
||||
|
||||
class TestRoute(base.TestCase):
|
||||
|
||||
def test_from_json(self):
|
||||
data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24"}'
|
||||
route = objects.Route.from_json(json.loads(data))
|
||||
self.assertEqual("172.19.0.1", route.next_hop)
|
||||
self.assertEqual("172.19.0.0/24", route.ip_netmask)
|
||||
self.assertFalse(route.default)
|
||||
|
||||
def test_from_json_default_route(self):
|
||||
data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", ' \
|
||||
'"default": true}'
|
||||
route = objects.Route.from_json(json.loads(data))
|
||||
self.assertEqual("172.19.0.1", route.next_hop)
|
||||
self.assertEqual("172.19.0.0/24", route.ip_netmask)
|
||||
self.assertTrue(route.default)
|
||||
|
||||
data = '{"next_hop": "172.19.0.1", "ip_netmask": "172.19.0.0/24", ' \
|
||||
'"default": "true"}'
|
||||
route = objects.Route.from_json(json.loads(data))
|
||||
self.assertEqual("172.19.0.1", route.next_hop)
|
||||
self.assertEqual("172.19.0.0/24", route.ip_netmask)
|
||||
self.assertTrue(route.default)
|
||||
|
||||
|
||||
class TestAddress(base.TestCase):
|
||||
|
||||
def test_ipv4_address(self):
|
||||
address = objects.Address('192.168.1.1/24')
|
||||
self.assertEqual("192.168.1.1", address.ip)
|
||||
self.assertEqual("255.255.255.0", address.netmask)
|
||||
self.assertEqual(4, address.version)
|
||||
|
||||
def test_ipv6_address(self):
|
||||
address = objects.Address('2001:abc:a::/64')
|
||||
self.assertEqual("2001:abc:a::", address.ip)
|
||||
self.assertEqual("ffff:ffff:ffff:ffff::", address.netmask)
|
||||
self.assertEqual(6, address.version)
|
||||
|
||||
def test_from_json(self):
|
||||
data = '{"ip_netmask": "192.0.2.5/24"}'
|
||||
address = objects.Address.from_json(json.loads(data))
|
||||
self.assertEqual("192.0.2.5", address.ip)
|
||||
self.assertEqual("255.255.255.0", address.netmask)
|
||||
self.assertEqual(4, address.version)
|
||||
|
||||
def test_from_json_invalid(self):
|
||||
self.assertRaises(objects.InvalidConfigException,
|
||||
objects.Address.from_json,
|
||||
{})
|
||||
data = '{"ip_netmask": false}'
|
||||
json_data = json.loads(data)
|
||||
self.assertRaises(objects.InvalidConfigException,
|
||||
objects.Address.from_json,
|
||||
json_data)
|
||||
|
||||
|
||||
class TestInterface(base.TestCase):
|
||||
|
||||
def test_interface_addresses(self):
|
||||
v4_addr = objects.Address('192.168.1.1/24')
|
||||
v6_addr = objects.Address('2001:abc:a::/64')
|
||||
interface = objects.Interface('foo', addresses=[v4_addr, v6_addr])
|
||||
self.assertEqual("192.168.1.1", interface.v4_addresses()[0].ip)
|
||||
self.assertEqual("2001:abc:a::", interface.v6_addresses()[0].ip)
|
||||
|
||||
def test_from_json_dhcp(self):
|
||||
data = '{"type": "interface", "name": "em1", "use_dhcp": true}'
|
||||
interface = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("em1", interface.name)
|
||||
self.assertTrue(interface.use_dhcp)
|
||||
|
||||
def test_from_json_defroute(self):
|
||||
data = '{"type": "interface", "name": "em1", "use_dhcp": true}'
|
||||
interface1 = objects.object_from_json(json.loads(data))
|
||||
data = """{
|
||||
"type": "interface",
|
||||
"name": "em1",
|
||||
"use_dhcp": true,
|
||||
"defroute": false
|
||||
}
|
||||
"""
|
||||
interface2 = objects.object_from_json(json.loads(data))
|
||||
self.assertTrue(interface1.defroute)
|
||||
self.assertFalse(interface2.defroute)
|
||||
|
||||
def test_from_json_dhclient_args(self):
|
||||
data = """{
|
||||
"type": "interface",
|
||||
"name": "em1",
|
||||
"use_dhcp": true,
|
||||
"dhclient_args": "--foobar"
|
||||
}
|
||||
"""
|
||||
interface1 = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("--foobar", interface1.dhclient_args)
|
||||
|
||||
def test_from_json_dns_servers(self):
|
||||
data = """{
|
||||
"type": "interface",
|
||||
"name": "em1",
|
||||
"use_dhcp": true,
|
||||
"dns_servers": ["1.2.3.4"]
|
||||
}
|
||||
"""
|
||||
interface1 = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual(["1.2.3.4"], interface1.dns_servers)
|
||||
|
||||
def test_from_json_dhcp_nic1(self):
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return {"nic1": "em3"}
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
data = '{"type": "interface", "name": "nic1", "use_dhcp": true}'
|
||||
interface = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("em3", interface.name)
|
||||
self.assertTrue(interface.use_dhcp)
|
||||
|
||||
def test_from_json_with_addresses(self):
|
||||
data = """{
|
||||
"type": "interface",
|
||||
"name": "em1",
|
||||
"use_dhcp": false,
|
||||
"mtu": 1501,
|
||||
"addresses": [{
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}],
|
||||
"routes": [{
|
||||
"next_hop": "192.0.2.1",
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
interface = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("em1", interface.name)
|
||||
self.assertFalse(interface.use_dhcp)
|
||||
self.assertFalse(interface.use_dhcpv6)
|
||||
self.assertEqual(1501, interface.mtu)
|
||||
address1 = interface.v4_addresses()[0]
|
||||
self.assertEqual("192.0.2.1", address1.ip)
|
||||
self.assertEqual("255.255.255.0", address1.netmask)
|
||||
route1 = interface.routes[0]
|
||||
self.assertEqual("192.0.2.1", route1.next_hop)
|
||||
self.assertEqual("192.0.2.1/24", route1.ip_netmask)
|
||||
|
||||
|
||||
class TestVlan(base.TestCase):
|
||||
|
||||
def test_from_json_dhcp(self):
|
||||
data = '{"type": "vlan", "device": "em1", "vlan_id": 16,' \
|
||||
'"use_dhcp": true}'
|
||||
vlan = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("em1", vlan.device)
|
||||
self.assertEqual(16, vlan.vlan_id)
|
||||
self.assertTrue(vlan.use_dhcp)
|
||||
|
||||
def test_from_json_dhcp_nic1(self):
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return {"nic1": "em4"}
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
data = '{"type": "vlan", "device": "nic1", "vlan_id": 16,' \
|
||||
'"use_dhcp": true}'
|
||||
vlan = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("em4", vlan.device)
|
||||
self.assertEqual(16, vlan.vlan_id)
|
||||
self.assertTrue(vlan.use_dhcp)
|
||||
|
||||
|
||||
class TestBridge(base.TestCase):
|
||||
|
||||
def test_from_json_dhcp(self):
|
||||
data = """{
|
||||
"type": "ovs_bridge",
|
||||
"name": "br-foo",
|
||||
"use_dhcp": true,
|
||||
"members": [{
|
||||
"type": "interface",
|
||||
"name": "em1"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("br-foo", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
self.assertTrue(interface1.ovs_port)
|
||||
self.assertEqual("br-foo", interface1.bridge_name)
|
||||
|
||||
def test_from_json_dhcp_with_nic1(self):
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return {"nic1": "em5"}
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
data = """{
|
||||
"type": "ovs_bridge",
|
||||
"name": "br-foo",
|
||||
"use_dhcp": true,
|
||||
"members": [{
|
||||
"type": "interface",
|
||||
"name": "nic1"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("br-foo", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em5", interface1.name)
|
||||
self.assertTrue(interface1.ovs_port)
|
||||
self.assertEqual("br-foo", interface1.bridge_name)
|
||||
|
||||
def test_from_json_primary_interface(self):
|
||||
data = """{
|
||||
"type": "ovs_bridge",
|
||||
"name": "br-foo",
|
||||
"use_dhcp": true,
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em1",
|
||||
"primary": "true"
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em2"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("br-foo", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
self.assertEqual("em1", bridge.primary_interface_name)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
self.assertTrue(interface1.ovs_port)
|
||||
self.assertTrue(interface1.primary)
|
||||
self.assertEqual("br-foo", interface1.bridge_name)
|
||||
interface2 = bridge.members[1]
|
||||
self.assertEqual("em2", interface2.name)
|
||||
self.assertTrue(interface2.ovs_port)
|
||||
self.assertEqual("br-foo", interface2.bridge_name)
|
||||
|
||||
|
||||
class TestLinuxBridge(base.TestCase):
|
||||
|
||||
def test_from_json_dhcp(self):
|
||||
data = """{
|
||||
"type": "linux_bridge",
|
||||
"name": "br-foo",
|
||||
"use_dhcp": true,
|
||||
"members": [{
|
||||
"type": "interface",
|
||||
"name": "em1"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("br-foo", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
self.assertFalse(interface1.ovs_port)
|
||||
self.assertEqual("br-foo", interface1.linux_bridge_name)
|
||||
|
||||
def test_from_json_dhcp_with_nic1(self):
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return {"nic1": "em5"}
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
data = """{
|
||||
"type": "linux_bridge",
|
||||
"name": "br-foo",
|
||||
"use_dhcp": true,
|
||||
"members": [{
|
||||
"type": "interface",
|
||||
"name": "nic1"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("br-foo", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em5", interface1.name)
|
||||
self.assertFalse(interface1.ovs_port)
|
||||
self.assertEqual("br-foo", interface1.linux_bridge_name)
|
||||
|
||||
def test_from_json_primary_interface(self):
|
||||
data = """{
|
||||
"type": "linux_bridge",
|
||||
"name": "br-foo",
|
||||
"use_dhcp": true,
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em1",
|
||||
"primary": "true"
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em2"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("br-foo", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
self.assertEqual("em1", bridge.primary_interface_name)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
self.assertFalse(interface1.ovs_port)
|
||||
self.assertTrue(interface1.primary)
|
||||
self.assertEqual("br-foo", interface1.linux_bridge_name)
|
||||
interface2 = bridge.members[1]
|
||||
self.assertEqual("em2", interface2.name)
|
||||
self.assertFalse(interface2.ovs_port)
|
||||
self.assertEqual("br-foo", interface2.linux_bridge_name)
|
||||
|
||||
|
||||
class TestIvsBridge(base.TestCase):
|
||||
|
||||
def test_interface_from_json(self):
|
||||
data = """{
|
||||
"type": "ivs_bridge",
|
||||
"members": [{
|
||||
"type": "interface",
|
||||
"name": "nic2"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("ivs", bridge.name)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("nic2", interface1.name)
|
||||
self.assertEqual(False, interface1.ovs_port)
|
||||
self.assertEqual("ivs", interface1.ivs_bridge_name)
|
||||
|
||||
def test_ivs_interface_from_json(self):
|
||||
data = """{
|
||||
"type": "ivs_bridge",
|
||||
"members": [{
|
||||
"type": "ivs_interface",
|
||||
"name": "storage",
|
||||
"vlan_id": 202
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("ivs", bridge.name)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("storage202", interface1.name)
|
||||
self.assertEqual(False, interface1.ovs_port)
|
||||
self.assertEqual("ivs", interface1.ivs_bridge_name)
|
||||
|
||||
def test_bond_interface_from_json(self):
|
||||
data = """{
|
||||
"type": "ivs_bridge",
|
||||
"members": [{
|
||||
"type": "linux_bond",
|
||||
"name": "bond1",
|
||||
"members": [
|
||||
{"type": "interface", "name": "nic2"},
|
||||
{"type": "interface", "name": "nic3"}
|
||||
]
|
||||
}]
|
||||
}
|
||||
"""
|
||||
err = self.assertRaises(objects.InvalidConfigException,
|
||||
objects.IvsBridge.from_json,
|
||||
json.loads(data))
|
||||
expected = 'IVS does not support bond interfaces.'
|
||||
self.assertIn(expected, err)
|
||||
|
||||
|
||||
class TestNfvswitchBridge(base.TestCase):
|
||||
|
||||
def test_from_json(self):
|
||||
data = """{
|
||||
"type": "nfvswitch_bridge",
|
||||
"cpus": "2,3,4,5",
|
||||
"members": [
|
||||
{"type": "interface", "name": "nic2"}
|
||||
]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("nfvswitch", bridge.name)
|
||||
self.assertEqual("2,3,4,5", bridge.cpus)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("nic2", interface1.name)
|
||||
self.assertEqual(False, interface1.ovs_port)
|
||||
self.assertEqual("nfvswitch", interface1.nfvswitch_bridge_name)
|
||||
|
||||
|
||||
class TestNfvswitchInterface(base.TestCase):
|
||||
|
||||
def test_interface_from_json(self):
|
||||
data = """{
|
||||
"type": "nfvswitch_bridge",
|
||||
"cpus": "2,3,4,5",
|
||||
"members": [
|
||||
{"type": "interface","name": "nic1"},
|
||||
{"type": "interface","name": "nic2"}
|
||||
]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("nfvswitch", bridge.name)
|
||||
self.assertEqual("2,3,4,5", bridge.cpus)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("nic1", interface1.name)
|
||||
interface2 = bridge.members[1]
|
||||
self.assertEqual("nic2", interface2.name)
|
||||
self.assertEqual(False, interface2.ovs_port)
|
||||
self.assertEqual("nfvswitch", interface1.nfvswitch_bridge_name)
|
||||
|
||||
def test_nfvswitch_internal_from_json(self):
|
||||
data = """{
|
||||
"type": "nfvswitch_bridge",
|
||||
"cpus": "2,3,4,5",
|
||||
"members": [
|
||||
{"type": "nfvswitch_internal", "name": "storage", "vlan_id": 202},
|
||||
{"type": "nfvswitch_internal", "name": "api", "vlan_id": 201}
|
||||
]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("nfvswitch", bridge.name)
|
||||
self.assertEqual("2,3,4,5", bridge.cpus)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("storage202", interface1.name)
|
||||
interface2 = bridge.members[1]
|
||||
self.assertEqual("api201", interface2.name)
|
||||
self.assertEqual(False, interface1.ovs_port)
|
||||
self.assertEqual("nfvswitch", interface1.nfvswitch_bridge_name)
|
||||
|
||||
def test_bond_interface_from_json(self):
|
||||
data = """{
|
||||
"type": "nfvswitch_bridge",
|
||||
"cpus": "2,3,4,5",
|
||||
"members": [{
|
||||
"type": "linux_bond", "name": "bond1", "members":
|
||||
[{"type": "interface", "name": "nic2"},
|
||||
{"type": "interface", "name": "nic3"}]
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
err = self.assertRaises(objects.InvalidConfigException,
|
||||
objects.NfvswitchBridge.from_json,
|
||||
json.loads(data))
|
||||
expected = 'NFVSwitch does not support bond interfaces.'
|
||||
self.assertIn(expected, err)
|
||||
|
||||
|
||||
class TestBond(base.TestCase):
|
||||
|
||||
def test_from_json_dhcp(self):
|
||||
data = """{
|
||||
"type": "ovs_bond",
|
||||
"name": "bond1",
|
||||
"use_dhcp": true,
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em1"
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em2"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("bond1", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
interface2 = bridge.members[1]
|
||||
self.assertEqual("em2", interface2.name)
|
||||
|
||||
def test_from_json_dhcp_with_nic1_nic2(self):
|
||||
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return {"nic1": "em1", "nic2": "em2"}
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
data = """{
|
||||
"type": "ovs_bond",
|
||||
"name": "bond1",
|
||||
"use_dhcp": true,
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "nic1"
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "nic2"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("bond1", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
interface2 = bridge.members[1]
|
||||
self.assertEqual("em2", interface2.name)
|
||||
|
||||
|
||||
class TestLinuxTeam(base.TestCase):
|
||||
|
||||
def test_from_json_dhcp(self):
|
||||
data = """{
|
||||
"type": "team",
|
||||
"name": "team1",
|
||||
"use_dhcp": true,
|
||||
"members": [
|
||||
{ "type": "interface", "name": "em1", "primary": true },
|
||||
{ "type": "interface", "name": "em2" }
|
||||
]
|
||||
}
|
||||
"""
|
||||
team = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("team1", team.name)
|
||||
self.assertTrue(team.use_dhcp)
|
||||
interface1 = team.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
interface2 = team.members[1]
|
||||
self.assertEqual("em2", interface2.name)
|
||||
|
||||
|
||||
class TestLinuxBond(base.TestCase):
|
||||
|
||||
def test_from_json_dhcp(self):
|
||||
data = """{
|
||||
"type": "linux_bond",
|
||||
"name": "bond1",
|
||||
"use_dhcp": true,
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em1"
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "em2"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("bond1", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
interface2 = bridge.members[1]
|
||||
self.assertEqual("em2", interface2.name)
|
||||
|
||||
def test_from_json_dhcp_with_nic1_nic2(self):
|
||||
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return {"nic1": "em1", "nic2": "em2"}
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
data = """{
|
||||
"type": "ovs_bond",
|
||||
"name": "bond1",
|
||||
"use_dhcp": true,
|
||||
"members": [
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "nic1"
|
||||
},
|
||||
{
|
||||
"type": "interface",
|
||||
"name": "nic2"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("bond1", bridge.name)
|
||||
self.assertTrue(bridge.use_dhcp)
|
||||
interface1 = bridge.members[0]
|
||||
self.assertEqual("em1", interface1.name)
|
||||
interface2 = bridge.members[1]
|
||||
self.assertEqual("em2", interface2.name)
|
||||
|
||||
|
||||
class TestOvsTunnel(base.TestCase):
|
||||
|
||||
def test_from_json(self):
|
||||
data = """{
|
||||
"type": "ovs_bridge",
|
||||
"name": "br-foo",
|
||||
"members": [{
|
||||
"type": "ovs_tunnel",
|
||||
"name": "tun0",
|
||||
"tunnel_type": "gre",
|
||||
"ovs_options": [
|
||||
"remote_ip=192.168.1.1"
|
||||
],
|
||||
"ovs_extra": [
|
||||
"ovs extra"
|
||||
]
|
||||
}]
|
||||
}
|
||||
"""
|
||||
bridge = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("br-foo", bridge.name)
|
||||
tun0 = bridge.members[0]
|
||||
self.assertEqual("tun0", tun0.name)
|
||||
self.assertFalse(tun0.ovs_port)
|
||||
self.assertEqual("br-foo", tun0.bridge_name)
|
||||
self.assertEqual("gre", tun0.tunnel_type)
|
||||
self.assertEqual(
|
||||
["options:remote_ip=192.168.1.1"],
|
||||
tun0.ovs_options)
|
||||
self.assertEqual(
|
||||
["ovs extra"],
|
||||
tun0.ovs_extra)
|
||||
|
||||
|
||||
class TestOvsPatchPort(base.TestCase):
|
||||
|
||||
def test_from_json(self):
|
||||
data = """{
|
||||
"type": "ovs_patch_port",
|
||||
"name": "br-pub-patch",
|
||||
"bridge_name": "br-ex",
|
||||
"peer": "br-ex-patch"
|
||||
}
|
||||
"""
|
||||
patch_port = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("br-pub-patch", patch_port.name)
|
||||
self.assertEqual("br-ex", patch_port.bridge_name)
|
||||
self.assertEqual("br-ex-patch", patch_port.peer)
|
||||
|
||||
|
||||
class TestIbInterface(base.TestCase):
|
||||
|
||||
def test_ib_interface_addresses(self):
|
||||
v4_addr = objects.Address('192.168.1.1/24')
|
||||
v6_addr = objects.Address('2001:abc:a::/64')
|
||||
ib_interface = objects.IbInterface('foo', addresses=[v4_addr, v6_addr])
|
||||
self.assertEqual("192.168.1.1", ib_interface.v4_addresses()[0].ip)
|
||||
self.assertEqual("2001:abc:a::", ib_interface.v6_addresses()[0].ip)
|
||||
|
||||
def test_from_json_dhcp(self):
|
||||
data = '{"type": "ib_interface", "name": "ib0", "use_dhcp": true}'
|
||||
ib_interface = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("ib0", ib_interface.name)
|
||||
self.assertTrue(ib_interface.use_dhcp)
|
||||
|
||||
def test_from_json_defroute(self):
|
||||
data = '{"type": "ib_interface", "name": "ib0", "use_dhcp": true}'
|
||||
ib_interface1 = objects.object_from_json(json.loads(data))
|
||||
data = """{
|
||||
"type": "ib_interface",
|
||||
"name": "ib0",
|
||||
"use_dhcp": true,
|
||||
"defroute": false
|
||||
}
|
||||
"""
|
||||
ib_interface2 = objects.object_from_json(json.loads(data))
|
||||
self.assertTrue(ib_interface1.defroute)
|
||||
self.assertFalse(ib_interface2.defroute)
|
||||
|
||||
def test_from_json_dhclient_args(self):
|
||||
data = """{
|
||||
"type": "ib_interface",
|
||||
"name": "ib0",
|
||||
"use_dhcp": true,
|
||||
"dhclient_args": "--foobar"
|
||||
}
|
||||
"""
|
||||
ib_interface1 = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("--foobar", ib_interface1.dhclient_args)
|
||||
|
||||
def test_from_json_dns_servers(self):
|
||||
data = """{
|
||||
"type": "ib_interface",
|
||||
"name": "ib0",
|
||||
"use_dhcp": true,
|
||||
"dns_servers": ["1.2.3.4"]
|
||||
}
|
||||
"""
|
||||
ib_interface1 = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual(["1.2.3.4"], ib_interface1.dns_servers)
|
||||
|
||||
def test_from_json_dhcp_nic1(self):
|
||||
def dummy_numbered_nics(nic_mapping=None):
|
||||
return {"nic1": "ib0"}
|
||||
self.stubs.Set(objects, '_numbered_nics', dummy_numbered_nics)
|
||||
|
||||
data = '{"type": "ib_interface", "name": "nic1", "use_dhcp": true}'
|
||||
ib_interface = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("ib0", ib_interface.name)
|
||||
self.assertTrue(ib_interface.use_dhcp)
|
||||
|
||||
def test_from_json_with_addresses(self):
|
||||
data = """{
|
||||
"type": "ib_interface",
|
||||
"name": "ib0",
|
||||
"use_dhcp": false,
|
||||
"mtu": 1501,
|
||||
"addresses": [{
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}],
|
||||
"routes": [{
|
||||
"next_hop": "192.0.2.1",
|
||||
"ip_netmask": "192.0.2.1/24"
|
||||
}]
|
||||
}
|
||||
"""
|
||||
ib_interface = objects.object_from_json(json.loads(data))
|
||||
self.assertEqual("ib0", ib_interface.name)
|
||||
self.assertFalse(ib_interface.use_dhcp)
|
||||
self.assertFalse(ib_interface.use_dhcpv6)
|
||||
self.assertEqual(1501, ib_interface.mtu)
|
||||
address1 = ib_interface.v4_addresses()[0]
|
||||
self.assertEqual("192.0.2.1", address1.ip)
|
||||
self.assertEqual("255.255.255.0", address1.netmask)
|
||||
route1 = ib_interface.routes[0]
|
||||
self.assertEqual("192.0.2.1", route1.next_hop)
|
||||
self.assertEqual("192.0.2.1/24", route1.ip_netmask)
|
||||
|
||||
|
||||
class TestNumberedNicsMapping(base.TestCase):
|
||||
|
||||
# We want to test the function, not the dummy..
|
||||
stub_numbered_nics = False
|
||||
|
||||
def tearDown(self):
|
||||
super(TestNumberedNicsMapping, self).tearDown()
|
||||
objects._NUMBERED_NICS = None
|
||||
|
||||
def _stub_active_nics(self, nics):
|
||||
def dummy_ordered_active_nics():
|
||||
return nics
|
||||
self.stubs.Set(utils, 'ordered_active_nics', dummy_ordered_active_nics)
|
||||
|
||||
def test_numbered_nics_default(self):
|
||||
self._stub_active_nics(['em1', 'em2'])
|
||||
expected = {'nic1': 'em1', 'nic2': 'em2'}
|
||||
self.assertEqual(expected, objects._numbered_nics())
|
||||
|
||||
def test_numbered_nics_mapped(self):
|
||||
self._stub_active_nics(['em1', 'em2'])
|
||||
mapping = {'nic1': 'em2', 'nic2': 'em1'}
|
||||
expected = {'nic1': 'em2', 'nic2': 'em1'}
|
||||
self.assertEqual(expected, objects._numbered_nics(nic_mapping=mapping))
|
||||
|
||||
def test_numbered_nics_mapped_partial(self):
|
||||
self._stub_active_nics(['em1', 'em2', 'em3', 'em4'])
|
||||
mapping = {'nic1': 'em2', 'nic2': 'em1'}
|
||||
expected = {'nic1': 'em2', 'nic2': 'em1', 'nic3': 'em3', 'nic4': 'em4'}
|
||||
self.assertEqual(expected, objects._numbered_nics(nic_mapping=mapping))
|
||||
|
||||
def test_numbered_nics_map_error_notactive(self):
|
||||
self._stub_active_nics(['em1', 'em2'])
|
||||
mapping = {'nic1': 'em3', 'nic2': 'em1'}
|
||||
expected = {'nic2': 'em1'}
|
||||
self.assertEqual(expected, objects._numbered_nics(nic_mapping=mapping))
|
||||
|
||||
def test_numbered_nics_map_error_duplicate(self):
|
||||
self._stub_active_nics(['em1', 'em2'])
|
||||
mapping = {'nic1': 'em1', 'nic2': 'em1'}
|
||||
err = self.assertRaises(objects.InvalidConfigException,
|
||||
objects._numbered_nics, nic_mapping=mapping)
|
||||
expected = 'em1 already mapped, check mapping file for duplicates'
|
||||
self.assertIn(expected, six.text_type(err))
|
||||
|
||||
def test_numbered_nics_map_mac(self):
|
||||
def dummy_interface_mac(name):
|
||||
mac_map = {'em1': '12:34:56:78:9a:bc',
|
||||
'em2': '12:34:56:de:f0:12'}
|
||||
return mac_map[name]
|
||||
self.stubs.Set(utils, 'interface_mac', dummy_interface_mac)
|
||||
self._stub_active_nics(['em1', 'em2'])
|
||||
mapping = {'nic1': '12:34:56:de:f0:12', 'nic2': '12:34:56:78:9a:bc'}
|
||||
expected = {'nic1': 'em2', 'nic2': 'em1'}
|
||||
self.assertEqual(expected, objects._numbered_nics(nic_mapping=mapping))
|
||||
|
||||
def test_numbered_nics_no_active(self):
|
||||
self._stub_active_nics([])
|
||||
expected = {}
|
||||
# This only emits a warning, so it should still work
|
||||
self.assertEqual(expected, objects._numbered_nics())
|
@ -1,30 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
test_os_net_config
|
||||
----------------------------------
|
||||
|
||||
Tests for `os_net_config` module.
|
||||
"""
|
||||
|
||||
from os_net_config.tests import base
|
||||
|
||||
|
||||
class TestOs_net_config(base.TestCase):
|
||||
|
||||
def test_something(self):
|
||||
pass
|
@ -1,51 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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.path
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
from os_net_config.tests import base
|
||||
from os_net_config import utils
|
||||
|
||||
|
||||
class TestUtils(base.TestCase):
|
||||
|
||||
def test_ordered_active_nics(self):
|
||||
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
self.stubs.Set(utils, '_SYS_CLASS_NET', tmpdir)
|
||||
|
||||
def test_is_active_nic(interface_name):
|
||||
return True
|
||||
self.stubs.Set(utils, '_is_active_nic', test_is_active_nic)
|
||||
|
||||
for nic in ['a1', 'em1', 'em2', 'eth2', 'z1',
|
||||
'enp8s0', 'enp10s0', 'enp1s0f0']:
|
||||
with open(os.path.join(tmpdir, nic), 'w') as f:
|
||||
f.write(nic)
|
||||
|
||||
nics = utils.ordered_active_nics()
|
||||
self.assertEqual('em1', nics[0])
|
||||
self.assertEqual('em2', nics[1])
|
||||
self.assertEqual('eth2', nics[2])
|
||||
self.assertEqual('a1', nics[3])
|
||||
self.assertEqual('enp1s0f0', nics[4])
|
||||
self.assertEqual('enp8s0', nics[5])
|
||||
self.assertEqual('enp10s0', nics[6])
|
||||
self.assertEqual('z1', nics[7])
|
||||
|
||||
shutil.rmtree(tmpdir)
|
@ -1,120 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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 glob
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_SYS_CLASS_NET = '/sys/class/net'
|
||||
|
||||
|
||||
def write_config(filename, data):
|
||||
with open(filename, 'w') as f:
|
||||
f.write(str(data))
|
||||
|
||||
|
||||
def get_file_data(filename):
|
||||
if not os.path.exists(filename):
|
||||
return ''
|
||||
|
||||
try:
|
||||
with open(filename, 'r') as f:
|
||||
return f.read()
|
||||
except IOError:
|
||||
logger.error("Error reading file: %s" % filename)
|
||||
return ''
|
||||
|
||||
|
||||
def interface_mac(name):
|
||||
try: # If the iface is part of a Linux bond, the real MAC is only here.
|
||||
with open('/sys/class/net/%s/bonding_slave/perm_hwaddr' % name,
|
||||
'r') as f:
|
||||
return f.read().rstrip()
|
||||
except IOError:
|
||||
pass # Iface is not part of a bond, continue
|
||||
|
||||
try:
|
||||
with open('/sys/class/net/%s/address' % name, 'r') as f:
|
||||
return f.read().rstrip()
|
||||
except IOError:
|
||||
logger.error("Unable to read mac address: %s" % name)
|
||||
raise
|
||||
|
||||
|
||||
def _is_active_nic(interface_name):
|
||||
try:
|
||||
if interface_name == 'lo':
|
||||
return False
|
||||
|
||||
device_dir = _SYS_CLASS_NET + '/%s/device' % interface_name
|
||||
has_device_dir = os.path.isdir(device_dir)
|
||||
|
||||
operstate = None
|
||||
with open(_SYS_CLASS_NET + '/%s/operstate' % interface_name, 'r') as f:
|
||||
operstate = f.read().rstrip().lower()
|
||||
|
||||
address = None
|
||||
with open(_SYS_CLASS_NET + '/%s/address' % interface_name, 'r') as f:
|
||||
address = f.read().rstrip()
|
||||
|
||||
if has_device_dir and operstate == 'up' and address:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except IOError:
|
||||
return False
|
||||
|
||||
|
||||
def _natural_sort_key(s):
|
||||
nsre = re.compile('([0-9]+)')
|
||||
return [int(text) if text.isdigit() else text
|
||||
for text in re.split(nsre, s)]
|
||||
|
||||
|
||||
def ordered_active_nics():
|
||||
embedded_nics = []
|
||||
nics = []
|
||||
logger.debug("Finding active nics")
|
||||
for name in glob.iglob(_SYS_CLASS_NET + '/*'):
|
||||
nic = name[(len(_SYS_CLASS_NET) + 1):]
|
||||
if _is_active_nic(nic):
|
||||
if nic.startswith('em') or nic.startswith('eth') or \
|
||||
nic.startswith('eno'):
|
||||
logger.debug("%s is an embedded active nic" % nic)
|
||||
embedded_nics.append(nic)
|
||||
else:
|
||||
logger.debug("%s is an active nic" % nic)
|
||||
nics.append(nic)
|
||||
else:
|
||||
logger.debug("%s is not an active nic" % nic)
|
||||
# NOTE: we could just natural sort all active devices,
|
||||
# but this ensures em, eno, and eth are ordered first
|
||||
# (more backwards compatible)
|
||||
active_nics = (sorted(embedded_nics, key=_natural_sort_key) +
|
||||
sorted(nics, key=_natural_sort_key))
|
||||
logger.debug("Active nics are %s" % active_nics)
|
||||
return active_nics
|
||||
|
||||
|
||||
def diff(filename, data):
|
||||
file_data = get_file_data(filename)
|
||||
logger.debug("Diff file data:\n%s" % file_data)
|
||||
logger.debug("Diff data:\n%s" % data)
|
||||
# convert to string as JSON may have unicode in it
|
||||
return not file_data == data
|
@ -1,19 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2014 Red Hat, Inc.
|
||||
#
|
||||
# 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 pbr.version
|
||||
|
||||
version_info = pbr.version.VersionInfo('os-net-config')
|
@ -1,10 +0,0 @@
|
||||
pbr>=0.6,!=0.7,<1.0
|
||||
anyjson>=0.3.3
|
||||
Babel>=0.9.6
|
||||
six>=1.6.0
|
||||
eventlet>=0.13.0
|
||||
iso8601>=0.1.9
|
||||
netaddr>=0.7.6
|
||||
oslo.concurrency>=1.4.1 # Apache-2.0
|
||||
oslo.utils>=1.2.0 # Apache-2.0
|
||||
PyYAML>=3.1.0
|
54
setup.cfg
54
setup.cfg
@ -1,54 +0,0 @@
|
||||
[metadata]
|
||||
name = os-net-config
|
||||
summary = OpenStack network configuration
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://git.openstack.org/cgit/openstack/os-net-config
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Developers
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python
|
||||
|
||||
[files]
|
||||
packages =
|
||||
os_net_config
|
||||
|
||||
[global]
|
||||
setup-hooks =
|
||||
pbr.hooks.setup_hook
|
||||
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
os-net-config = os_net_config.cli:main
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
all_files = 1
|
||||
|
||||
[upload_sphinx]
|
||||
upload-dir = doc/build/html
|
||||
|
||||
[compile_catalog]
|
||||
directory = os_net_config/locale
|
||||
domain = os-net-config
|
||||
|
||||
[update_catalog]
|
||||
domain = os-net-config
|
||||
output_dir = os_net_config/locale
|
||||
input_file = os_net_config/locale/os-net-config.pot
|
||||
|
||||
[extract_messages]
|
||||
keywords = _ gettext ngettext l_ lazy_gettext
|
||||
mapping_file = babel.cfg
|
||||
output_file = os_net_config/locale/os-net-config.pot
|
||||
|
||||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
tag_svn_revision = 0
|
22
setup.py
22
setup.py
@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True)
|
@ -1,13 +0,0 @@
|
||||
hacking>=0.10.2,<0.11 # Apache-2.0
|
||||
|
||||
coverage>=3.6
|
||||
discover
|
||||
fixtures>=0.3.14
|
||||
python-subunit
|
||||
sphinx>=1.1.2
|
||||
oslosphinx
|
||||
testrepository>=0.0.17
|
||||
testscenarios>=0.4,<0.5
|
||||
testtools>=0.9.32
|
||||
mock>=1.0
|
||||
mox>=0.5.3
|
34
tox.ini
34
tox.ini
@ -1,34 +0,0 @@
|
||||
[tox]
|
||||
minversion = 1.6
|
||||
envlist = py27,py33,pypy,pep8
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
install_command = pip install -U {opts} {packages}
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands = python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:pep8]
|
||||
commands = flake8
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:cover]
|
||||
commands = python setup.py testr --coverage --testr-args='{posargs}'
|
||||
|
||||
[testenv:docs]
|
||||
commands = python setup.py build_sphinx
|
||||
|
||||
[flake8]
|
||||
# H803 skipped on purpose per list discussion.
|
||||
# E123, E125 skipped as they are invalid PEP-8.
|
||||
|
||||
show-source = True
|
||||
ignore = E123,E125,H803
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build
|
Loading…
Reference in New Issue
Block a user