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:
Andreas Jaeger 2017-04-17 19:27:38 +02:00
parent 9e1a613204
commit b5418e5912
61 changed files with 13 additions and 6063 deletions

View File

@ -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
View File

@ -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

View File

@ -1,4 +0,0 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/os-net-config.git

View File

@ -1,3 +0,0 @@
# Format is:
# <preferred e-mail> <other e-mail 1>
# <preferred e-mail> <other e-mail 2>

View File

@ -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

View File

@ -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

View File

@ -1,4 +0,0 @@
os-net-config Style Commandments
===============================================
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/

175
LICENSE
View File

@ -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.

View File

@ -1,6 +0,0 @@
include AUTHORS
include ChangeLog
exclude .gitignore
exclude .gitreview
global-exclude *.pyc

View File

@ -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
View 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.

View File

@ -1 +0,0 @@
[python: **.py]

View File

@ -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}

View File

@ -1,4 +0,0 @@
============
Contributing
============
.. include:: ../../CONTRIBUTING.rst

View File

@ -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`

View File

@ -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

View File

@ -1 +0,0 @@
.. include:: ../../README.rst

View File

@ -1,7 +0,0 @@
========
Usage
========
To use os-net-config in a project::
import os_net_config

View File

@ -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" }
]
}
]
}
]
}

View File

@ -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

View File

@ -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

View File

@ -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"
}
]
}
]
}

View File

@ -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

View File

@ -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"
}]
}
]
}

View File

@ -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

View File

@ -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
}
]
}

View File

@ -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

View File

@ -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
}
]
}

View File

@ -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

View File

@ -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
}
]
}
]
}

View File

@ -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

View File

@ -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

View File

@ -1,9 +0,0 @@
network_config:
-
type: linux_bridge
name: br-ctlplane
use_dhcp: true
members:
-
type: interface
name: em1

View File

@ -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

View File

@ -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
}
]
}
]
}

View File

@ -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

View File

@ -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"
}
]
}

View File

@ -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

View File

@ -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" }
]
}
]
}

View File

@ -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

View File

@ -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)

View File

@ -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))

View File

@ -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}

View File

@ -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

View File

@ -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."""

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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)

View 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())

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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
View File

@ -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