Build Windows Templates in RHV
This commit is contained in:
12
roles/linux-system-roles.network/.ansible-lint
Normal file
12
roles/linux-system-roles.network/.ansible-lint
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
skip_list:
|
||||
- '106' # Role name does not match ^[a-z][a-z0-9_]+$ pattern
|
||||
- '206' # Variables should have spaces before and after: {{ var_name }}
|
||||
- '208' # File permissions unset or incorrect
|
||||
- '301' # Commands should not change things if nothing needs doing
|
||||
- '303' # Using command rather than module
|
||||
- '305' # Use shell only when shell functionality is required
|
||||
- '403' # Package installs should not use latest
|
||||
- '502' # All tasks should be named
|
||||
- '601' # Don't compare to literal True/False
|
||||
- '602' # Don't compare to empty string
|
||||
12
roles/linux-system-roles.network/.github/stale.yml
vendored
Normal file
12
roles/linux-system-roles.network/.github/stale.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
daysUntilStale: 30
|
||||
daysUntilClose: 14
|
||||
staleLabel: stale
|
||||
markComment: >
|
||||
Thank you for your contribution! There was no activity in this pull request
|
||||
recently. To avoid pull requests to pile up, an automated process marked this
|
||||
pull request as stale. It will close this pull request if no further activity
|
||||
occurs. The current policy is available at:
|
||||
https://github.com//linux-system-roles/network/blob/main/.github/stale.yml
|
||||
only: pulls
|
||||
11
roles/linux-system-roles.network/.github/workflows/markdownlint.yml
vendored
Normal file
11
roles/linux-system-roles.network/.github/workflows/markdownlint.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: markdownlint
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
markdownlint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@main
|
||||
- name: Run mdl
|
||||
uses: actionshub/markdownlint@main
|
||||
51
roles/linux-system-roles.network/.github/workflows/tox.yml
vendored
Normal file
51
roles/linux-system-roles.network/.github/workflows/tox.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# yamllint disable rule:line-length
|
||||
name: tox
|
||||
on: # yamllint disable-line rule:truthy
|
||||
- pull_request
|
||||
env:
|
||||
TOX_LSR: "git+https://github.com/linux-system-roles/tox-lsr@2.4.0"
|
||||
LSR_ANSIBLE_TEST_DOCKER: "true"
|
||||
LSR_ANSIBLES: 'ansible==2.8.* ansible==2.9.*'
|
||||
LSR_MSCENARIOS: default
|
||||
# LSR_EXTRA_PACKAGES: "libdbus-1-dev libgirepository1.0-dev python3-dev"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
jobs:
|
||||
python:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
pyver: ['2.7', '3.6', '3.7', '3.8']
|
||||
steps:
|
||||
- name: checkout PR
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.pyver }}
|
||||
- name: Install platform dependencies, python, tox, tox-lsr
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
python -m pip install --upgrade pip
|
||||
sudo apt-get update
|
||||
sudo apt-get install git
|
||||
pip install "$TOX_LSR"
|
||||
lsr_ci_preinstall
|
||||
- name: Run tox tests
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
toxpyver=$(echo "${{ matrix.pyver }}" | tr -d .)
|
||||
toxenvs="py${toxpyver}"
|
||||
case "$toxpyver" in
|
||||
27) toxenvs="${toxenvs},coveralls,flake8,pylint" ;;
|
||||
36) toxenvs="${toxenvs},coveralls,black,yamllint,ansible-lint,collection" ;;
|
||||
37) toxenvs="${toxenvs},coveralls" ;;
|
||||
38) toxenvs="${toxenvs},coveralls" ;;
|
||||
esac
|
||||
TOXENV="$toxenvs" lsr_ci_runtox
|
||||
python-26:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout PR
|
||||
uses: actions/checkout@v2
|
||||
- name: Run py26 tests
|
||||
uses: linux-system-roles/lsr-gh-action-py26@1.0.1
|
||||
5
roles/linux-system-roles.network/.lgtm.yml
Normal file
5
roles/linux-system-roles.network/.lgtm.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
extraction:
|
||||
python:
|
||||
python_setup:
|
||||
version: 2
|
||||
9
roles/linux-system-roles.network/.mdl_style.rb
Normal file
9
roles/linux-system-roles.network/.mdl_style.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
all
|
||||
# https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md#md003---header-style
|
||||
rule 'MD003', :style => :setext_with_atx
|
||||
# https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md#md013---line-length
|
||||
rule 'MD013', :line_length => 88
|
||||
# https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md#md029---ordered-list-item-prefix
|
||||
rule 'MD029', :style => :ordered
|
||||
# https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md#md024---multiple-headers-with-the-same-content
|
||||
rule "MD024", :allow_different_nesting => true
|
||||
1
roles/linux-system-roles.network/.mdlrc
Normal file
1
roles/linux-system-roles.network/.mdlrc
Normal file
@@ -0,0 +1 @@
|
||||
style '.mdl_style.rb'
|
||||
11
roles/linux-system-roles.network/.travis/custom.sh
Executable file
11
roles/linux-system-roles.network/.travis/custom.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
set -e
|
||||
|
||||
. "$LSR_SCRIPTDIR/utils.sh"
|
||||
|
||||
# Write your custom commands here that should be run when `tox -e custom`:
|
||||
if lsr_check_python_version python -eq '3.6'; then
|
||||
(set -x; cd "${TOPDIR}/tests"; python ./ensure_provider_tests.py)
|
||||
fi
|
||||
23
roles/linux-system-roles.network/.yamllint.yml
Normal file
23
roles/linux-system-roles.network/.yamllint.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
---
|
||||
extends: yamllint_defaults.yml
|
||||
# possible customizations over the base yamllint config
|
||||
# skip the yaml files in the /tests/ directory
|
||||
# NOTE: If you want to customize `ignore` you'll have to
|
||||
# copy in all of the config from .yamllint.yml, then
|
||||
# add your own - so if you want to just add /tests/ to
|
||||
# be ignored, you'll have to add the ignores from the base
|
||||
# ignore: |
|
||||
# /tests/
|
||||
# /.tox/
|
||||
# skip checking line length
|
||||
# NOTE: the above does not apply to `rules` - you do not
|
||||
# have to copy all of the rules from the base config
|
||||
# rules:
|
||||
# line-length: disable
|
||||
rules:
|
||||
truthy: disable
|
||||
line-length:
|
||||
ignore: |
|
||||
/tests/tests_wireless_plugin_installation_nm.yml
|
||||
/tests/tests_team_plugin_installation_nm.yml
|
||||
49
roles/linux-system-roles.network/CHANGELOG.md
Normal file
49
roles/linux-system-roles.network/CHANGELOG.md
Normal file
@@ -0,0 +1,49 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
[1.3.0] - 2021-04-08
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
|
||||
- Use inclusive language
|
||||
- `slave` is deprecated in favor of `port`
|
||||
- `master` is deprecated in favor of `controller`
|
||||
|
||||
### New features
|
||||
|
||||
- Support disabling IPv6
|
||||
- Support `dns_options` when using one or more IPv4 nameservers
|
||||
- Support Ethtool coalesce settings
|
||||
- Support dummy interfaces
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fix static IPv6 support for initscripts provider
|
||||
|
||||
[1.2.0] - 2020-08-26
|
||||
--------------------
|
||||
|
||||
### Changes
|
||||
|
||||
- Rename ethtool features to use underscores instead of dashes to support
|
||||
Jinja2 dot notation. Accept old notation for compatibility with existing
|
||||
playbooks.
|
||||
|
||||
### New features
|
||||
|
||||
- Initial 802.1x authentication support (only EAP-TLS)
|
||||
- Wireless support
|
||||
- Handle OracleLinux as a RHEL clone
|
||||
- Remove dependency on ethtool command line tool
|
||||
- initscripts: Support creating and activating bond profiles in one run
|
||||
- Ignore up/down states if a profile is not defined and not present on the
|
||||
managed host
|
||||
- Document bond profiles
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- NetworkManager: Always rollback checkpoint on failure
|
||||
- NetworkManager: Try to reapply changes to reduce network interruptions
|
||||
- initscripts: Fix dependencies for Fedora 32
|
||||
- Only log actual warnings as Ansible warnings
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# ansible and dependencies for all supported platforms
|
||||
ansible ; python_version > "2.6"
|
||||
ansible<2.7 ; python_version < "2.7"
|
||||
idna<2.8 ; python_version < "2.7"
|
||||
PyYAML<5.1 ; python_version < "2.7"
|
||||
409
roles/linux-system-roles.network/contributing.md
Normal file
409
roles/linux-system-roles.network/contributing.md
Normal file
@@ -0,0 +1,409 @@
|
||||
Contributing to the Network Linux System Role
|
||||
=============================================
|
||||
|
||||
Where to start
|
||||
--------------
|
||||
|
||||
- **Bugs and needed implementations** are listed on [Github
|
||||
Issues](https://github.com/linux-system-roles/network/issues). Issues labeled with
|
||||
[**help
|
||||
wanted**](https://github.com/linux-system-roles/network/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)
|
||||
are likely to be suitable for new contributors!
|
||||
|
||||
- **Code** is managed on
|
||||
[Github](https://github.com/linux-system-roles/network), using [Pull
|
||||
Requests](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests).
|
||||
|
||||
- The code needs to be **compatible with Python 2.6, 2.7, 3.6, 3.7 and 3.8**.
|
||||
|
||||
Code structure
|
||||
--------------
|
||||
|
||||
The repository is structured as follows:
|
||||
|
||||
- `./defaults/` - Contains the default role configuration.
|
||||
|
||||
- `./examples/` - Contains YAML examples for different configurations.
|
||||
|
||||
- `./library/network_connections.py` - Contains the internal Ansible module, which is
|
||||
the main script. It controls the communication between the role and Ansible, imports
|
||||
the YAML configuration and applies the changes to the provider (i.e. NetworkManager,
|
||||
initscripts).
|
||||
|
||||
- `./meta/` - Metadata of the project.
|
||||
|
||||
- `./module_utils/network_lsr/` - Contains other files that are useful for the network
|
||||
role (e.g. the YAML argument validator)
|
||||
|
||||
- `./tasks/` - Declaration of the different tasks that the role is going to execute.
|
||||
|
||||
- `./tests/playbooks/` - Contains the complete tests for the role. `./tests/test_*.yml`
|
||||
are shims to run tests once for every provider. `./tests/tasks/` contains task
|
||||
snippets that are used in multiple tests to avoid having the same code repeated
|
||||
multiple times.
|
||||
|
||||
The rest of files in the root folder mostly serve as configuration files for diferent
|
||||
testing tools and bots that help with the manteinance of the project.
|
||||
|
||||
The code files will always have the imports on the first place, followed by constants
|
||||
and in the last place, classes and methods. The style of python coding for this project
|
||||
is [**PEP 8**](https://www.python.org/dev/peps/pep-0008/), with automatic formatting
|
||||
thanks to [Python Black](https://black.readthedocs.io/en/stable/). Make sure to install
|
||||
the formatter, it will help you a lot throughout the whole coding process!
|
||||
|
||||
Configuring Git
|
||||
---------------
|
||||
|
||||
Before starting to contribute, make sure you have the basic git configuration: Your name
|
||||
and email. This will be useful when signing your contributions. The following commands
|
||||
will set your global name and email, althought you can change it later for every repo:
|
||||
|
||||
```bash
|
||||
git config --global user.name "Jane Doe"
|
||||
git config --global user.email janedoe@example.com
|
||||
```
|
||||
|
||||
The git editor is your system's default. If you feel more comfortable with a different
|
||||
editor for writing your commits (such as Vim), change it with:
|
||||
|
||||
```bash
|
||||
git config --global core.editor vim
|
||||
```
|
||||
|
||||
If you want to check your settings, use `git config --list` to see all the settings Git
|
||||
can find.
|
||||
|
||||
How to contribute
|
||||
-----------------
|
||||
|
||||
1. Make a
|
||||
[fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo)
|
||||
of this repository.
|
||||
|
||||
2. Create a new git branch on your local fork (the name is not relevant) and make the
|
||||
changes you need to complete an issue.
|
||||
|
||||
3. Do not forget to run unit and integration tests before pushing any changes!
|
||||
1. This project uses [tox](https://tox.readthedocs.io/en/latest/) to run unit tests.
|
||||
You can try it with `tox -e py36` in case you want to try it using Python 3.6, or
|
||||
just `tox` if you want to run all the tests.
|
||||
|
||||
2. Check the formatting of the code with
|
||||
[Python Black](https://black.readthedocs.io/en/stable/)
|
||||
|
||||
3. Check the YAML files are correctly formatted using `tox -e yamllint`.
|
||||
|
||||
4. Integration tests are executed as
|
||||
[Ansible Playbooks](https://docs.ansible.com/ansible/latest/user_guide/playbooks.html).
|
||||
|
||||
To run them you can use a cloud image like the [CentOS Linux 8.1
|
||||
VM](https://cloud.centos.org/centos/8/x86_64/images/CentOS-8-GenericCloud-8.1.1911-20200113.3.x86_64.qcow2)
|
||||
and execute the command and download the package
|
||||
`standard-test-roles-inventory-qemu` from the Fedora repository:
|
||||
|
||||
```bash
|
||||
dnf install standard-test-roles-inventory-qemu
|
||||
```
|
||||
|
||||
Note that the last path is the one of the test you want to run:
|
||||
|
||||
```bash
|
||||
TEST_SUBJECTS=CentOS-8-GenericCloud-8.1.1911-20200113.3.x86_64.qcow2 \
|
||||
ansible-playbook -v -i /usr/share/ansible/inventory/standard-inventory-qcow2 \
|
||||
tests/test_default.yml
|
||||
```
|
||||
|
||||
5. Check the markdown format with
|
||||
[mdl](https://github.com/markdownlint/markdownlint) after changing any
|
||||
markdown document.
|
||||
|
||||
4. Once the work is ready and commited, push the branch to your remote fork and click on
|
||||
"new Pull Request" on Github.
|
||||
|
||||
5. All set! Now wait for the continuous integration to pass and go over your commit if
|
||||
there are any errors. If there is no problem with your contribution, the mantainer
|
||||
will merge it to the main project.
|
||||
|
||||
### Find other images for testing
|
||||
|
||||
The CentOS project publishes cloud images for
|
||||
[CentOS Linux 6](https://cloud.centos.org/centos/6/images/),
|
||||
[CentOS Linux 7](https://cloud.centos.org/centos/7/images/) and
|
||||
[CentOS Linux 8](https://cloud.centos.org/centos/8/x86_64/images/).
|
||||
|
||||
- For qemu testing cases, we prefer the image architecture to be `x86_64-GenericCloud`.
|
||||
- `2003` in `CentOS-7-x86_64-GenericCloud-2003.qcow2c` stands for image released in
|
||||
March 2020.
|
||||
- We can use the image with extension `.qcow2` and `.qcow2c`.
|
||||
- To save the image, right click on the link above, then select "Save link as...".
|
||||
|
||||
For Fedora, we recommend to use the [latest qcow2
|
||||
images](https://kojipkgs.fedoraproject.org/compose/cloud/).
|
||||
|
||||
### Some important tips
|
||||
|
||||
- Make sure your fork and branch are up-to-date with the main project. First of all,
|
||||
[configure a remote upstream for your
|
||||
fork](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork),
|
||||
and keep your branch up-to-date with the upstream using
|
||||
`git pull --rebase upstream main`.
|
||||
|
||||
- Try to make a commit per issue.
|
||||
|
||||
- If you are asked to make changes to your PR, don't panic! Many times it is enough to
|
||||
amend your previous commit adding the new content to it (`git commit --amend`). Be
|
||||
sure to pull the latest upstream changes after that, and use `git push
|
||||
--force-with-lease` to re-upload your commit with the changes! Another way of doing
|
||||
changes to a PR is by [squashing
|
||||
commits](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-merges#squash-and-merge-your-pull-request-commits).
|
||||
|
||||
- There are times when someone has made changes on a file you were modifying while you
|
||||
were making changes to your unfinished commit. At times like this, you need to make a
|
||||
[**rebase**](https://help.github.com/en/github/using-git/about-git-rebase) with
|
||||
conflicts. On the rebase you have to compare what the other person added to what you
|
||||
added, and merge both file versions into one that combines it all.
|
||||
|
||||
- If you have any doubt, do not hesitate to ask! You can join IRC channel \#systemroles
|
||||
on freenode, or ask on the PR/issue itself.
|
||||
|
||||
### Naming Ansible Items
|
||||
|
||||
- All YAML or Python files, variables, arguments, repositories, and other such names
|
||||
should follow standard Python naming conventions of being in
|
||||
`snake_case_naming_schemes`.
|
||||
|
||||
- Names should be mnemonic and descriptive and not strive to shorten more than
|
||||
necessary. Systems support long identifier names, so use them to be descriptive
|
||||
|
||||
- All defaults and all arguments to a role should have a name that begins with the role
|
||||
name to help avoid collision with other names. Avoid names like `packages` in favor of
|
||||
a name like `network_packages`.
|
||||
|
||||
- Same argument applies for modules provided in the roles, they also need a `$ROLENAME_`
|
||||
prefix: `network_module`. While they are usually implementation details and not intended
|
||||
for direct use in playbooks, the unfortunate fact is that importing a role makes them
|
||||
available to the rest of the playbook and therefore creates opportunities for name
|
||||
collisions.
|
||||
|
||||
- Moreover, internal variables (those that are not expected to be set by users) are to
|
||||
be prefixed by two underscores: `__network_variable`. This includes variables set by
|
||||
`set_fact` and `register`, because they persist in the namespace after the role has
|
||||
finished!
|
||||
|
||||
- Do not use special characters other than underscore in variable names, even if
|
||||
YAML/JSON allow them. (Using such variables in Jinja2 or Python would be then very
|
||||
confusing and probably not functional.)
|
||||
|
||||
*Find more explanation on this matter in the [meta
|
||||
standards](https://github.com/oasis-roles/meta_standards#naming-things).*
|
||||
|
||||
### Write a good commit message
|
||||
|
||||
Here are a few rules to keep in mind while writing a commit message
|
||||
|
||||
1. Separate subject from body with a blank line
|
||||
2. Limit the subject line to 50 characters
|
||||
3. Capitalize the subject line
|
||||
4. Do not end the subject line with a period
|
||||
5. Use the imperative mood in the subject line
|
||||
6. Wrap the body at 72 characters
|
||||
7. Use the body to explain what and why vs. how
|
||||
|
||||
A good commit message looks something like this:
|
||||
|
||||
```text
|
||||
Summarize changes in around 50 characters or less
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as the
|
||||
subject of the commit and the rest of the text as the body. The
|
||||
blank line separating the summary from the body is critical (unless
|
||||
you omit the body entirely); various tools like `log`, `shortlog`
|
||||
and `rebase` can get confused if you run the two together.
|
||||
|
||||
Explain the problem that this commit is solving. Focus on why you
|
||||
are making this change as opposed to how (the code explains that).
|
||||
Are there side effects or other unintuitive consequences of this
|
||||
change? Here's the place to explain them.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, preceded
|
||||
by a single space, with blank lines in between, but conventions
|
||||
vary here
|
||||
|
||||
If you use an issue tracker, put references to them at the bottom,
|
||||
like this:
|
||||
|
||||
Resolves: #123
|
||||
See also: #456, #789
|
||||
|
||||
Do not forget to sign your commit! Use `git commit -s`
|
||||
```
|
||||
|
||||
This is taken from [chris beams git commit](https://chris.beams.io/posts/git-commit/).
|
||||
You may want to read this for a more detailed explanation (and links to other posts on
|
||||
how to write a good commit message). This content is licensed under
|
||||
[CC-BY-SA](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
### Sign off your commit
|
||||
|
||||
You need to sign off your commit. By adding your 'Signed-off-by' line to the commit
|
||||
messages you adhere to the
|
||||
[Developer Certificate of Origin (DCO)](https://developercertificate.org/).
|
||||
|
||||
Use the `-s` command-line option to append the `Signed-off-by` line when committing your
|
||||
code:
|
||||
|
||||
`$ git commit -s`
|
||||
|
||||
This is the full text of the Developer Certificate of Origin:
|
||||
|
||||
```text
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
|
||||
1 Letterman Drive
|
||||
Suite D4700
|
||||
San Francisco, CA, 94129
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies of this
|
||||
license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
||||
### Debugging
|
||||
|
||||
When using the `nm` provider, NetworkManager create a checkpoint and reverts the changes
|
||||
on failures. This makes it hard to debug the error. To disable this, set the Ansible
|
||||
variable `__network_debug_flags` to include the value `disable-checkpoints`. Also tests
|
||||
clean up by default in case there are failures. They should be tagged as
|
||||
`tests::cleanup` and can be skipped. To use both, run the test playbooks like this:
|
||||
|
||||
```bash
|
||||
ansible-playbook --skip-tags tests::cleanup \
|
||||
-e "__network_debug_flags=disable-checkpoints" \
|
||||
-i testhost, tests/playbooks/tests_802_1x.yml
|
||||
```
|
||||
|
||||
### NetworkManager Documentation
|
||||
|
||||
- [NM 1.0](https://lazka.github.io/pgi-docs/#NM-1.0), it contains a full explanation
|
||||
about the NetworkManager API.
|
||||
|
||||
### Integration tests with podman
|
||||
|
||||
1. Create `~/.ansible/collections/ansible_collections/containers/podman/` if this
|
||||
directory does not exist and `cd` into this directory.
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.ansible/collections/ansible_collections/containers/podman/
|
||||
cd ~/.ansible/collections/ansible_collections/containers/podman/
|
||||
```
|
||||
|
||||
2. Clone the collection plugins for Ansible-Podman into the current directory.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/containers/ansible-podman-collections.git .
|
||||
```
|
||||
|
||||
3. Change directory into the `tests` subdirectory.
|
||||
|
||||
```bash
|
||||
cd ~/network/tests
|
||||
```
|
||||
|
||||
4. Use podman with `-d` to run in the background (daemon). Use `c7` because
|
||||
`centos/systemd` is centos7.
|
||||
|
||||
```bash
|
||||
podman run --name lsr-ci-c7 --rm --privileged -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
|
||||
-d registry.centos.org/centos/systemd
|
||||
```
|
||||
|
||||
5. Use `podman unshare` first to run "podman mount" in root mode, use `-vi` to run
|
||||
ansible as inventory in verbose mode, use `-c podman` to use collection plugins. Note,
|
||||
the following tests are currently not working with podman:
|
||||
- `tests_802_1x_nm.yml`
|
||||
- `tests_802_1x_updated_nm.yml`
|
||||
- `tests_bond_initscripts.yml`
|
||||
- `tests_bond_nm.yml`
|
||||
- `tests_bridge_initscripts.yml`
|
||||
- `tests_bridge_nm.yml`
|
||||
- `tests_default_nm.yml`
|
||||
- `tests_ethernet_nm.yml`
|
||||
- `tests_reapply_nm.yml`
|
||||
- `tests_states_nm.yml`
|
||||
- `tests_vlan_mtu_initscripts.yml`
|
||||
- `tests_vlan_mtu_nm.yml`
|
||||
- `tests_wireless_nm.yml`
|
||||
|
||||
```bash
|
||||
podman unshare
|
||||
ansible-playbook -vi lsr-ci-c7, -c podman tests_provider_nm.yml
|
||||
```
|
||||
|
||||
6. NOTE that this leaves the container running in the background, to kill it:
|
||||
|
||||
```bash
|
||||
podman stop lsr-ci-c7
|
||||
podman rm lsr-ci-c7
|
||||
```
|
||||
|
||||
### Continuous integration
|
||||
|
||||
The [continuous integration](https://en.wikipedia.org/wiki/Continuous_integration) (CI)
|
||||
contains a set of automated tests that are triggered on a remote server. Some of them
|
||||
are immediately triggered when pushing new content to a PR (i.e. the tests hosted on
|
||||
TravisCI) while other need to be triggered by members of the project. This second
|
||||
set of tests can be manually triggered. To trigger them, write a command as a PR
|
||||
comment. The available commands are:
|
||||
|
||||
- [citest] - Trigger a re-test for all machines.
|
||||
- [citest bad] - Trigger a re-test for all machines with an error or failure status.
|
||||
- [citest pending] - Trigger a re-test for all machines with a pending status.
|
||||
- [citest commit:<sha1\>] - Whitelist a commit to be tested if the submitter is not
|
||||
trusted.
|
||||
|
||||
How to reach us
|
||||
---------------
|
||||
|
||||
The mailing list for developers: systemroles@lists.fedorahosted.org
|
||||
|
||||
[Subscribe to the mailing list](https://lists.fedorahosted.org/admin/lists/systemroles.lists.fedorahosted.org/)
|
||||
|
||||
[Archive of the mailing list](https://lists.fedorahosted.org/archives/list/systemroles@lists.fedorahosted.org/)
|
||||
|
||||
If you are using IRC, join the `#systemroles` IRC channel on
|
||||
[freenode](https://freenode.net/kb/answer/chat)
|
||||
|
||||
*Thanks for contributing and happy coding!!*
|
||||
4
roles/linux-system-roles.network/custom_requirements.txt
Normal file
4
roles/linux-system-roles.network/custom_requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Write requirements for running your custom commands in tox here:
|
||||
PyYAML; python_version == '2.7' or python_version >= '3.5'
|
||||
36
roles/linux-system-roles.network/examples/bond_simple.yml
Normal file
36
roles/linux-system-roles.network/examples/bond_simple.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: network-test
|
||||
vars:
|
||||
network_connections:
|
||||
# Specify the bond profile
|
||||
- name: bond0
|
||||
state: up
|
||||
type: bond
|
||||
interface_name: bond0
|
||||
# ip configuration (optional)
|
||||
ip:
|
||||
address:
|
||||
- "192.0.2.24/24"
|
||||
- "2001:db8::23/64"
|
||||
# bond configuration settings: (optional)
|
||||
bond:
|
||||
mode: active-backup
|
||||
miimon: 110
|
||||
|
||||
# add an ethernet profile to the bond
|
||||
- name: member1
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: eth1
|
||||
controller: bond0
|
||||
|
||||
# add a second ethernet profile to the bond
|
||||
- name: member2
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: eth2
|
||||
controller: bond0
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
...
|
||||
38
roles/linux-system-roles.network/examples/bond_with_vlan.yml
Normal file
38
roles/linux-system-roles.network/examples/bond_with_vlan.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: network-test
|
||||
vars:
|
||||
network_connections:
|
||||
|
||||
# Create a bond profile, which is the parent of VLAN.
|
||||
- name: prod2
|
||||
state: up
|
||||
type: bond
|
||||
interface_name: bond2
|
||||
ip:
|
||||
dhcp4: no
|
||||
auto6: no
|
||||
bond:
|
||||
mode: active-backup
|
||||
miimon: 110
|
||||
|
||||
# set an ethernet as port to the bond
|
||||
- name: prod2-port1
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: "{{ network_interface_name2 }}"
|
||||
controller: prod2
|
||||
|
||||
# on top of it, create a VLAN with ID 100 and static
|
||||
# addressing
|
||||
- name: prod2.100
|
||||
state: up
|
||||
type: vlan
|
||||
parent: prod2
|
||||
vlan_id: 100
|
||||
ip:
|
||||
address:
|
||||
- "192.0.2.{{ network_iphost }}/24"
|
||||
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
@@ -0,0 +1,36 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: network-test
|
||||
vars:
|
||||
network_connections:
|
||||
|
||||
# Create a bridge profile, which is the parent of VLAN.
|
||||
- name: prod2
|
||||
state: up
|
||||
type: bridge
|
||||
interface_name: bridge2
|
||||
ip:
|
||||
dhcp4: no
|
||||
auto6: no
|
||||
|
||||
# set an ethernet port to the bridge
|
||||
- name: prod2-port1
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: "{{ network_interface_name2 }}"
|
||||
controller: prod2
|
||||
port_type: bridge
|
||||
|
||||
# on top of it, create a VLAN with ID 100 and static
|
||||
# addressing
|
||||
- name: prod2.100
|
||||
state: up
|
||||
type: vlan
|
||||
parent: prod2
|
||||
vlan_id: 100
|
||||
ip:
|
||||
address:
|
||||
- "192.0.2.{{ network_iphost }}/24"
|
||||
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
1
roles/linux-system-roles.network/examples/down_profile.yml
Symbolic link
1
roles/linux-system-roles.network/examples/down_profile.yml
Symbolic link
@@ -0,0 +1 @@
|
||||
../tests/playbooks/down_profile.yml
|
||||
17
roles/linux-system-roles.network/examples/dummy_simple.yml
Normal file
17
roles/linux-system-roles.network/examples/dummy_simple.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
network_connections:
|
||||
# Specify the dummy profile
|
||||
- name: dummy0
|
||||
state: up
|
||||
type: dummy
|
||||
interface_name: dummy0
|
||||
ip:
|
||||
address:
|
||||
- "192.0.2.42/30"
|
||||
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
...
|
||||
@@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
network_connections:
|
||||
- name: eth0
|
||||
type: ethernet
|
||||
ip:
|
||||
route_metric4: 100
|
||||
dhcp4: no
|
||||
gateway4: 192.0.2.1
|
||||
dns:
|
||||
- 192.0.2.2
|
||||
- 198.51.100.5
|
||||
dns_search:
|
||||
- example.com
|
||||
- subdomain.example.com
|
||||
dns_options:
|
||||
- rotate
|
||||
- timeout:1
|
||||
|
||||
route_metric6: -1
|
||||
auto6: no
|
||||
gateway6: 2001:db8::1
|
||||
|
||||
address:
|
||||
- 192.0.2.3/24
|
||||
- 198.51.100.3/26
|
||||
- 2001:db8::80/7
|
||||
|
||||
route:
|
||||
- network: 198.51.100.128
|
||||
prefix: 26
|
||||
gateway: 198.51.100.1
|
||||
metric: 2
|
||||
- network: 198.51.100.64
|
||||
prefix: 26
|
||||
gateway: 198.51.100.6
|
||||
metric: 4
|
||||
route_append_only: no
|
||||
rule_append_only: yes
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
...
|
||||
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: network-test
|
||||
vars:
|
||||
network_connections:
|
||||
|
||||
# Create one ethernet profile and activate it.
|
||||
# The profile uses automatic IP addressing
|
||||
# and is tied to the interface by MAC address.
|
||||
- name: prod1
|
||||
state: up
|
||||
type: ethernet
|
||||
autoconnect: yes
|
||||
mac: "{{ network_mac1 }}"
|
||||
mtu: 1450
|
||||
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
@@ -0,0 +1,30 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: network-test
|
||||
vars:
|
||||
network_connections:
|
||||
- name: eth0
|
||||
type: ethernet
|
||||
ieee802_1x:
|
||||
identity: myhost
|
||||
eap: tls
|
||||
private_key: /etc/pki/tls/client.key
|
||||
# recommend vault encrypting the private key password
|
||||
# see https://docs.ansible.com/ansible/latest/user_guide/vault.html
|
||||
private_key_password: "p@55w0rD"
|
||||
client_cert: /etc/pki/tls/client.pem
|
||||
ca_cert: /etc/pki/tls/cacert.pem
|
||||
domain_suffix_match: example.com
|
||||
|
||||
# certs have to be deployed first
|
||||
pre_tasks:
|
||||
- name: copy certs/keys for 802.1x auth
|
||||
copy:
|
||||
src: "{{ item }}"
|
||||
dest: "/etc/pki/tls/{{ item }}"
|
||||
with_items:
|
||||
- client.key
|
||||
- client.pem
|
||||
- cacert.pem
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
29
roles/linux-system-roles.network/examples/eth_with_vlan.yml
Normal file
29
roles/linux-system-roles.network/examples/eth_with_vlan.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: network-test
|
||||
vars:
|
||||
network_connections:
|
||||
|
||||
# Create a profile for the underlying device of the VLAN.
|
||||
- name: prod2
|
||||
type: ethernet
|
||||
autoconnect: no
|
||||
state: up
|
||||
interface_name: "{{ network_interface_name2 }}"
|
||||
ip:
|
||||
dhcp4: no
|
||||
auto6: no
|
||||
|
||||
# on top of it, create a VLAN with ID 100 and static
|
||||
# addressing
|
||||
- name: prod2.100
|
||||
state: up
|
||||
type: vlan
|
||||
parent: prod2
|
||||
vlan_id: 100
|
||||
ip:
|
||||
address:
|
||||
- "192.0.2.{{ network_iphost }}/24"
|
||||
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
@@ -0,0 +1,38 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ network_interface_name1 }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
ip:
|
||||
dhcp4: no
|
||||
auto6: no
|
||||
ethtool:
|
||||
coalesce:
|
||||
adaptive_rx: yes
|
||||
adaptive_tx: no
|
||||
pkt_rate_high: 128
|
||||
pkt_rate_low: 128
|
||||
rx_frames: 128
|
||||
rx_frames_high: 128
|
||||
rx_frames_irq: 128
|
||||
rx_frames_low: 128
|
||||
rx_usecs: 128
|
||||
rx_usecs_high: 128
|
||||
rx_usecs_irq: 128
|
||||
rx_usecs_low: 128
|
||||
sample_interval: 128
|
||||
stats_block_usecs: 128
|
||||
tx_frames: 128
|
||||
tx_frames_high: 128
|
||||
tx_frames_irq: 128
|
||||
tx_frames_low: 128
|
||||
tx_usecs: 128
|
||||
tx_usecs_high: 128
|
||||
tx_usecs_irq: 128
|
||||
tx_usecs_low: 128
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ network_interface_name1 }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
ip:
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
ethtool:
|
||||
features:
|
||||
gro: "no"
|
||||
gso: "yes"
|
||||
tx_sctp_segmentation: "no"
|
||||
@@ -0,0 +1,14 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ network_interface_name1 }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
ip:
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
12
roles/linux-system-roles.network/examples/ipv6_disabled.yml
Normal file
12
roles/linux-system-roles.network/examples/ipv6_disabled.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
network_connections:
|
||||
- name: eth0
|
||||
type: ethernet
|
||||
ip:
|
||||
ipv6_disabled: true
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
...
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Set {{ profile }} down
|
||||
hosts: all
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ profile }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
...
|
||||
1
roles/linux-system-roles.network/examples/remove_profile.yml
Symbolic link
1
roles/linux-system-roles.network/examples/remove_profile.yml
Symbolic link
@@ -0,0 +1 @@
|
||||
../tests/playbooks/remove_profile.yml
|
||||
33
roles/linux-system-roles.network/examples/team_simple.yml
Normal file
33
roles/linux-system-roles.network/examples/team_simple.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: network-test
|
||||
vars:
|
||||
network_connections:
|
||||
# Specify the team profile
|
||||
- name: team0
|
||||
state: up
|
||||
type: team
|
||||
interface_name: team0
|
||||
# ip configuration (optional)
|
||||
ip:
|
||||
address:
|
||||
- "192.0.2.24/24"
|
||||
- "2001:db8::23/64"
|
||||
|
||||
# add an team profile to the team
|
||||
- name: member1
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: eth1
|
||||
controller: team0
|
||||
|
||||
# add a second team profile to the team
|
||||
- name: member2
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: eth2
|
||||
controller: team0
|
||||
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
...
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: network-test
|
||||
vars:
|
||||
network_connections:
|
||||
- name: wlan0
|
||||
type: wireless
|
||||
wireless:
|
||||
ssid: "My WPA2-PSK Network"
|
||||
key_mgmt: "wpa-psk"
|
||||
# recommend vault encrypting the wireless password
|
||||
# see https://docs.ansible.com/ansible/latest/user_guide/vault.html
|
||||
password: "p@55w0rD"
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
@@ -1,2 +1,2 @@
|
||||
install_date: Tue Apr 20 16:13:56 2021
|
||||
install_date: Wed Apr 21 16:48:45 2021
|
||||
version: 1.3.0
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import array
|
||||
import struct
|
||||
import fcntl
|
||||
import socket
|
||||
|
||||
from .utils import Util
|
||||
|
||||
ETHTOOL_GPERMADDR = 0x00000020
|
||||
SIOCETHTOOL = 0x8946
|
||||
MAX_ADDR_LEN = 32
|
||||
IFNAMESIZ = 16
|
||||
|
||||
|
||||
def get_perm_addr(ifname):
|
||||
"""
|
||||
Return the Permanent address value for the specified interface using the
|
||||
ETHTOOL_GPERMADDR ioctl command.
|
||||
|
||||
Please for further documentation, see:
|
||||
https://github.com/torvalds/linux/blob/master/include/uapi/linux/ethtool.h#L734
|
||||
https://github.com/torvalds/linux/blob/master/include/uapi/linux/ethtool.h#L1388
|
||||
https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/tree/ethtool.c#n4172
|
||||
"""
|
||||
try:
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sockfd = sock.fileno()
|
||||
ifname = ifname.encode("utf-8")
|
||||
if len(ifname) > IFNAMESIZ:
|
||||
return None
|
||||
|
||||
ecmd = array.array(
|
||||
"B",
|
||||
struct.pack(
|
||||
"II%is" % MAX_ADDR_LEN,
|
||||
ETHTOOL_GPERMADDR,
|
||||
MAX_ADDR_LEN,
|
||||
b"\x00" * MAX_ADDR_LEN,
|
||||
),
|
||||
)
|
||||
ifreq = struct.pack("%isP" % IFNAMESIZ, ifname, ecmd.buffer_info()[0])
|
||||
|
||||
fcntl.ioctl(sockfd, SIOCETHTOOL, ifreq)
|
||||
try:
|
||||
res = ecmd.tobytes()
|
||||
except AttributeError: # tobytes() is not available in python2
|
||||
res = ecmd.tostring()
|
||||
_, size, perm_addr = struct.unpack("II%is" % MAX_ADDR_LEN, res)
|
||||
perm_addr = Util.mac_ntoa(perm_addr[:size])
|
||||
except IOError:
|
||||
perm_addr = None
|
||||
finally:
|
||||
sock.close()
|
||||
|
||||
return perm_addr
|
||||
@@ -0,0 +1,7 @@
|
||||
# Relative import is not support by ansible 2.8 yet
|
||||
# pylint: disable=import-error, no-name-in-module
|
||||
from ansible.module_utils.network_lsr.nm import provider # noqa:E501
|
||||
|
||||
# pylint: enable=import-error, no-name-in-module
|
||||
|
||||
provider.NetworkManagerProvider
|
||||
@@ -0,0 +1,128 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Handle NM.ActiveConnection
|
||||
|
||||
import logging
|
||||
|
||||
# Relative import is not support by ansible 2.8 yet
|
||||
# pylint: disable=import-error, no-name-in-module
|
||||
from ansible.module_utils.network_lsr.nm import client # noqa:E501
|
||||
from ansible.module_utils.network_lsr.nm import error # noqa:E501
|
||||
|
||||
# pylint: enable=import-error, no-name-in-module
|
||||
|
||||
|
||||
NM_AC_STATE_CHANGED_SIGNAL = "state-changed"
|
||||
|
||||
|
||||
def deactivate_active_connection(nm_ac, timeout, check_mode):
|
||||
if not nm_ac or nm_ac.props.state == client.NM.ActiveConnectionState.DEACTIVATED:
|
||||
logging.info("Connection is not active, no need to deactivate")
|
||||
return False
|
||||
if not check_mode:
|
||||
main_loop = client.get_mainloop(timeout)
|
||||
logging.debug(
|
||||
"Deactivating {id} with timeout {timeout}".format(
|
||||
id=nm_ac.get_id(), timeout=timeout
|
||||
)
|
||||
)
|
||||
user_data = main_loop
|
||||
handler_id = nm_ac.connect(
|
||||
NM_AC_STATE_CHANGED_SIGNAL, _nm_ac_state_change_callback, user_data
|
||||
)
|
||||
logging.debug(
|
||||
"Registered {signal} on client.NM.ActiveConnection {id}".format(
|
||||
signal=NM_AC_STATE_CHANGED_SIGNAL, id=nm_ac.get_id()
|
||||
)
|
||||
)
|
||||
if nm_ac.props.state != client.NM.ActiveConnectionState.DEACTIVATING:
|
||||
nm_client = client.get_client()
|
||||
user_data = (main_loop, nm_ac, nm_ac.get_id(), handler_id)
|
||||
nm_client.deactivate_connection_async(
|
||||
nm_ac,
|
||||
main_loop.cancellable,
|
||||
_nm_ac_deactivate_call_back,
|
||||
user_data,
|
||||
)
|
||||
logging.debug(
|
||||
"Deactivating client.NM.ActiveConnection {0}".format(nm_ac.get_id())
|
||||
)
|
||||
main_loop.run()
|
||||
return True
|
||||
|
||||
|
||||
def _nm_ac_state_change_callback(nm_ac, state, reason, user_data):
|
||||
main_loop = user_data
|
||||
if main_loop.is_cancelled:
|
||||
return
|
||||
logging.debug(
|
||||
"Got client.NM.ActiveConnection state change: {id}: {state} {reason}".format(
|
||||
id=nm_ac.get_id(), state=state, reason=reason
|
||||
)
|
||||
)
|
||||
if nm_ac.props.state == client.NM.ActiveConnectionState.DEACTIVATED:
|
||||
logging.debug(
|
||||
"client.NM.ActiveConnection {0} is deactivated".format(nm_ac.get_id())
|
||||
)
|
||||
main_loop.quit()
|
||||
|
||||
|
||||
def _nm_ac_deactivate_call_back(nm_client, result, user_data):
|
||||
main_loop, nm_ac, nm_ac_id, handler_id = user_data
|
||||
logging.debug("client.NM.ActiveConnection deactivating callback")
|
||||
if main_loop.is_cancelled:
|
||||
if nm_ac:
|
||||
nm_ac.handler_disconnect(handler_id)
|
||||
return
|
||||
|
||||
try:
|
||||
success = nm_client.deactivate_connection_finish(result)
|
||||
except client.GLib.Error as e:
|
||||
if e.matches(
|
||||
client.NM.ManagerError.quark(), client.NM.ManagerError.CONNECTIONNOTACTIVE
|
||||
):
|
||||
logging.info(
|
||||
"Connection is not active on {0}, no need to deactivate".format(
|
||||
nm_ac_id
|
||||
)
|
||||
)
|
||||
if nm_ac:
|
||||
nm_ac.handler_disconnect(handler_id)
|
||||
main_loop.quit()
|
||||
return
|
||||
else:
|
||||
_deactivate_fail(
|
||||
main_loop,
|
||||
handler_id,
|
||||
nm_ac,
|
||||
"Failed to deactivate connection {id}, error={error}".format(
|
||||
id=nm_ac_id, error=e
|
||||
),
|
||||
)
|
||||
return
|
||||
except Exception as e:
|
||||
_deactivate_fail(
|
||||
main_loop,
|
||||
handler_id,
|
||||
nm_ac,
|
||||
"Failed to deactivate connection {id}, error={error}".format(
|
||||
id=nm_ac_id, error=e
|
||||
),
|
||||
)
|
||||
return
|
||||
|
||||
if not success:
|
||||
_deactivate_fail(
|
||||
main_loop,
|
||||
handler_id,
|
||||
nm_ac,
|
||||
"Failed to deactivate connection {0}, error='None "
|
||||
"returned from deactivate_connection_finish()'".format(nm_ac_id),
|
||||
)
|
||||
|
||||
|
||||
def _deactivate_fail(main_loop, handler_id, nm_ac, msg):
|
||||
if nm_ac:
|
||||
nm_ac.handler_disconnect(handler_id)
|
||||
logging.error(msg)
|
||||
main_loop.fail(error.LsrNetworkNmError(msg))
|
||||
@@ -0,0 +1,96 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import logging
|
||||
|
||||
# Relative import is not support by ansible 2.8 yet
|
||||
# pylint: disable=import-error, no-name-in-module
|
||||
from ansible.module_utils.network_lsr.nm import error # noqa:E501
|
||||
|
||||
import gi
|
||||
|
||||
try:
|
||||
gi.require_version("NM", "1.0")
|
||||
|
||||
# It is required to state the NM version before importing it
|
||||
# But this break the flake8 rule: https://www.flake8rules.com/rules/E402.html
|
||||
# Use NOQA: E402 to suppress it.
|
||||
from gi.repository import NM # NOQA: E402
|
||||
from gi.repository import GLib # NOQA: E402
|
||||
from gi.repository import Gio # NOQA: E402
|
||||
|
||||
# pylint: enable=import-error, no-name-in-module
|
||||
|
||||
NM
|
||||
GLib
|
||||
Gio
|
||||
except ValueError:
|
||||
# This is to workaround a bug in ansible 2.9 which causes
|
||||
# this code to be executed on the control node, where NM
|
||||
# is not guaranteed to exist. On the other hand, it is
|
||||
# ensured on the managed nodes as NM package is installed
|
||||
# in the network role. Therefore, this exception handling
|
||||
# does not affect the network installation and configuration
|
||||
# on the managed nodes.
|
||||
pass
|
||||
|
||||
|
||||
def get_client():
|
||||
return NM.Client.new()
|
||||
|
||||
|
||||
class _NmMainLoop(object):
|
||||
def __init__(self, timeout):
|
||||
self._mainloop = GLib.MainLoop()
|
||||
self._cancellable = Gio.Cancellable.new()
|
||||
self._timeout = timeout
|
||||
self._timeout_id = None
|
||||
|
||||
def run(self):
|
||||
logging.debug("NM mainloop running")
|
||||
user_data = None
|
||||
self._timeout_id = GLib.timeout_add(
|
||||
int(self._timeout * 1000),
|
||||
self._timeout_call_back,
|
||||
user_data,
|
||||
)
|
||||
logging.debug("Added timeout checker")
|
||||
self._mainloop.run()
|
||||
|
||||
def _timeout_call_back(self, _user_data):
|
||||
logging.error("Timeout")
|
||||
self.fail(error.LsrNetworkNmError("Timeout"))
|
||||
|
||||
@property
|
||||
def cancellable(self):
|
||||
return self._cancellable
|
||||
|
||||
@property
|
||||
def is_cancelled(self):
|
||||
if self._cancellable:
|
||||
return self._cancellable.is_cancelled()
|
||||
return True
|
||||
|
||||
def _clean_up(self):
|
||||
logging.debug("NM mainloop cleaning up")
|
||||
if self._timeout_id:
|
||||
logging.debug("Removing timeout checker")
|
||||
GLib.source_remove(self._timeout_id)
|
||||
self._timeout_id = None
|
||||
if self._cancellable:
|
||||
logging.debug("Canceling all pending tasks")
|
||||
self._cancellable.cancel()
|
||||
self._cancellable = None
|
||||
self._mainloop = None
|
||||
|
||||
def quit(self):
|
||||
logging.debug("NM mainloop quiting")
|
||||
self._mainloop.quit()
|
||||
self._clean_up()
|
||||
|
||||
def fail(self, exception):
|
||||
self.quit()
|
||||
raise exception
|
||||
|
||||
|
||||
def get_mainloop(timeout):
|
||||
return _NmMainLoop(timeout)
|
||||
@@ -0,0 +1,113 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# Handle NM.RemoteConnection
|
||||
|
||||
import logging
|
||||
|
||||
# Relative import is not support by ansible 2.8 yet
|
||||
# pylint: disable=import-error, no-name-in-module
|
||||
from ansible.module_utils.network_lsr.nm import client # noqa:E501
|
||||
from ansible.module_utils.network_lsr.nm import error # noqa:E501
|
||||
|
||||
# pylint: enable=import-error, no-name-in-module
|
||||
|
||||
|
||||
def delete_remote_connection(nm_profile, timeout, check_mode):
|
||||
if not nm_profile:
|
||||
logging.info("NULL NM.RemoteConnection, no need to delete")
|
||||
return False
|
||||
|
||||
if not check_mode:
|
||||
main_loop = client.get_mainloop(timeout)
|
||||
user_data = main_loop
|
||||
nm_profile.delete_async(
|
||||
main_loop.cancellable,
|
||||
_nm_profile_delete_call_back,
|
||||
user_data,
|
||||
)
|
||||
logging.debug(
|
||||
"Deleting profile {id}/{uuid} with timeout {timeout}".format(
|
||||
id=nm_profile.get_id(), uuid=nm_profile.get_uuid(), timeout=timeout
|
||||
)
|
||||
)
|
||||
main_loop.run()
|
||||
return True
|
||||
|
||||
|
||||
def _nm_profile_delete_call_back(nm_profile, result, user_data):
|
||||
main_loop = user_data
|
||||
if main_loop.is_cancelled:
|
||||
return
|
||||
|
||||
try:
|
||||
success = nm_profile.delete_finish(result)
|
||||
except Exception as e:
|
||||
main_loop.fail(
|
||||
error.LsrNetworkNmError(
|
||||
"Connection deletion aborted on {id}/{uuid}: error={error}".format(
|
||||
id=nm_profile.get_id(), uuid=nm_profile.get_uuid(), error=e
|
||||
)
|
||||
)
|
||||
)
|
||||
if success:
|
||||
main_loop.quit()
|
||||
else:
|
||||
main_loop.fail(
|
||||
error.LsrNetworkNmError(
|
||||
"Connection deletion aborted on {id}/{uuid}: error=unknown".format(
|
||||
id=nm_profile.get_id(), uuid=nm_profile.get_uuid()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def volatilize_remote_connection(nm_profile, timeout, check_mode):
|
||||
if not nm_profile:
|
||||
logging.info("NULL NM.RemoteConnection, no need to volatilize")
|
||||
return False
|
||||
if not check_mode:
|
||||
main_loop = client.get_mainloop(timeout)
|
||||
user_data = main_loop
|
||||
nm_profile.update2(
|
||||
None, # settings
|
||||
client.NM.SettingsUpdate2Flags.IN_MEMORY_ONLY
|
||||
| client.NM.SettingsUpdate2Flags.VOLATILE,
|
||||
None, # args
|
||||
main_loop.cancellable,
|
||||
_nm_profile_volatile_update2_call_back,
|
||||
user_data,
|
||||
)
|
||||
logging.debug(
|
||||
"Volatilizing profile {id}/{uuid} with timeout {timeout}".format(
|
||||
id=nm_profile.get_id(), uuid=nm_profile.get_uuid(), timeout=timeout
|
||||
)
|
||||
)
|
||||
main_loop.run()
|
||||
return True
|
||||
|
||||
|
||||
def _nm_profile_volatile_update2_call_back(nm_profile, result, user_data):
|
||||
main_loop = user_data
|
||||
if main_loop.is_cancelled:
|
||||
return
|
||||
|
||||
try:
|
||||
success = nm_profile.update2_finish(result)
|
||||
except Exception as e:
|
||||
main_loop.fail(
|
||||
error.LsrNetworkNmError(
|
||||
"Connection volatilize aborted on {id}/{uuid}: error={error}".format(
|
||||
id=nm_profile.get_id(), uuid=nm_profile.get_uuid(), error=e
|
||||
)
|
||||
)
|
||||
)
|
||||
if success:
|
||||
main_loop.quit()
|
||||
else:
|
||||
main_loop.fail(
|
||||
error.LsrNetworkNmError(
|
||||
"Connection volatilize aborted on {id}/{uuid}: error=unknown".format(
|
||||
id=nm_profile.get_id(), uuid=nm_profile.get_uuid()
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
|
||||
class LsrNetworkNmError(Exception):
|
||||
pass
|
||||
@@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
import logging
|
||||
|
||||
# Relative import is not support by ansible 2.8 yet
|
||||
# pylint: disable=import-error, no-name-in-module
|
||||
from ansible.module_utils.network_lsr.nm import active_connection # noqa:E501
|
||||
from ansible.module_utils.network_lsr.nm import client # noqa:E501
|
||||
from ansible.module_utils.network_lsr.nm import connection # noqa:E501
|
||||
|
||||
# pylint: enable=import-error, no-name-in-module
|
||||
|
||||
|
||||
class NetworkManagerProvider:
|
||||
def deactivate_connection(self, connection_name, timeout, check_mode):
|
||||
"""
|
||||
Return True if changed.
|
||||
"""
|
||||
nm_client = client.get_client()
|
||||
changed = False
|
||||
for nm_ac in nm_client.get_active_connections():
|
||||
nm_profile = nm_ac.get_connection()
|
||||
if nm_profile and nm_profile.get_id() == connection_name:
|
||||
changed |= active_connection.deactivate_active_connection(
|
||||
nm_ac, timeout, check_mode
|
||||
)
|
||||
if not changed:
|
||||
logging.info("No active connection for {0}".format(connection_name))
|
||||
|
||||
return changed
|
||||
|
||||
def volatilize_connection_by_uuid(self, uuid, timeout, check_mode):
|
||||
"""
|
||||
Mark NM.RemoteConnection as volatile(delete on deactivation) via Update2,
|
||||
if not supported, delete the profile.
|
||||
|
||||
Return True if changed.
|
||||
"""
|
||||
nm_client = client.get_client()
|
||||
changed = False
|
||||
for nm_profile in nm_client.get_connections():
|
||||
if nm_profile and nm_profile.get_uuid() == uuid:
|
||||
if hasattr(nm_profile, "update2"):
|
||||
changed |= connection.volatilize_remote_connection(
|
||||
nm_profile, timeout, check_mode
|
||||
)
|
||||
else:
|
||||
changed |= connection.delete_remote_connection(
|
||||
nm_profile, timeout, check_mode
|
||||
)
|
||||
if not changed:
|
||||
logging.info("No connection with UUID {0} to volatilize".format(uuid))
|
||||
|
||||
return changed
|
||||
|
||||
def get_connections(self):
|
||||
nm_client = client.get_client()
|
||||
return nm_client.get_connections()
|
||||
@@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Write extra requirements for running molecule here:
|
||||
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Write extra requirements for running pylint here:
|
||||
mock
|
||||
pytest
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Write extra requirements for running pytest here:
|
||||
# If you need ansible then uncomment the following line:
|
||||
#-ransible_pytest_extra_requirements.txt
|
||||
# If you need mock then uncomment the following line:
|
||||
mock ; python_version < "3.0"
|
||||
# ansible and dependencies for all supported platforms
|
||||
ansible ; python_version > "2.6"
|
||||
ansible<2.7 ; python_version < "2.7"
|
||||
idna<2.8 ; python_version < "2.7"
|
||||
PyYAML<5.1 ; python_version < "2.7"
|
||||
184
roles/linux-system-roles.network/scripts/print_all_options.py
Executable file
184
roles/linux-system-roles.network/scripts/print_all_options.py
Executable file
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/python3 -tt
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Helper to print all options that the module in the network role accepts for
|
||||
# profiles
|
||||
|
||||
from collections.abc import Mapping
|
||||
from collections.abc import Sequence
|
||||
from copy import deepcopy
|
||||
from unittest import mock
|
||||
import os
|
||||
import sys
|
||||
|
||||
PRIORITIES = (
|
||||
"name",
|
||||
"type",
|
||||
"interface_name",
|
||||
"mac",
|
||||
"state",
|
||||
"persistent_state",
|
||||
"controller",
|
||||
"port_type",
|
||||
"parent",
|
||||
"ignore_errors",
|
||||
"force_state_change",
|
||||
"check_iface_exists",
|
||||
"autoconnect",
|
||||
"wait",
|
||||
"zone",
|
||||
"mtu",
|
||||
"ip",
|
||||
"ethernet",
|
||||
"ethtool",
|
||||
"bridge",
|
||||
"bond",
|
||||
"team",
|
||||
"vlan",
|
||||
"wireless",
|
||||
"macvlan",
|
||||
"infiniband",
|
||||
)
|
||||
|
||||
|
||||
import yaml
|
||||
|
||||
parentdir = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
with mock.patch.object(
|
||||
sys,
|
||||
"path",
|
||||
[parentdir, os.path.join(parentdir, "module_utils/network_lsr")] + sys.path,
|
||||
):
|
||||
with mock.patch.dict(
|
||||
"sys.modules",
|
||||
{"ansible": mock.Mock(), "ansible.module_utils": __import__("module_utils")},
|
||||
):
|
||||
import argument_validator as av
|
||||
|
||||
COMMENT = "@@"
|
||||
EMPTY = "/EMPTY/"
|
||||
|
||||
|
||||
def parse_validator(validator):
|
||||
default = validator.default_value
|
||||
if isinstance(validator, av.ArgValidatorDict):
|
||||
res = {}
|
||||
for k, v in validator.nested.items():
|
||||
if (
|
||||
v.name
|
||||
not in (
|
||||
"infiniband_transport_mode",
|
||||
"infiniband_p_key",
|
||||
"vlan_id",
|
||||
)
|
||||
and not isinstance(v, av.ArgValidatorDeprecated)
|
||||
):
|
||||
name = k
|
||||
if not validator.required:
|
||||
pass
|
||||
# name += " DICT optional"
|
||||
res[name] = parse_validator(v)
|
||||
elif isinstance(validator, av.ArgValidatorList):
|
||||
res = [parse_validator(validator.nested)]
|
||||
elif isinstance(validator, av.ArgValidatorNum):
|
||||
|
||||
minval = validator.val_min
|
||||
maxval = validator.val_max
|
||||
comment = f" {COMMENT}"
|
||||
if not validator.required:
|
||||
comment += " optional"
|
||||
if minval is not None:
|
||||
comment += " mininum=" + str(minval)
|
||||
if maxval:
|
||||
if maxval == 0xFFFFFFFF:
|
||||
maxval = hex(maxval)
|
||||
comment += " maximum=" + str(maxval)
|
||||
|
||||
if default is not None:
|
||||
res = str(default)
|
||||
elif minval is not None:
|
||||
res = str(minval)
|
||||
elif maxval is not None:
|
||||
res = str(maxval)
|
||||
else:
|
||||
res = ""
|
||||
|
||||
res += comment
|
||||
elif isinstance(validator, av.ArgValidatorIP):
|
||||
res = f"{EMPTY} {COMMENT} IP Address"
|
||||
elif isinstance(validator, av.ArgValidatorStr):
|
||||
if default:
|
||||
res = default
|
||||
elif validator.enum_values:
|
||||
res = "|".join(validator.enum_values)
|
||||
else:
|
||||
res = EMPTY
|
||||
if not validator.required:
|
||||
res += f" {COMMENT} optional"
|
||||
|
||||
# res += " " + str(validator.__class__)
|
||||
elif isinstance(validator, av.ArgValidatorBool):
|
||||
if default is not None:
|
||||
res = "yes" if default else "no"
|
||||
else:
|
||||
res = "yes|no"
|
||||
|
||||
if not validator.required:
|
||||
res += f" {COMMENT} optional"
|
||||
else:
|
||||
res = validator.name + f" {COMMENT} FIXME " + str(validator.__class__)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def represent_dict(dumper, data):
|
||||
"""
|
||||
Represent dictionary with insert order
|
||||
"""
|
||||
value = []
|
||||
|
||||
for item_key, item_value in data.items():
|
||||
node_key = dumper.represent_data(item_key)
|
||||
node_value = dumper.represent_data(item_value)
|
||||
value.append((node_key, node_value))
|
||||
|
||||
return yaml.nodes.MappingNode("tag:yaml.org,2002:map", value)
|
||||
|
||||
|
||||
def priority_sorted(data):
|
||||
if isinstance(data, Sequence) and not isinstance(data, str):
|
||||
return [priority_sorted(item) for item in data]
|
||||
|
||||
if isinstance(data, Mapping):
|
||||
sorted_data = {}
|
||||
for key in sorted(data, key=prioritize):
|
||||
sorted_data[key] = priority_sorted(data[key])
|
||||
return sorted_data
|
||||
|
||||
return deepcopy(data)
|
||||
|
||||
|
||||
def prioritize(key):
|
||||
try:
|
||||
priority = PRIORITIES.index(key)
|
||||
except ValueError:
|
||||
priority = len(PRIORITIES)
|
||||
return (priority, key)
|
||||
|
||||
|
||||
yaml.add_representer(dict, represent_dict)
|
||||
sorted_data = priority_sorted([parse_validator(av.ArgValidator_DictConnection())])
|
||||
yaml_example = (
|
||||
yaml.dump(
|
||||
sorted_data,
|
||||
explicit_start=True,
|
||||
default_flow_style=False,
|
||||
width=100,
|
||||
)
|
||||
.replace(COMMENT, "#")
|
||||
.replace(EMPTY, "")
|
||||
)
|
||||
|
||||
# yaml_example = re.sub(r"# ([^:]*):", r": # \1", yaml_example)
|
||||
|
||||
print(yaml_example)
|
||||
227
roles/linux-system-roles.network/tests/ensure_provider_tests.py
Executable file
227
roles/linux-system-roles.network/tests/ensure_provider_tests.py
Executable file
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
""" Check that there is a playbook to run all role tests with both providers
|
||||
"""
|
||||
# vim: fileencoding=utf8
|
||||
|
||||
import glob
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
GET_NM_VERSION = """
|
||||
- block:
|
||||
- name: Install NetworkManager
|
||||
package:
|
||||
name: NetworkManager
|
||||
state: present
|
||||
- name: Get NetworkManager version
|
||||
command: rpm -q --qf "%{version}" NetworkManager
|
||||
args:
|
||||
warn: false
|
||||
register: NetworkManager_version
|
||||
when: true
|
||||
when:
|
||||
- ansible_distribution_major_version != '6'
|
||||
tags:
|
||||
- always
|
||||
"""
|
||||
|
||||
MINIMUM_NM_VERSION_CHECK = """
|
||||
- NetworkManager_version.stdout is version({minimum_nm_version}, '>=')
|
||||
"""
|
||||
|
||||
EXTRA_RUN_CONDITION_PREFIX = " - "
|
||||
|
||||
RUN_PLAYBOOK_WITH_NM = """# SPDX-License-Identifier: BSD-3-Clause
|
||||
# This file was generated by ensure_provider_tests.py
|
||||
---
|
||||
# set network provider and gather facts
|
||||
- hosts: all
|
||||
name: Run playbook '{test_playbook}' with nm as provider
|
||||
tasks:
|
||||
- name: Set network provider to 'nm'
|
||||
set_fact:
|
||||
network_provider: nm
|
||||
tags:
|
||||
- always
|
||||
{get_nm_version}
|
||||
|
||||
# The test requires or should run with NetworkManager, therefore it cannot run
|
||||
# on RHEL/CentOS 6
|
||||
- import_playbook: {test_playbook}
|
||||
when:
|
||||
- ansible_distribution_major_version != '6'
|
||||
{minimum_nm_version_check}{extra_run_condition}"""
|
||||
|
||||
MINIMUM_VERSION = "minimum_version"
|
||||
EXTRA_RUN_CONDITION = "extra_run_condition"
|
||||
NM_ONLY_TESTS = {
|
||||
"playbooks/tests_802_1x_updated.yml": {},
|
||||
"playbooks/tests_802_1x.yml": {},
|
||||
"playbooks/tests_eth_dns_support.yml": {},
|
||||
"playbooks/tests_dummy.yml": {},
|
||||
"playbooks/tests_ethtool_features.yml": {
|
||||
MINIMUM_VERSION: "'1.20.0'",
|
||||
"comment": "# NetworkManager 1.20.0 introduced ethtool settings support",
|
||||
},
|
||||
"playbooks/tests_ipv6_disabled.yml": {
|
||||
EXTRA_RUN_CONDITION: "ansible_distribution_major_version == '8'",
|
||||
},
|
||||
"playbooks/tests_provider.yml": {
|
||||
MINIMUM_VERSION: "'1.20.0'",
|
||||
"comment": "# NetworKmanager 1.20.0 added support for forgetting profiles",
|
||||
},
|
||||
"playbooks/tests_ethtool_coalesce.yml": {
|
||||
MINIMUM_VERSION: "'1.25.1'",
|
||||
"comment": "# NetworkManager 1.25.1 introduced ethtool coalesce support",
|
||||
},
|
||||
"playbooks/tests_802_1x_updated.yml": {},
|
||||
"playbooks/tests_802_1x.yml": {},
|
||||
"playbooks/tests_reapply.yml": {},
|
||||
# team interface is not supported on Fedora
|
||||
"playbooks/tests_team.yml": {
|
||||
EXTRA_RUN_CONDITION: "ansible_distribution != 'Fedora'",
|
||||
},
|
||||
"playbooks/tests_team_plugin_installation.yml": {},
|
||||
# mac80211_hwsim (used for tests_wireless) only seems to be available
|
||||
# and working on RHEL/CentOS 7
|
||||
"playbooks/tests_wireless.yml": {
|
||||
EXTRA_RUN_CONDITION: "ansible_distribution_major_version == '7'",
|
||||
},
|
||||
"playbooks/tests_wireless_plugin_installation.yml": {},
|
||||
}
|
||||
|
||||
IGNORE = [
|
||||
# checked by tests_regression_nm.yml
|
||||
"playbooks/tests_checkpoint_cleanup.yml",
|
||||
]
|
||||
|
||||
RUN_PLAYBOOK_WITH_INITSCRIPTS = """# SPDX-License-Identifier: BSD-3-Clause
|
||||
# This file was generated by ensure_provider_tests.py
|
||||
---
|
||||
- hosts: all
|
||||
name: Run playbook '{test_playbook}' with initscripts as provider
|
||||
tasks:
|
||||
- name: Set network provider to 'initscripts'
|
||||
set_fact:
|
||||
network_provider: initscripts
|
||||
tags:
|
||||
- always
|
||||
|
||||
- import_playbook: {test_playbook}
|
||||
"""
|
||||
|
||||
|
||||
def create_nm_playbook(test_playbook):
|
||||
fileroot = os.path.splitext(os.path.basename(test_playbook))[0]
|
||||
nm_testfile = fileroot + "_nm.yml"
|
||||
|
||||
minimum_nm_version = NM_ONLY_TESTS.get(test_playbook, {}).get(MINIMUM_VERSION)
|
||||
extra_run_condition = NM_ONLY_TESTS.get(test_playbook, {}).get(
|
||||
EXTRA_RUN_CONDITION, ""
|
||||
)
|
||||
if extra_run_condition:
|
||||
extra_run_condition = "{}{}\n".format(
|
||||
EXTRA_RUN_CONDITION_PREFIX, extra_run_condition
|
||||
)
|
||||
|
||||
nm_version_check = ""
|
||||
if minimum_nm_version:
|
||||
nm_version_check = MINIMUM_NM_VERSION_CHECK.format(
|
||||
minimum_nm_version=minimum_nm_version
|
||||
)
|
||||
|
||||
nominal_nm_testfile_data = RUN_PLAYBOOK_WITH_NM.format(
|
||||
test_playbook=test_playbook,
|
||||
get_nm_version=minimum_nm_version and GET_NM_VERSION or "",
|
||||
minimum_nm_version_check=nm_version_check,
|
||||
extra_run_condition=extra_run_condition,
|
||||
)
|
||||
|
||||
return nm_testfile, nominal_nm_testfile_data
|
||||
|
||||
|
||||
def create_initscripts_playbook(test_playbook):
|
||||
fileroot = os.path.splitext(os.path.basename(test_playbook))[0]
|
||||
init_testfile = fileroot + "_initscripts.yml"
|
||||
|
||||
nominal_data = RUN_PLAYBOOK_WITH_INITSCRIPTS.format(test_playbook=test_playbook)
|
||||
|
||||
return init_testfile, nominal_data
|
||||
|
||||
|
||||
def check_playbook(generate, testfile, test_playbook, nominal_data):
|
||||
is_missing = False
|
||||
returncode = None
|
||||
if generate:
|
||||
print(testfile)
|
||||
with open(testfile, "w") as ofile:
|
||||
ofile.write(nominal_data)
|
||||
|
||||
if not os.path.isfile(testfile) and not generate:
|
||||
is_missing = True
|
||||
else:
|
||||
with open(testfile) as ifile:
|
||||
testdata = ifile.read()
|
||||
if testdata != nominal_data:
|
||||
print(f"ERROR: Playbook does not match nominal value: {testfile}")
|
||||
returncode = 1
|
||||
|
||||
return is_missing, returncode
|
||||
|
||||
|
||||
def main():
|
||||
testsfiles = glob.glob("playbooks/tests_*.yml")
|
||||
missing = []
|
||||
returncode = 0
|
||||
|
||||
# Generate files when specified
|
||||
generate = bool(len(sys.argv) > 1 and sys.argv[1] == "generate")
|
||||
|
||||
if not testsfiles:
|
||||
print("ERROR: No tests found")
|
||||
returncode = 1
|
||||
|
||||
for test_playbook in testsfiles:
|
||||
if test_playbook in IGNORE:
|
||||
continue
|
||||
|
||||
nm_testfile, nominal_nm_testfile_data = create_nm_playbook(test_playbook)
|
||||
|
||||
is_missing, new_returncode = check_playbook(
|
||||
generate=generate,
|
||||
testfile=nm_testfile,
|
||||
test_playbook=test_playbook,
|
||||
nominal_data=nominal_nm_testfile_data,
|
||||
)
|
||||
if is_missing:
|
||||
missing.append(test_playbook)
|
||||
if new_returncode:
|
||||
returncode = new_returncode
|
||||
|
||||
if test_playbook not in NM_ONLY_TESTS:
|
||||
init_testfile, nominal_init_testfile_data = create_initscripts_playbook(
|
||||
test_playbook
|
||||
)
|
||||
is_missing, new_returncode = check_playbook(
|
||||
generate=generate,
|
||||
testfile=init_testfile,
|
||||
test_playbook=test_playbook,
|
||||
nominal_data=nominal_init_testfile_data,
|
||||
)
|
||||
if is_missing:
|
||||
missing.append(test_playbook)
|
||||
if new_returncode:
|
||||
returncode = new_returncode
|
||||
|
||||
if missing:
|
||||
print("ERROR: No NM or initscripts tests found for:\n" + ", \n".join(missing))
|
||||
print("Try to generate them with '{} generate'".format(sys.argv[0]))
|
||||
returncode = 1
|
||||
|
||||
return returncode
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
30
roles/linux-system-roles.network/tests/files/cacert.key
Normal file
30
roles/linux-system-roles.network/tests/files/cacert.key
Normal file
@@ -0,0 +1,30 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-256-CBC,B773C37C13C791B1B2F735A7D6D22F1D
|
||||
|
||||
KcpCACKK2i/zLDkH/e2bM/3hzyuC7UkSJ32Vn2xvH6ukKzOpt71PJjtzucY3TgB7
|
||||
T8fYDJ0OGFfW/97M9OSjY10+wo/Vn+aTTCJWe2Y0+JeoV+bFJq33fuP0SlJI1PIU
|
||||
CrxnWhFUM3iaDHjuJ32GaUCkLozKTRdb5KT0BttSdSudnT+9d6zHejCwvYEaGek0
|
||||
C3fifoN2xC47P+63UF40KWMP0+j83ZRtHXUUgQ9E0Eqmbag6jTBh2TvV/PiaWlRv
|
||||
YCVMapOBs0ktSPPJACygRJcR63MocS9of7aRaPMCDP7HpzrjzKnHqJ+bPteuaE4k
|
||||
UmVOlrBsJb4g/zpfT4Ee2waT/mKEiRtNhf8a7DNkc34I50iMqhOojM1zRPtQugO6
|
||||
5BGhFeciHCe7RzHvltWJRmLrl+H7Z8wvusxbSQRM5ZT18+wgBkgTb8dA3bmZS0Ws
|
||||
JYcd9BN8zbsxETo/IFZ2gFOaVvOymVE5mscRR21RsiBi1vfqjl+pAt4ZrlGwVpxL
|
||||
3z3yvT3lAx8Cgeg8dCxrDNb14Xwk+hkBblExLMXsUGCsRXJglk9QVPE0XjKD9XNa
|
||||
mZnBHOpAsdPun58PRiaPpC+VgaFBhzPHTyBczCG1sjpkOiTJpGLpgveAq4wOXQGH
|
||||
PMcux4ZDARYbJfGXANNqloIO3PHDPuhVmSAJZSMixDd4SLKjT6tALdqIv1BvOLl7
|
||||
Ay0y3Vie4oGc4EWjHqQA+r+6CATHHXtIOvWLJQ4/KQa/R+pTp0qDtXdOeHaAZzhv
|
||||
BpqvQUouKUyxXlGFZrGUq9l+sFtjLlcKP33Yb2WHg4ct0gAVDIA6SK4rNH6+h/NS
|
||||
rFQNOvArTeZgLCaG6htJh68WLF8p6687s4bKNM8niZ5VcsFTvMYPbfF5WdE0l53s
|
||||
fZpZBf1v03ZRJYg2V9a0sNPEysaIaTJzs5lFeya78iTF/Epo4GtTHv8sWebVwh/H
|
||||
FYINLIcPzzxAvw7a+7ymIsYZphomuEoCCoX85DPPbXfZOb2Bdysfdr7uyRsB480E
|
||||
or6+gQxZJWxcO5tMR7+G8EuUgnPMelVNczw3UJHM+sl4Kjh9q3hF4ppWFTIOaPQ/
|
||||
BL3qPE/ZxSFC8UcG+QJEbNmPPQLXnpWPUZ3GmyH/+pPUZCkcWanpn0W3chGlJCsW
|
||||
spkDMt/dpPtje1q7rfrWCVAYo4AeYzigSuxoyfpBfqcpD6wAssPQmWj4fFr91RW7
|
||||
p/iLlACpevyecALrJpU65yGWDvGWlx+dEqvdz7FRUSTkVrted/W3pmro8eDAInWx
|
||||
17VM0hHfNE00hwpGaga2CY8q3EC+3kApSE6d8dbBtSzBp4YZsGq+p+Xkj7mTc/rn
|
||||
mXJazUSPjNhWooI+0pN2VxB3HRBloNjsQOLaWVcSiv6l3wKl70ZbBjPkikO05k+v
|
||||
QXayu3i9RjXvhT974atOqoqCSigc8ROsCYGxgHjwVMU9Spc9i8y6PrgX9ID6yk9f
|
||||
9YcJjmtEi6MYh0uXNkx2m6utMjgcuAqP8yfPqeBRK2SOoLuBM9JKP8tjwq4ZBawj
|
||||
SuWe82zTRjR2oXMgNy6gBBDGky+W7kNaNw/KksZUxdiNhzeDRbDG8hMJI1HcY4xQ
|
||||
-----END RSA PRIVATE KEY-----
|
||||
21
roles/linux-system-roles.network/tests/files/cacert.pem
Normal file
21
roles/linux-system-roles.network/tests/files/cacert.pem
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDizCCAnOgAwIBAgIUG1DftQ2xyrN+HE+KHLFmKHZnIkcwDQYJKoZIhvcNAQEL
|
||||
BQAwVDELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UE
|
||||
CgwTRGVmYXVsdCBDb21wYW55IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0yMDA1
|
||||
MDMwNTI2MTFaGA8yMjk0MDIxNTA1MjYxMVowVDELMAkGA1UEBhMCWFgxFTATBgNV
|
||||
BAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEQ
|
||||
MA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AMGAmO9ugnI/jaw4qNTyh/O65BNEvzOIwLU0mo3wTOSiakoOuC0gqO4S+0FOmC6v
|
||||
ceoArS+GllowzrgnnmM4EH9hqmiLeFKa4Z2graIm2W86ayN5k3psiMolONOZ8y0r
|
||||
nAMj84FifDYIOHoYbKUeN5BDsotrHbrZ/PZhlZgN1ou3gapXqM12TkXdzaj//vRd
|
||||
CORjwO1ubpzb17PFUNOLWaDf3ohfoMCG08UkGwIGK0mouJ1yflda27MCcLzmDxV8
|
||||
4dfI//R/6WtN1hzWSW9ae99VwSjlACH2go/0fDD+K9jvKkEVRZAqBEnM3voQCOah
|
||||
P9NMJ30R9Sh8B/D2KXGyIU0CAwEAAaNTMFEwHQYDVR0OBBYEFDUKdAwDiWpUpayU
|
||||
mjiWEcMcXjQdMB8GA1UdIwQYMBaAFDUKdAwDiWpUpayUmjiWEcMcXjQdMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKEyNiDawDJeaauDUmHgdNlG
|
||||
WuBlvn4Lph/+J27njmAoIbKv3aDw+kndxI02ryCZTJOm8a1NqHfkNct4ny+Cj4cz
|
||||
rNoZIyMucVoKGgCMYb5zwYtW3W7RshUZoBdQDBLiIuktNsWTyqss3yVPPq8Q1JJY
|
||||
89dtjCNydL6dunFSrGjVJ2K5HaTyidti2IN9g2Sbxmxgoz71ZP09xmBxaY+O738M
|
||||
z5nRdrb2DX0flmv5pcqSzn7063t9FGKOp2bF9NTpcEWkultsCOvsVcsO4X/18L4J
|
||||
3W8FVltyCvunv4GQecWqlNHTRT+QI2h48EVEzHQnOGEe9q1C8WVGeQ3cZXMei8k=
|
||||
-----END CERTIFICATE-----
|
||||
31
roles/linux-system-roles.network/tests/files/client.key
Normal file
31
roles/linux-system-roles.network/tests/files/client.key
Normal file
@@ -0,0 +1,31 @@
|
||||
# password=test
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-256-CBC,C4A5E9A189773AB0F3CE3DCC98F208AE
|
||||
|
||||
LPNSExpEERS+/qHJxd8puT+EaZ/dZ20gkU/C2eaNNJerzr4moSXG4ioh5ggz4utQ
|
||||
w57fD5OYqPiloNIawi/Ta5Opo3zU+iMZPVQALLbemXWXmNMxqxNCGdonc4enxMoN
|
||||
auLxpdYPW+infFmf0UPwZjWkrLnK8XFapTGDaNesfgMNSRVSt+DQL3xeKUjcuXfh
|
||||
rYvF26/Ls8NHB0tCU449vCa5ta1fHPT78B0cWgCmhcg/L8/0veBYfwxnyu6l3E6Q
|
||||
RXWcyaJoihhCSg9kCZOqQFKDtz3B9G8/G8P5n5udN2TYUK0ieCktocOip0r/aUfk
|
||||
Rz/NPjej18tuvA9e+uho2DuEj7OV1Rt0Fr6G2NySDYAIjlzM1+GoDdX3R8Rva2eX
|
||||
SJYEjQvvLMAXU9wLEGd2u9jw3h8g2rNPF34Mo/fZsU6f83WceN7wzaDjKBM9TC/U
|
||||
DjeUpJ2LHr3SduRoq5K7PqTG6LlRx4ZC06P8Gwu/cjlHqHuMlLE6wWPHowp9O08S
|
||||
zMzJji6csSzZ5x5U41xiBJd19G0tbfjGBOvxhVLC3hmfqMtRwgeKSZMUz5f0iFvS
|
||||
V4LE/ZNXWv5OybEzMyIiQBRB0G8mq5BkQ3rU9uTMO6Xc6mosQy0jiCsQLYaX2IoT
|
||||
kyU6ZqPgAeBD3g5zCGudcF4qqY3pWRU6cijpivsuyX58YmulhQJsB2rnoImv8ZOR
|
||||
4Uw+fvAx38v/dH/aAGKNdQV/4z+CXpAX4SdqYgBx9wXu6Wva31AVrbDrKnpSlWYF
|
||||
M9gAHgpuhW9OH7du/y7sePU6k37fHtqDX0V5XoyeRxixR+KGb8k3tt0HFA1GExSu
|
||||
XyXcOOfwec7xNQjZBM9jREI0yO1tCbHEeLsLpQnf31cpfSQumBZoiim6Vyk7vCN8
|
||||
YBJ9qiVNrFiVogWl5hUrSS2MLQP1ZQBkedmOeKZpkZ26GW5yY0y27v2mHdhU2Dvd
|
||||
otvLGiVKxSXlu+tqt1WkMvu6hcfrDZDCONW7emGW7xs2vdYdvADVlYs/Eb0WFXb1
|
||||
tLkwg3v7I23LeFRrKX4Fm5/biG4GuR4sj9iPLayrKWhpujIVFJqHTI3YhjIU56Qp
|
||||
uPuClnoFsKrWS9DXaziuuXmLZlXH3e5aOO+M2H3JmXTRCojyjKlIJiJJmHGrfwfe
|
||||
oJkSF+ABs2zrpteXU+Cnfn8V01TrtxPYIBF3CbOMZEvwgjPLX0UNtnss0hXH4rJe
|
||||
9yF/PiKWehUow8q4Gpwt2PnLkUWyL21GwCwXf5Cq3yRAKtyrJTlJsdYV1f3brzfb
|
||||
JkBgKaFJ44Ee7D75PAio8g/BIDpvUdZVXwn3FizjfAU+HhXonPSYb2M34C6I/frk
|
||||
mJPgZ5hbpt1SoCCER48+rQygiLdNQH6OsuhJeEElPFYwNo6i5jZsZ9iE0rmJxGgk
|
||||
m7Mhi491NdK8L6Kh8kM2Dgupsfcstmx4+pI3gmgnsYZApmFoQlfcg4MhbWqxznv+
|
||||
cPm1n2SZMoMLru44vbnjW+ZAggen5zNZOrsVt8UImSBVKfAIrgDUuYIv7uqUiKHI
|
||||
yHmAkZDlqEbpkbUG9m60OeuEIgpN7MT3Kod387ZyOu9uaTZWdD18/N83E4eFecND
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAuQipSk9+0rd/qBMDRiFzV8vDksaueVphejGEgiQhqtUDgjc/
|
||||
ot/o7M8fFVC6wau2ixTnEMHuZXgoBOKATxX805FggEsLLL98OnN7AyTTKOtHVfIm
|
||||
gK3fJ1Y9l95+2nuJWhmaan0vr3YMp6z3lSa+hlhhTYx/mIvTZho/K3+METg8DEfl
|
||||
QUSkhAlrFSEahr2Pu/yETr8c+8vKTDnZDLvcFyyuDtAz+clEQUVndWJQpQpSVfR9
|
||||
4xKuzaj10mUA9Utv4RkbNJ78/KgdTbaGIOVLUnYCJUg8d3/YV7aNCqraHBAZ9aoP
|
||||
S4dl46KXC3qpaEBFfKaF+RcPSVUtc4eCQ74kKwIDAQABAoIBAGoArUN2IVjEaSy3
|
||||
n7OIrFSK1oL6sa+x+JARWDFaU7NTj0wFLL65ee5Yhh0m/6a+IbiyA+IUx+d3m62Y
|
||||
uRsVpJ7r9RXqZ/99v8SYrctSSGpzx41USXyEn4ggnu6nN5MhHMHyUwVYrH3fqkZR
|
||||
EBFxfcrnTO8pY1vYFwayWKgpzOt7ip30JF1E7RH0IWfA2koJ+hZgSumPmF31btBK
|
||||
eqDaQ168u0at6I7nYvRIWVT68D2k+PMb/c/rlOUYSyy+VfCgnShWD+m1hlyaDF1c
|
||||
cbVvOhsul3rFeEqbToGN/6yyDDcyolTvYxMm3vb6jmoExZyRsShv0XyhokSuCN9P
|
||||
v5SeNpkCgYEA7OpIlsZUoTXm2ffCQiZd8gRtKk0O3dzmWTkcNEgj2uUNH6ANNy3W
|
||||
gLojKeF2EyC3appRWLVRYN/m6r/Qj+rztZfW3Jw1UJQV+tLEOBzk3yBnRdh1aRgW
|
||||
8YTH1+HJqlJ/2iKJRKRhseM5AHiTslp7ude6cWQxO52pJ6Rbp1z3fBUCgYEAx/B4
|
||||
LreIDJYDnYSyL/CvVkHEn1hCYX0oBpefzV6ofYDqv0OLe8BWOBsShQ3Crh0FuQTa
|
||||
xV2xc+OzDewlu2OwNm4/X0qjXvoWkEMLBXKEHjPyxnbHLCYaaA/9ENmVIkc8aZWE
|
||||
p7KcCYGlfiHpbdYWAD8KYdv5CsFHFbwhPwrD7z8CgYAEtsSq+1dDvebR/3QGDO1h
|
||||
m2TwqofZMkQDEnfVMnpEKLqSHoUky+ywswNwGeRXjRcZL+jecv0jiFD36skjk/E1
|
||||
c8f6q8ED0W5+hyMQWsLTDboAUcZESQ5rz9CKIxv4H5wbowRIMV0gRP0lXUDTE6nS
|
||||
kNBM4Ul5fjGXcFXChr8F4QKBgGSmAeoKi9tCHTnLVePaNnmmi/Nm+6uV1HNVGqXI
|
||||
k+rx3bpAp1O5o+2Ee1MtdSYvB/V2oyadnrnnEvjcOrZVXZxY7V/r88fY/0jJ5x9r
|
||||
4WRO5FTR8DuiRsLB4bP8xB1IXPoNwYSl3fTPJd8T9S1MizC+i1xt3rVyTHV9igLx
|
||||
SWcDAoGBAMoynJvQUOssWwFTtNQK0ptz95rrTkO2bri+8MJfSh8tessekwPHVe6M
|
||||
SBofFhDiesrHBHczJ61qDnb3GemA0kEbo023mxNo0HPam+OFgX5mrihizBZnRZjh
|
||||
aecVouDd0uwacsB76fwP6Fl5GhkFvOSBKr2IKNJjUMXyvW8/XGZE
|
||||
-----END RSA PRIVATE KEY-----
|
||||
22
roles/linux-system-roles.network/tests/files/client.pem
Normal file
22
roles/linux-system-roles.network/tests/files/client.pem
Normal file
@@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrDCCApSgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwVDELMAkGA1UEBhMCWFgx
|
||||
FTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55
|
||||
IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0yMDA1MDMwODUxMTdaGA8yMjk0MDIx
|
||||
NTA4NTExN1owXzELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEc
|
||||
MBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEbMBkGA1UEAwwSY2xpZW50LmV4
|
||||
YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuQipSk9+
|
||||
0rd/qBMDRiFzV8vDksaueVphejGEgiQhqtUDgjc/ot/o7M8fFVC6wau2ixTnEMHu
|
||||
ZXgoBOKATxX805FggEsLLL98OnN7AyTTKOtHVfImgK3fJ1Y9l95+2nuJWhmaan0v
|
||||
r3YMp6z3lSa+hlhhTYx/mIvTZho/K3+METg8DEflQUSkhAlrFSEahr2Pu/yETr8c
|
||||
+8vKTDnZDLvcFyyuDtAz+clEQUVndWJQpQpSVfR94xKuzaj10mUA9Utv4RkbNJ78
|
||||
/KgdTbaGIOVLUnYCJUg8d3/YV7aNCqraHBAZ9aoPS4dl46KXC3qpaEBFfKaF+RcP
|
||||
SVUtc4eCQ74kKwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1P
|
||||
cGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUoUCV4T3pFwaQ
|
||||
HYSlCr8Iqdd+/TcwHwYDVR0jBBgwFoAUNQp0DAOJalSlrJSaOJYRwxxeNB0wDQYJ
|
||||
KoZIhvcNAQELBQADggEBALXhDSFirybmhZXcHuSqXn0tLp6mZintW+91B81bDUtO
|
||||
FuCrWqXwV0iensm94mOeykGIR/r0Y0Y4uqOHpIznY+q5NIek0qIdirbdr5mCXK5y
|
||||
fxXVIMM14GMTyIR9A4+IZaRkFbcrVnBhOdUpTQjp88jlzDr5jdyjTEnOZyOJH9kL
|
||||
Qpd417iB4X5TxuQ2xe5EgHOCb8OfxO0a2BzlwtfUQAkz2v+h0RlVBwQFcE2NCJ3z
|
||||
hvF3AWGl+5pkfWpY6d+1EPI3+82C6uRf8be/WKHPKu3i0irrVtZdMsKNkRiD5UUK
|
||||
S4Y0WnoVu/DWSR8h9iPGSFKMkUcjFI8hgc4YQ6G4Odc=
|
||||
-----END CERTIFICATE-----
|
||||
8
roles/linux-system-roles.network/tests/files/dh.pem
Normal file
8
roles/linux-system-roles.network/tests/files/dh.pem
Normal file
@@ -0,0 +1,8 @@
|
||||
-----BEGIN DH PARAMETERS-----
|
||||
MIIBCAKCAQEAjbYPkANn2XGqDGCzse9wAfM0I5WJpp+Xl+iNJFmaKXBguo0BPYQt
|
||||
hZOpJbKL3aNaFsRxhdAJ8UXzBP6oIzCejcGti+jw+xtVk8ietWEK6e91yi+Ak2g2
|
||||
/Xtt9hoYQkeoe5hkcv35NcJ0xdQwlSvMbY/j8HtKamx/A3zu+YPQAe/3AOe3L+JT
|
||||
iEL5Gw00NPVnyEWKX4fVchAbMUkRsQKeXtsyOyDc4/RccjfLa1toyj8PRommK5UH
|
||||
dkSqi04FTOUIx6aTwt21EehJuggLVDShoQdxGV+FzXmdtelLmerGMtVPBbf8DSkN
|
||||
MKMBEg4d28DzjXPAWUHMD+JGPzAlvf87EwIBAg==
|
||||
-----END DH PARAMETERS-----
|
||||
31
roles/linux-system-roles.network/tests/files/server.key
Normal file
31
roles/linux-system-roles.network/tests/files/server.key
Normal file
@@ -0,0 +1,31 @@
|
||||
# password=test
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-256-CBC,ED349A8B098E2D1DB70C30F77EF599AB
|
||||
|
||||
j1rzje2sWFk3B9kD6eE7WrqVDynFEJ3t3kdOv0iUvH5Ybll1C7Qx3EFEdoM4z2OV
|
||||
E6q3nr2DOvpMPox1DvBdIipWOQWJxkZyBHqNn4v4GR4c0uxLswsk7XSBQLUclRsn
|
||||
QBGO6x8pcEA9u/O3PSrTt+pVozWrXWmR2UHNM//9WUsRpWF4Lv0EINzsfwmD7aJQ
|
||||
nRcSfXsCggXP6wnJX5dgo5PlRm6R+bodgzePr0QRlh8TT6wnixZfWalYM5iUKlEF
|
||||
GcE+VejZuBL69byl2AcRt8I5tQ+UZxmzhKPSsYN0NKD8vbcVVnp2sre/rbdTzWz5
|
||||
laF386g1M8QBimDE/V3Bw5b9Bg1ZP3arlpugVXGVNA+HFti8PVdkaMqLgkFIC2Xu
|
||||
OwmNKffAPIItuB8leg5A76oLoIlllRqjWO9M/O+MqAlrJ96xLRiUeGkez4Pp7eFV
|
||||
30YrlOXyzwZKfXoOPIfE5Mbz4CPqR67XuqW8jOryIGOryMB17b0+vdRpDY0wxk8/
|
||||
lGmc5rglDxLFA8dNemAHDednasCuVlrbsQsZRnPkKavXiSu7QCbvm1frAXZfnyRp
|
||||
TpPmE6L4+nEy8PQnK/IxOCqRcy6e1SPezRpajRjB5ooDT8hDmDkG47NdnrB+kOKL
|
||||
5LIpATLSGS9IVk0RW/M8EqJP1kRh2JOCQT3V+gUN0ttz8bjZpivKnp76/ztg0lo0
|
||||
oC2lhuXV5HOYHw1z5jDazsYpQDYoHgYWXnzPJJp6Ecn+nkjZMKQjDV9ZqE1miPrZ
|
||||
E4V0ULNmWaAQHvwc98yR97ui1YHmw5XVMoeDhy3fhB6IOyaGGdEj9o2iQr8kp9GC
|
||||
dxBKK/xMOU6kwDF9Nsfh46veRGTbhAJdGeWqdxscdCupkO8KRtZqzL454+9GnYfe
|
||||
n1f7wxJh7aTLNjF2an5Qa9v7uU6D58+9blxG7ls5qGt4xjBNAXCc8bPpmLqeCW4G
|
||||
Xz8iwxECvwWIQ+SjUcXuP8+/NO58B14kDNP03+1gA7AHIesa2CTvHLCyMPaN2oGK
|
||||
3R4LNxQQDNygEzRj8vHjURU1FNRJ4RjCi7SbqoOsl31Hvef6j0lcW0Sz4UICcCJI
|
||||
p4NPnApoaHewL4exvlJ80qPbFscuVevXBlUC2LdxXS+9E+c0NaLauEeNYCUoaBDi
|
||||
HIpbxRKXmqLc4LAKYVuEcIBFhdXp3UC9niVd7Nrguu0lUJXC78OzpltxWrqX/u4E
|
||||
O2aCNK0Yg9U+rxm6wyccqEyptIS2GRCIpUGD/LVF3mOC16NB/JeYGrOWvDptdCeg
|
||||
9pJrakJjE1Fm3pg4Xc74bT6IDj0EKwKSvZhtlcsM9JaXWChe/ZrDPPI/NP6MuyW4
|
||||
jcqpa9HPBBSyaxKsEPXFJhdhrz8VfsU2e5VvcALaJaAOpHwZgaNUpvpsY4LPW9mi
|
||||
lHsecEBiq6re0r7TAgBE1AnlaI4ho0fKSgSub3NWUZlEaBK3X2n/Li6op6LIsvM5
|
||||
iySYaAluQy4dANww0KhQHMIh0jbuZGzmG2Hxk/poorYRf60YJlbTnHVD/FKUdFX+
|
||||
rUow0iy8Ez1uF272u5orYW2tBbkhSaieKOT8f4HFCxUsgITbd8Lf/XJ6l6Qns6SK
|
||||
-----END RSA PRIVATE KEY-----
|
||||
22
roles/linux-system-roles.network/tests/files/server.pem
Normal file
22
roles/linux-system-roles.network/tests/files/server.pem
Normal file
@@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrDCCApSgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwVDELMAkGA1UEBhMCWFgx
|
||||
FTATBgNVBAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55
|
||||
IEx0ZDEQMA4GA1UEAwwHVGVzdCBDQTAgFw0yMDA1MDMwODUxMzBaGA8yMjk0MDIx
|
||||
NTA4NTEzMFowXzELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0eTEc
|
||||
MBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEbMBkGA1UEAwwSc2VydmVyLmV4
|
||||
YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcC44Amd
|
||||
KQBDwR67aMTPqmNu6HfjadZqsD2xZj5XMVdn4karqsVYIbKMOq+SRzgm5aZ/kzQI
|
||||
CpXJMXfj16cID6BCxNecfJVOfvPyI0kCUbMf1YZiRG2FmB2VsG8AVDGWmn4a7SmX
|
||||
yaCA0ac8dkipnlCF2nddLhcBak/Ls+hjRYN7VSLLvxO8KT42ivhuP9YgGY1K5Yta
|
||||
e90H4HBiKxbnkwOUxi9wobERSXSLgb4e+uX8WRrqxIIYmHF+Gzv5kilRFrPwKBmo
|
||||
3idVPrqjschZe0o8m/nbNo3SzWGI9fdXn0+KgZoQdG3ZixX6uOhrCqJ3iJmnHkp4
|
||||
aXKL5Y7JmX/FFQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1P
|
||||
cGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUx7TXCxUioob7
|
||||
5r/1kMypCYy9Mj0wHwYDVR0jBBgwFoAUNQp0DAOJalSlrJSaOJYRwxxeNB0wDQYJ
|
||||
KoZIhvcNAQELBQADggEBAKtTPl4WJuxfMeut+aEw7vVRU+z5A7D35nlZPQI5nBTt
|
||||
ybgqMNIjdcYT/JwT2GhbzcObc3STNEo582clVN9gTpK7mYKzBBf69nTsWeZzPuNt
|
||||
JQbVbK4RHwFvyosJcw6NfzxE9OxeXhTcKQDQSGKP338sAWoapEZlXNrYOIJac6HX
|
||||
Xo3dQqx/8BdO9hSv1u0/zClnL5lbk1RBylS24wIe8wLoiy4ftLjL4aOYOlonj7HU
|
||||
hknTY6L30oOpG5VtH8SEv3xveH/5GNKwfoGltTzemCgVfb9IhyVTLB3tIv8OW6k1
|
||||
y3+YEzVniVB4gtJ5UniLN1V4lBf6t7MGn0ybAEbOxPI=
|
||||
-----END CERTIFICATE-----
|
||||
65
roles/linux-system-roles.network/tests/get_coverage.sh
Executable file
65
roles/linux-system-roles.network/tests/get_coverage.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
#! /bin/bash
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if [ -n "${DEBUG}" ]
|
||||
then
|
||||
set -x
|
||||
fi
|
||||
set -e
|
||||
|
||||
if [ "$#" -lt 2 ]
|
||||
then
|
||||
echo "USAGE: ${0} host playbook"
|
||||
echo "Get coverage info from host for playbook"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
host="${1}"
|
||||
shift
|
||||
playbook="${1}"
|
||||
|
||||
coverage_data="remote-coveragedata-${host}-${playbook%.yml}"
|
||||
coverage="/root/.local/bin/coverage"
|
||||
|
||||
echo "Getting coverage for ${playbook} on ${host}" >&2
|
||||
|
||||
call_ansible() {
|
||||
local module="${1}"
|
||||
shift
|
||||
local args="${1}"
|
||||
shift
|
||||
ansible -m "${module}" -i "${host}", -a "${args}" all "${@}"
|
||||
}
|
||||
|
||||
remote_coverage_dir="$(mktemp -d /tmp/remote_coverage-XXXXXX)"
|
||||
trap "rm -rf '${remote_coverage_dir}'" EXIT
|
||||
ansible-playbook -i "${host}", get_coverage.yml -e "test_playbook=${playbook} destdir=${remote_coverage_dir}"
|
||||
|
||||
#COVERAGE_FILE=remote-coverage coverage combine remote-coverage/tests_*/*/root/.coverage
|
||||
./merge_coverage.sh coverage "${coverage_data}"-tmp $(find "${remote_coverage_dir}" -type f | tr , _)
|
||||
|
||||
cat > tmp_merge_coveragerc <<EOF
|
||||
[paths]
|
||||
source =
|
||||
.
|
||||
EOF
|
||||
# example path with Ansible 2.9.6:
|
||||
# /tmp/ansible_network_connections_payload_psugdf6r/ansible_network_connections_payload.zip/ansible/modules/network_connections.py
|
||||
# /tmp/ansible_network_connections_payload_psugdf6r/ansible_network_connections_payload.zip/ansible/module_utils/network_lsr/__init__.py
|
||||
# /tmp/ansible_network_connections_payload_psugdf6r/ansible_network_connections_payload.zip/ansible/module_utils/network_lsr/argument_validator.py
|
||||
# /tmp/ansible_network_connections_payload_psugdf6r/ansible_network_connections_payload.zip/ansible/module_utils/network_lsr/utils.py
|
||||
# /tmp/ansible_network_connections_payload_psugdf6r/ansible_network_connections_payload.zip/ansible/module_utils/network_lsr/nm_provider.py
|
||||
for file in $(echo 'SELECT path FROM file;' | sqlite3 "${coverage_data}"-tmp | sed s,/module.*.py,, | sort -u)
|
||||
do
|
||||
echo " ${file}" >> tmp_merge_coveragerc
|
||||
done
|
||||
|
||||
COVERAGE_FILE="${coverage_data}" coverage combine --rcfile tmp_merge_coveragerc "${coverage_data}"-tmp
|
||||
|
||||
test -n "${DEBUG}" && cat tmp_merge_coveragerc
|
||||
rm tmp_merge_coveragerc
|
||||
|
||||
COVERAGE_FILE="${coverage_data}" coverage report ||:
|
||||
COVERAGE_FILE="${coverage_data}" coverage html --directory "htmlcov-${coverage_data}" ||:
|
||||
|
||||
echo "Coverage collected in: ${coverage_data}"
|
||||
82
roles/linux-system-roles.network/tests/get_coverage.yml
Normal file
82
roles/linux-system-roles.network/tests/get_coverage.yml
Normal file
@@ -0,0 +1,82 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
# This expects the variable test_playbook to be set from the outside
|
||||
- name: Prepare for coverage extraction
|
||||
hosts: all
|
||||
tasks:
|
||||
# Use set_fact to set variables to make them available in all plays
|
||||
# 'vars:' Would only set variables for the current play
|
||||
- name: set facts
|
||||
set_fact:
|
||||
coverage_module: network_connections
|
||||
coverage: /root/.local/bin/coverage
|
||||
destdir: "remote_coverage/{{ test_playbook }}"
|
||||
|
||||
# This uses variables from the other set_fact task, therefore it needs to
|
||||
# be its own task
|
||||
- name: set more facts
|
||||
set_fact:
|
||||
coverage_file:
|
||||
# yamllint disable-line rule:line-length
|
||||
ansible-coverage-{{ coverage_module }}-{{ test_playbook|replace('.yml', '') }}
|
||||
|
||||
- name: debug info
|
||||
debug:
|
||||
msg:
|
||||
# yamllint disable-line rule:line-length
|
||||
Getting coverage for '{{ coverage_module }}' with '{{ test_playbook }}'
|
||||
|
||||
# combine data in case old data is left there
|
||||
- command: "{{ coverage }} combine"
|
||||
environment:
|
||||
COVERAGE_FILE: "{{ coverage_file }}"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: remove old data
|
||||
file:
|
||||
state: absent
|
||||
path: "{{ coverage_file }}"
|
||||
|
||||
- name: find coverage files to delete
|
||||
find:
|
||||
path: "{{ ansible_env.HOME }}"
|
||||
patterns: ".coverage.*"
|
||||
hidden: yes
|
||||
register: files_to_delete
|
||||
|
||||
- name: remove old data
|
||||
file:
|
||||
path: "{{ item.path }}"
|
||||
state: absent
|
||||
with_items: "{{ files_to_delete.files }}"
|
||||
|
||||
- name: copy coveragerc
|
||||
copy:
|
||||
content: "[run]\ndisable_warnings = no-data-collected\n"
|
||||
dest: .coveragerc
|
||||
|
||||
- name: install latest pip
|
||||
pip:
|
||||
name: coverage
|
||||
extra_args: --user --upgrade
|
||||
|
||||
- import_playbook: "{{ test_playbook }}"
|
||||
vars:
|
||||
ansible_python_interpreter:
|
||||
# yamllint disable-line rule:line-length
|
||||
"{{ coverage }} run -p --include /*/modules/network_connections.py,/*/module_utils/network_lsr/*"
|
||||
|
||||
- name: Gather coverage data
|
||||
hosts: all
|
||||
tasks:
|
||||
- shell: "{{ coverage }} combine .coverage.*"
|
||||
environment:
|
||||
COVERAGE_FILE: "{{ coverage_file }}"
|
||||
|
||||
- name: Get coverage data
|
||||
hosts: all
|
||||
tasks:
|
||||
- fetch:
|
||||
src: "{{ coverage_file }}"
|
||||
dest: "{{ destdir }}"
|
||||
flat: no
|
||||
34
roles/linux-system-roles.network/tests/get_total_coverage.sh
Executable file
34
roles/linux-system-roles.network/tests/get_total_coverage.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#! /bin/bash
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
set -e
|
||||
coverage_data=total-coveragedata
|
||||
testhost="${1}"
|
||||
|
||||
if [ "$#" -lt 1 ]
|
||||
then
|
||||
echo "USAGE: ${0} host"
|
||||
echo "Get local and all remote coverage data for host"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f remote-coveragedata* "${coveragedata}"
|
||||
|
||||
|
||||
# collect pytest coverage
|
||||
tox -e py26,py27,py36,py37 -- --cov-append
|
||||
|
||||
for test_playbook in tests_*.yml
|
||||
do
|
||||
./get_coverage.sh "${testhost}" "${test_playbook}"
|
||||
done
|
||||
|
||||
./merge_coverage.sh coverage "total-remote-coveragedata" remote-coveragedata-*
|
||||
./covstats .coverage remote-coveragedata-* "total-remote-coveragedata"
|
||||
|
||||
./merge_coverage.sh coverage "${coverage_data}" .coverage remote-coveragedata-*
|
||||
echo "Total coverage:"
|
||||
COVERAGE_FILE="${coverage_data}" coverage report ||:
|
||||
COVERAGE_FILE="${coverage_data}" coverage html --directory "htmlcov-${coverage_data}" ||:
|
||||
echo "Open HTML report with:"
|
||||
echo "xdg-open htmlcov-${coverage_data}/index.html"
|
||||
@@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption(
|
||||
"--provider", action="store", default="nm", help="Network provider"
|
||||
)
|
||||
@@ -0,0 +1,114 @@
|
||||
# -*- coding: utf-8 -*
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
import mock
|
||||
|
||||
parent_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
|
||||
with mock.patch.dict(
|
||||
"sys.modules",
|
||||
{
|
||||
"ansible.module_utils.basic": mock.Mock(),
|
||||
},
|
||||
):
|
||||
import network_connections as nc
|
||||
|
||||
|
||||
class PytestRunEnvironment(nc.RunEnvironment):
|
||||
def log(self, connections, idx, severity, msg, **kwargs):
|
||||
if severity == nc.LogLevel.ERROR:
|
||||
logging.error("Error: {}".format(connections[idx]))
|
||||
raise RuntimeError(msg)
|
||||
else:
|
||||
logging.debug("Log: {}".format(connections[idx]))
|
||||
|
||||
def run_command(self, argv, encoding=None):
|
||||
command = subprocess.Popen(
|
||||
argv, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
||||
)
|
||||
return_code = command.wait()
|
||||
out, err = command.communicate()
|
||||
return return_code, out.decode("utf-8"), err.decode("utf-8")
|
||||
|
||||
def _check_mode_changed(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
|
||||
def _configure_network(connections, provider):
|
||||
cmd = nc.Cmd.create(
|
||||
provider,
|
||||
run_env=PytestRunEnvironment(),
|
||||
connections_unvalidated=connections,
|
||||
connection_validator=nc.ArgValidator_ListConnections(),
|
||||
)
|
||||
cmd.run()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def provider(request):
|
||||
return request.config.getoption("--provider")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def testnic1():
|
||||
veth_name = "testeth"
|
||||
try:
|
||||
subprocess.call(
|
||||
[
|
||||
"ip",
|
||||
"link",
|
||||
"add",
|
||||
veth_name,
|
||||
"type",
|
||||
"veth",
|
||||
"peer",
|
||||
"name",
|
||||
veth_name + "peer",
|
||||
],
|
||||
close_fds=True,
|
||||
)
|
||||
yield veth_name
|
||||
finally:
|
||||
subprocess.call(["ip", "link", "delete", veth_name])
|
||||
|
||||
|
||||
def _get_ip_addresses(interface):
|
||||
ip_address = subprocess.check_output(["ip", "address", "show", interface])
|
||||
return ip_address.decode("UTF-8")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def network_lsr_nm_mock():
|
||||
with mock.patch.dict(
|
||||
"sys.modules",
|
||||
{
|
||||
"ansible.module_utils.basic": mock.Mock(),
|
||||
},
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
def test_static_ip_with_ethernet(testnic1, provider, network_lsr_nm_mock):
|
||||
ip_address = "192.0.2.127/24"
|
||||
connections = [
|
||||
{
|
||||
"name": testnic1,
|
||||
"type": "ethernet",
|
||||
"state": "up",
|
||||
"ip": {"address": [ip_address]},
|
||||
}
|
||||
]
|
||||
_configure_network(connections, provider)
|
||||
assert ip_address in _get_ip_addresses(testnic1)
|
||||
if provider == "initscripts":
|
||||
assert os.path.exists("/etc/sysconfig/network-scripts/ifcfg-" + testnic1)
|
||||
else:
|
||||
subprocess.check_call(["nmcli", "connection", "show", testnic1])
|
||||
35
roles/linux-system-roles.network/tests/merge_coverage.sh
Executable file
35
roles/linux-system-roles.network/tests/merge_coverage.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#! /bin/bash
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if [ -n "${DEBUG}" ]
|
||||
then
|
||||
set -x
|
||||
fi
|
||||
set -e
|
||||
|
||||
if [ "$#" -lt 3 ]
|
||||
then
|
||||
echo "USAGE: ${0} path_to_coverage_binary output_file input_files..."
|
||||
echo "Merges all input_files into output file without removing input_files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# path to coverage binary
|
||||
coverage="${1}"
|
||||
shift
|
||||
|
||||
# read by coverage binary
|
||||
export COVERAGE_FILE="${1}"
|
||||
shift
|
||||
|
||||
tempdir="$(mktemp -d /tmp/coverage_merge-XXXXXX)"
|
||||
trap "rm -rf '${tempdir}'" EXIT
|
||||
|
||||
cp --backup=numbered -- "${@}" "${tempdir}"
|
||||
# FIXME: Would not work if coverage files are not hidden but they are by
|
||||
# default
|
||||
shopt -s dotglob
|
||||
"${coverage}" combine "${tempdir}/"*
|
||||
|
||||
echo "Merged data into ${COVERAGE_FILE}"
|
||||
./covstats "${COVERAGE_FILE}"
|
||||
1
roles/linux-system-roles.network/tests/module_utils
Symbolic link
1
roles/linux-system-roles.network/tests/module_utils
Symbolic link
@@ -0,0 +1 @@
|
||||
../module_utils/
|
||||
1
roles/linux-system-roles.network/tests/modules
Symbolic link
1
roles/linux-system-roles.network/tests/modules
Symbolic link
@@ -0,0 +1 @@
|
||||
../library/
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Set {{ profile }} down
|
||||
hosts: all
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ profile }}"
|
||||
state: down
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
1
roles/linux-system-roles.network/tests/playbooks/files
Symbolic link
1
roles/linux-system-roles.network/tests/playbooks/files
Symbolic link
@@ -0,0 +1 @@
|
||||
../files
|
||||
@@ -0,0 +1,149 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Install dependencies for integration tests
|
||||
hosts: all
|
||||
vars:
|
||||
- rpmdependencies:
|
||||
- git
|
||||
- python3-pip
|
||||
- rsync
|
||||
|
||||
tasks:
|
||||
- name: Install rpm dependencies
|
||||
package:
|
||||
state: present
|
||||
name: "{{ rpmdependencies }}"
|
||||
|
||||
- name: Install Pytest
|
||||
command: "pip3 install pytest"
|
||||
|
||||
|
||||
# Import needed in order to install initscripts dependencies on the remote
|
||||
# system.
|
||||
- import_playbook: "../tests_default_initscripts.yml"
|
||||
|
||||
# Import needed in order to install Network Manager dependencies on the remote
|
||||
# system.
|
||||
- import_playbook: "../tests_default_nm.yml"
|
||||
|
||||
|
||||
- name: Run Pytest tests
|
||||
hosts: all
|
||||
tasks:
|
||||
- block:
|
||||
- name: create tempdir for code to test
|
||||
tempfile:
|
||||
state: directory
|
||||
prefix: lsrtest_
|
||||
register: _rundir
|
||||
|
||||
- name: get tempfile for tar
|
||||
tempfile:
|
||||
prefix: lsrtest_
|
||||
suffix: ".tar"
|
||||
register: temptar
|
||||
delegate_to: localhost
|
||||
|
||||
- include_tasks: ../tasks/get_modules_and_utils_paths.yml
|
||||
|
||||
- name: get tests directory
|
||||
set_fact:
|
||||
tests_directory: "{{ lookup('first_found', params) }}"
|
||||
vars:
|
||||
params:
|
||||
files:
|
||||
- tests
|
||||
- network
|
||||
paths:
|
||||
- "../.."
|
||||
|
||||
# TODO: using tar and copying the file is a workaround for the
|
||||
# synchronize module that does not work in test-harness. Related issue:
|
||||
# https://github.com/linux-system-roles/test-harness/issues/102
|
||||
#
|
||||
- name: Create Tar file
|
||||
command: >
|
||||
tar -cvf {{ temptar.path }} --exclude "*.pyc"
|
||||
--exclude "__pycache__"
|
||||
-C {{ tests_directory | realpath | dirname }}
|
||||
{{ tests_directory | basename }}
|
||||
-C {{ modules_parent_and_dir.stdout_lines[0] }}
|
||||
{{ modules_parent_and_dir.stdout_lines[1] }}
|
||||
-C {{ module_utils_parent_and_dir.stdout_lines[0] }}
|
||||
{{ module_utils_parent_and_dir.stdout_lines[1] }}
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Copy testrepo.tar to the remote system
|
||||
copy:
|
||||
src: "{{ temptar.path }}"
|
||||
dest: "{{ _rundir.path }}"
|
||||
|
||||
- name: Untar testrepo.tar
|
||||
command: tar xf {{ temptar.path | basename }}
|
||||
args:
|
||||
chdir: "{{ _rundir.path }}"
|
||||
|
||||
- file:
|
||||
state: directory
|
||||
path: "{{ _rundir.path }}/ansible"
|
||||
|
||||
- name: Move module_utils to ansible directory
|
||||
shell: |
|
||||
if [ -d {{ _rundir.path }}/module_utils ]; then
|
||||
mv {{ _rundir.path }}/module_utils {{ _rundir.path }}/ansible
|
||||
fi
|
||||
|
||||
- name: Fake out python module directories, primarily for python2
|
||||
shell: |
|
||||
for dir in $(find {{ _rundir.path }} -type d -print); do
|
||||
if [ ! -f "$dir/__init__.py" ]; then
|
||||
touch "$dir/__init__.py"
|
||||
fi
|
||||
done
|
||||
|
||||
- set_fact:
|
||||
_lsr_python_path: "{{
|
||||
_rundir.path ~ '/' ~
|
||||
modules_parent_and_dir.stdout_lines[1] ~ ':' ~ _rundir.path
|
||||
}}"
|
||||
|
||||
- debug:
|
||||
msg: path {{ _lsr_python_path }}
|
||||
- command: ls -alrtFR {{ _rundir.path }}
|
||||
|
||||
- block:
|
||||
- name: Run pytest with nm
|
||||
command: >
|
||||
pytest
|
||||
{{ _rundir.path }}/{{ tests_directory | basename }}/integration/
|
||||
--provider=nm
|
||||
register: playbook_run
|
||||
environment:
|
||||
PYTHONPATH: "{{ _lsr_python_path }}"
|
||||
always:
|
||||
- debug:
|
||||
var: playbook_run.stdout_lines
|
||||
|
||||
- block:
|
||||
- name: Run pytest with initscripts
|
||||
command: >
|
||||
pytest
|
||||
{{ _rundir.path }}/{{ tests_directory | basename }}/integration/
|
||||
--provider=initscripts
|
||||
register: playbook_run
|
||||
environment:
|
||||
PYTHONPATH: "{{ _lsr_python_path }}"
|
||||
always:
|
||||
- debug:
|
||||
var: playbook_run.stdout_lines
|
||||
always:
|
||||
- name: remove local tar file
|
||||
file:
|
||||
state: absent
|
||||
path: "{{ temptar.path }}"
|
||||
delegate_to: localhost
|
||||
|
||||
- name: remove tempdir
|
||||
file:
|
||||
state: absent
|
||||
path: "{{ _rundir.path }}"
|
||||
@@ -0,0 +1,115 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: "{{ network_interface_name1 }}"
|
||||
type: "{{ network_interface_type1 }}"
|
||||
tasks:
|
||||
- name: "INIT: Ethtool coalesce tests"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- include_tasks: tasks/assert_device_present.yml
|
||||
- name: Install ethtool (test dependency)
|
||||
package:
|
||||
name: ethtool
|
||||
state: present
|
||||
- block:
|
||||
- name: >-
|
||||
TEST: I can create a profile without changing the ethtool coalesce.
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- name: Get current device coalesce
|
||||
command: "ethtool --show-coalesce {{ interface }}"
|
||||
register: original_ethtool_coalesce
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
ip:
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
- name: Get current device coalesce
|
||||
command: "ethtool --show-coalesce {{ interface }}"
|
||||
register: ethtool_coalesce
|
||||
- name: "ASSERT: The profile does not change the ethtool coalesce"
|
||||
assert:
|
||||
that:
|
||||
- original_ethtool_coalesce.stdout == ethtool_coalesce.stdout
|
||||
- name: >-
|
||||
TEST: I can set rx-frames and adaptive-tx.
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
ip:
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
ethtool:
|
||||
coalesce:
|
||||
rx_frames: 1
|
||||
tx_frames: 1
|
||||
- name: Get current device coalesce
|
||||
command: "ethtool --show-coalesce {{ interface }}"
|
||||
register: ethtool_coalesce
|
||||
- name:
|
||||
debug:
|
||||
var: ethtool_coalesce.stdout_lines
|
||||
- name: Assert device coalesce
|
||||
assert:
|
||||
that:
|
||||
- >-
|
||||
'rx-frames: 1' in
|
||||
ethtool_coalesce.stdout_lines
|
||||
- >-
|
||||
'tx-frames: 1' in
|
||||
ethtool_coalesce.stdout_lines
|
||||
- name: "TEST: I can reset coalesce to their original value."
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
ip:
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
- name: Get current device coalesce
|
||||
command: "ethtool --show-coalesce {{ interface }}"
|
||||
register: ethtool_coalesce
|
||||
# Resetting the ethtools only works with NetworkManager
|
||||
- name: "ASSERT: The profile does not change the ethtool coalesce"
|
||||
assert:
|
||||
that:
|
||||
- original_ethtool_coalesce.stdout == ethtool_coalesce.stdout
|
||||
when:
|
||||
network_provider == 'nm'
|
||||
always:
|
||||
- block:
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
ignore_errors: true
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: absent
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Remove {{ profile }}
|
||||
hosts: all
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ profile }}"
|
||||
persistent_state: absent
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Run the tasklist {{ task }}
|
||||
hosts: all
|
||||
tasks:
|
||||
- include_tasks: "{{ task }}"
|
||||
@@ -0,0 +1,124 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: 802-1x-test
|
||||
tasks:
|
||||
- name: "INIT: 802.1x tests"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- include_tasks: tasks/setup_802.1x.yml
|
||||
- block:
|
||||
- name: "TEST: 802.1x profile with private key password and ca cert"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
interface_name: veth2
|
||||
state: up
|
||||
type: ethernet
|
||||
ip:
|
||||
address:
|
||||
- 203.0.113.2/24
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
ieee802_1x:
|
||||
identity: myhost
|
||||
eap: tls
|
||||
private_key: /etc/pki/tls/client.key
|
||||
private_key_password: test
|
||||
private_key_password_flags:
|
||||
- none
|
||||
client_cert: /etc/pki/tls/client.pem
|
||||
ca_cert: /etc/pki/tls/cacert.pem
|
||||
- name: "TEST: I can ping the EAP server"
|
||||
command: ping -c1 203.0.113.1
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: >-
|
||||
TEST: 802.1x profile with unencrypted private key,
|
||||
domain suffix match, and system ca certs
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- name: Copy cacert to system truststore
|
||||
copy:
|
||||
src: cacert.pem
|
||||
dest: /etc/pki/ca-trust/source/anchors/cacert.pem
|
||||
mode: 0644
|
||||
- name: Update ca trust
|
||||
command: update-ca-trust
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
interface_name: veth2
|
||||
state: up
|
||||
type: ethernet
|
||||
ip:
|
||||
address:
|
||||
- 203.0.113.2/24
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
ieee802_1x:
|
||||
identity: myhost
|
||||
eap: tls
|
||||
private_key: /etc/pki/tls/client.key.nocrypt
|
||||
client_cert: /etc/pki/tls/client.pem
|
||||
private_key_password_flags:
|
||||
- not-required
|
||||
system_ca_certs: True
|
||||
domain_suffix_match: example.com
|
||||
- name: "TEST: I can ping the EAP server"
|
||||
command: ping -c1 203.0.113.1
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
|
||||
- include_tasks: tasks/test_802.1x_capath.yml
|
||||
always:
|
||||
- block:
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: br1
|
||||
persistent_state: absent
|
||||
state: down
|
||||
ignore_errors: true
|
||||
- include_tasks: tasks/cleanup_802_1x_server.yml
|
||||
- name: Remove test certificates
|
||||
file:
|
||||
state: absent
|
||||
path: "/etc/pki/tls/{{ item }}"
|
||||
with_items:
|
||||
- client.key
|
||||
- client.key.nocrypt
|
||||
- client.pem
|
||||
- cacert.pem
|
||||
- name: Remove test CA
|
||||
file:
|
||||
state: absent
|
||||
path: "{{ item }}"
|
||||
with_items:
|
||||
- /etc/pki/tls/my_ca_certs
|
||||
- /etc/pki/ca-trust/source/anchors/cacert.pem
|
||||
- name: Update ca trust
|
||||
command: update-ca-trust
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
@@ -0,0 +1,13 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- name: Update NetworkManager
|
||||
package:
|
||||
name: NetworkManager
|
||||
state: latest
|
||||
- name: Restart NetworkManager
|
||||
service:
|
||||
name: NetworkManager
|
||||
state: restarted
|
||||
- import_playbook: tests_802_1x.yml
|
||||
@@ -0,0 +1,97 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
controller_profile: bond0
|
||||
controller_device: nm-bond
|
||||
port1_profile: bond0.0
|
||||
dhcp_interface1: test1
|
||||
port2_profile: bond0.1
|
||||
dhcp_interface2: test2
|
||||
tasks:
|
||||
- name: "INIT Prepare setup"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_tasks: tasks/create_test_interfaces_with_dhcp.yml
|
||||
- import_tasks: tasks/assert_device_present.yml
|
||||
vars:
|
||||
interface: "{{ dhcp_interface1 }}"
|
||||
- import_tasks: tasks/assert_device_present.yml
|
||||
vars:
|
||||
interface: "{{ dhcp_interface2 }}"
|
||||
- block:
|
||||
- name: "TEST Add Bond with 2 ports"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
# Create a bond controller
|
||||
- name: "{{ controller_profile }}"
|
||||
state: up
|
||||
type: bond
|
||||
interface_name: "{{ controller_device }}"
|
||||
bond:
|
||||
mode: active-backup
|
||||
miimon: 110
|
||||
# add an ethernet to the bond
|
||||
- name: "{{ port1_profile }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: "{{ dhcp_interface1 }}"
|
||||
controller: "{{ controller_profile }}"
|
||||
# add a second ethernet to the bond
|
||||
- name: "{{ port2_profile }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: "{{ dhcp_interface2 }}"
|
||||
controller: "{{ controller_profile }}"
|
||||
- import_tasks: tasks/assert_device_present.yml
|
||||
vars:
|
||||
interface: "{{ controller_device }}"
|
||||
- include_tasks: tasks/assert_profile_present.yml
|
||||
vars:
|
||||
profile: "{{ item }}"
|
||||
loop:
|
||||
- "{{ controller_profile }}"
|
||||
- "{{ port1_profile }}"
|
||||
- "{{ port2_profile }}"
|
||||
- command: grep 'Polling Interval'
|
||||
/proc/net/bonding/{{ controller_device }}
|
||||
name: "** TEST check polling interval"
|
||||
register: result
|
||||
until: "'110' in result.stdout"
|
||||
- command: ip -4 a s {{ controller_device }}
|
||||
name: "** TEST check IPv4"
|
||||
register: result
|
||||
until: "'192.0.2' in result.stdout"
|
||||
retries: 20
|
||||
delay: 2
|
||||
- command: ip -6 a s {{ controller_device }}
|
||||
name: "** TEST check IPv6"
|
||||
register: result
|
||||
until: "'2001' in result.stdout"
|
||||
retries: 20
|
||||
delay: 2
|
||||
always:
|
||||
- block:
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ port2_profile }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: "{{ port1_profile }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: "{{ controller_profile }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
ignore_errors: true
|
||||
- command: ip link del {{ controller_device }}
|
||||
ignore_errors: true
|
||||
- import_tasks: tasks/remove_test_interfaces_with_dhcp.yml
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
@@ -0,0 +1,97 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
controller_profile: bond0
|
||||
controller_device: nm-bond
|
||||
port1_profile: bond0.0
|
||||
dhcp_interface1: test1
|
||||
port2_profile: bond0.1
|
||||
dhcp_interface2: test2
|
||||
tasks:
|
||||
- name: "INIT Prepare setup"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_tasks: tasks/create_test_interfaces_with_dhcp.yml
|
||||
- import_tasks: tasks/assert_device_present.yml
|
||||
vars:
|
||||
interface: "{{ dhcp_interface1 }}"
|
||||
- import_tasks: tasks/assert_device_present.yml
|
||||
vars:
|
||||
interface: "{{ dhcp_interface2 }}"
|
||||
- block:
|
||||
- name: "TEST Add Bond with 2 ports using deprecated 'master' argument"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
# Create a bond controller
|
||||
- name: "{{ controller_profile }}"
|
||||
state: up
|
||||
type: bond
|
||||
interface_name: "{{ controller_device }}"
|
||||
bond:
|
||||
mode: active-backup
|
||||
miimon: 110
|
||||
# add an ethernet to the bond
|
||||
- name: "{{ port1_profile }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: "{{ dhcp_interface1 }}"
|
||||
master: "{{ controller_profile }}"
|
||||
# add a second ethernet to the bond
|
||||
- name: "{{ port2_profile }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
interface_name: "{{ dhcp_interface2 }}"
|
||||
master: "{{ controller_profile }}"
|
||||
- import_tasks: tasks/assert_device_present.yml
|
||||
vars:
|
||||
interface: "{{ controller_device }}"
|
||||
- include_tasks: tasks/assert_profile_present.yml
|
||||
vars:
|
||||
profile: "{{ item }}"
|
||||
loop:
|
||||
- "{{ controller_profile }}"
|
||||
- "{{ port1_profile }}"
|
||||
- "{{ port2_profile }}"
|
||||
- command: grep 'Polling Interval'
|
||||
/proc/net/bonding/{{ controller_device }}
|
||||
name: "** TEST check polling interval"
|
||||
register: result
|
||||
until: "'110' in result.stdout"
|
||||
- command: ip -4 a s {{ controller_device }}
|
||||
name: "** TEST check IPv4"
|
||||
register: result
|
||||
until: "'192.0.2' in result.stdout"
|
||||
retries: 20
|
||||
delay: 2
|
||||
- command: ip -6 a s {{ controller_device }}
|
||||
name: "** TEST check IPv6"
|
||||
register: result
|
||||
until: "'2001' in result.stdout"
|
||||
retries: 20
|
||||
delay: 2
|
||||
always:
|
||||
- block:
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ port2_profile }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: "{{ port1_profile }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: "{{ controller_profile }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
ignore_errors: true
|
||||
- command: ip link del {{ controller_device }}
|
||||
ignore_errors: true
|
||||
- import_tasks: tasks/remove_test_interfaces_with_dhcp.yml
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
@@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Test configuring bridges
|
||||
hosts: all
|
||||
vars:
|
||||
interface: LSR-TST-br31
|
||||
|
||||
tasks:
|
||||
- name: "set interface={{ interface }}"
|
||||
set_fact:
|
||||
interface: "{{ interface }}"
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/assert_device_absent.yml
|
||||
|
||||
- name: Add test bridge
|
||||
hosts: all
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
interface_name: "{{ interface }}"
|
||||
state: up
|
||||
type: bridge
|
||||
ip:
|
||||
dhcp4: no
|
||||
auto6: yes
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
|
||||
- import_playbook: run_tasks.yml
|
||||
vars:
|
||||
task: tasks/assert_device_present.yml
|
||||
|
||||
- import_playbook: run_tasks.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
task: tasks/assert_profile_present.yml
|
||||
|
||||
- import_playbook: down_profile.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
# FIXME: assert profile/device down
|
||||
|
||||
- import_playbook: remove_profile.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
|
||||
- import_playbook: run_tasks.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
task: tasks/assert_profile_absent.yml
|
||||
|
||||
# FIXME: Devices might still be left when profile is absent
|
||||
# - import_playbook: run_tasks.yml
|
||||
# vars:
|
||||
# task: tasks/assert_device_absent.yml
|
||||
@@ -0,0 +1,82 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# This test is supposed to check that checkpoints are properly cleaned-up after
|
||||
# failures in the module. This test currently uses the initscripts provider to
|
||||
# mark a device as unmanaged for NM and then tries to activiate it using NM.
|
||||
# This failed without removing the checkpoint.
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: cptstbr
|
||||
profile: "{{ interface }}"
|
||||
network_provider: nm
|
||||
pre_tasks:
|
||||
- debug:
|
||||
msg: Inside states tests
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/assert_device_absent.yml
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
tasks:
|
||||
- block:
|
||||
# Workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1832897
|
||||
- package:
|
||||
name: dbus-tools
|
||||
state: present
|
||||
# create test profile
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_provider: initscripts
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: bridge
|
||||
ip:
|
||||
dhcp4: false
|
||||
auto6: false
|
||||
- include_tasks: tasks/assert_device_present.yml
|
||||
- include_tasks: tasks/assert_profile_present.yml
|
||||
# Use internal module directly for speedup
|
||||
- network_connections:
|
||||
provider: nm
|
||||
connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: bridge
|
||||
ip:
|
||||
dhcp4: false
|
||||
auto6: false
|
||||
ignore_errors: true
|
||||
register: error_trigger
|
||||
- assert:
|
||||
fail_msg: The module call did not fail. Therefore the test
|
||||
condition was not triggered. This test needs to be adjusted or
|
||||
dropped.
|
||||
that: error_trigger.failed
|
||||
# yamllint disable-line rule:line-length
|
||||
- command: busctl --system tree --list org.freedesktop.NetworkManager
|
||||
register: nm_dbus_objects
|
||||
- debug:
|
||||
var: nm_dbus_objects
|
||||
- name: Assert that no checkpoints are left
|
||||
assert:
|
||||
fail_msg: Checkpoints not cleaned up
|
||||
that: >
|
||||
'/org/freedesktop/NetworkManager/Checkpoint/' not in
|
||||
nm_dbus_objects.stdout_lines
|
||||
always:
|
||||
- block:
|
||||
# Use internal module directly for speedup
|
||||
- network_connections:
|
||||
provider: nm
|
||||
connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- file:
|
||||
dest: "/etc/sysconfig/network-scripts/ifcfg-{{ interface }}"
|
||||
state: absent
|
||||
- command: ip link del "{{ interface }}"
|
||||
ignore_errors: true
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
@@ -0,0 +1,30 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: dummy0
|
||||
profile: "{{ interface }}"
|
||||
lsr_fail_debug:
|
||||
- __network_connections_result
|
||||
tasks:
|
||||
- debug:
|
||||
msg: "this is: playbooks/tests_dummy.yml"
|
||||
tags:
|
||||
- always
|
||||
|
||||
- block:
|
||||
- include_tasks: tasks/run_test.yml
|
||||
vars:
|
||||
lsr_description: Create a dummy interface
|
||||
lsr_setup:
|
||||
- tasks/delete_interface.yml
|
||||
- tasks/assert_device_absent.yml
|
||||
lsr_test:
|
||||
- tasks/create_dummy_profile.yml
|
||||
lsr_assert:
|
||||
- tasks/assert_profile_present.yml
|
||||
- tasks/assert_device_present.yml
|
||||
lsr_cleanup:
|
||||
- tasks/cleanup_profile+device.yml
|
||||
tags:
|
||||
- tests::dummy:create
|
||||
@@ -0,0 +1,110 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
|
||||
- name: Test configuring ethernet devices
|
||||
hosts: all
|
||||
vars:
|
||||
type: veth
|
||||
interface: ethtest0
|
||||
|
||||
|
||||
tasks:
|
||||
- name: "set type={{ type }} and interface={{ interface }}"
|
||||
set_fact:
|
||||
type: "{{ type }}"
|
||||
interface: "{{ interface }}"
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- include_tasks: tasks/assert_device_present.yml
|
||||
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
interface_name: "{{ interface }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
autoconnect: yes
|
||||
ip:
|
||||
route_metric4: 100
|
||||
dhcp4: no
|
||||
gateway4: 192.0.2.1
|
||||
dns:
|
||||
- 192.0.2.2
|
||||
- 198.51.100.5
|
||||
dns_search:
|
||||
- example.com
|
||||
- example.org
|
||||
dns_options:
|
||||
- rotate
|
||||
- timeout:1
|
||||
|
||||
route_metric6: -1
|
||||
auto6: no
|
||||
gateway6: 2001:db8::1
|
||||
|
||||
address:
|
||||
- 192.0.2.3/24
|
||||
- 198.51.100.3/26
|
||||
- 2001:db8::80/7
|
||||
|
||||
route:
|
||||
- network: 198.51.100.128
|
||||
prefix: 26
|
||||
gateway: 198.51.100.1
|
||||
metric: 2
|
||||
- network: 198.51.100.64
|
||||
prefix: 26
|
||||
gateway: 198.51.100.6
|
||||
metric: 4
|
||||
route_append_only: no
|
||||
rule_append_only: yes
|
||||
|
||||
- name: Verify nmcli connection DNS entry
|
||||
shell: |
|
||||
set -euxo pipefail
|
||||
nmcli connection show {{ interface }} | grep ipv4.dns
|
||||
register: ipv4_dns
|
||||
ignore_errors: yes
|
||||
|
||||
- name: "Assert that DNS addresses are configured correctly"
|
||||
assert:
|
||||
that:
|
||||
- "'192.0.2.2' in ipv4_dns.stdout"
|
||||
- "'198.51.100.5' in ipv4_dns.stdout"
|
||||
msg: "DNS addresses are configured incorrectly"
|
||||
|
||||
- name: "Assert that DNS search domains are configured correctly"
|
||||
assert:
|
||||
that:
|
||||
- "'example.com' in ipv4_dns.stdout"
|
||||
- "'example.org' in ipv4_dns.stdout"
|
||||
msg: "DNS search domains are configured incorrectly"
|
||||
|
||||
- name: "Assert that DNS options are configured correctly"
|
||||
assert:
|
||||
that:
|
||||
- "'rotate' in ipv4_dns.stdout"
|
||||
- "'timeout:1' in ipv4_dns.stdout"
|
||||
msg: "DNS options are configured incorrectly"
|
||||
|
||||
- import_playbook: down_profile.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
# FIXME: assert profile/device down
|
||||
- import_playbook: remove_profile.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
# FIXME: assert profile away
|
||||
- name: Remove interfaces
|
||||
hosts: all
|
||||
tasks:
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: absent
|
||||
- include_tasks: tasks/assert_device_absent.yml
|
||||
...
|
||||
@@ -0,0 +1,64 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- debug:
|
||||
msg: Inside ethernet tests
|
||||
- debug:
|
||||
var: network_provider
|
||||
|
||||
- name: Test configuring ethernet devices
|
||||
hosts: all
|
||||
vars:
|
||||
type: veth
|
||||
interface: lsr27
|
||||
|
||||
tasks:
|
||||
- name: "set type={{ type }} and interface={{ interface }}"
|
||||
set_fact:
|
||||
type: "{{ type }}"
|
||||
interface: "{{ interface }}"
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- include_tasks: tasks/assert_device_present.yml
|
||||
|
||||
- name: Test static interface up
|
||||
hosts: all
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
interface_name: "{{ interface }}"
|
||||
state: up
|
||||
type: ethernet
|
||||
autoconnect: yes
|
||||
ip:
|
||||
address: 192.0.2.1/24
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
tasks:
|
||||
- include_tasks: tasks/assert_output_in_stderr_without_warnings.yml
|
||||
|
||||
- hosts: all
|
||||
tasks:
|
||||
- debug:
|
||||
var: network_provider
|
||||
|
||||
# FIXME: assert profile present
|
||||
# FIXME: assert profile/device up + IP address
|
||||
- import_playbook: down_profile.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
# FIXME: assert profile/device down
|
||||
- import_playbook: remove_profile.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
# FIXME: assert profile away
|
||||
- name: Remove interfaces
|
||||
hosts: all
|
||||
tasks:
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: absent
|
||||
- include_tasks: tasks/assert_device_absent.yml
|
||||
@@ -0,0 +1,102 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: testnic1
|
||||
type: veth
|
||||
tasks:
|
||||
- debug:
|
||||
msg: "this is: playbooks/tests_ethtool_.coalesceyml"
|
||||
tags:
|
||||
- always
|
||||
|
||||
- name: "INIT: Ethtool coalesce tests"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- include_tasks: tasks/assert_device_present.yml
|
||||
- name: Install ethtool (test dependency)
|
||||
package:
|
||||
name: ethtool
|
||||
state: present
|
||||
|
||||
- block:
|
||||
- name: >-
|
||||
TEST: I can create a profile without any coalescing option.
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
type: ethernet
|
||||
autoconnect: no
|
||||
ip:
|
||||
dhcp4: no
|
||||
auto6: no
|
||||
- name: Get profile's coalescing options
|
||||
command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface }}
|
||||
register: no_coalesce
|
||||
- name: "ASSERT: The profile does not contain coalescing options"
|
||||
assert:
|
||||
that: no_coalesce.stdout == ""
|
||||
- name: >-
|
||||
TEST: I can set rx-frames.
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
type: ethernet
|
||||
autoconnect: no
|
||||
ip:
|
||||
dhcp4: no
|
||||
auto6: no
|
||||
ethtool:
|
||||
coalesce:
|
||||
rx_frames: 128
|
||||
- name: Get profile's coalescing options
|
||||
command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface }}
|
||||
register: with_coalesce
|
||||
- name: Assert coalesce options set in profile
|
||||
assert:
|
||||
that: with_coalesce.stdout == '128'
|
||||
- name: "TEST: I can clear coalescing options"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
type: ethernet
|
||||
autoconnect: no
|
||||
ip:
|
||||
dhcp4: no
|
||||
auto6: no
|
||||
- name: Get profile's coalescing options
|
||||
command: nmcli -g ethtool.coalesce-rx-frames c show {{ interface }}
|
||||
register: profile
|
||||
- name: "ASSERT: The profile does reset coalescing options"
|
||||
assert:
|
||||
that: no_coalesce.stdout == ""
|
||||
always:
|
||||
- block:
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
ignore_errors: true
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: absent
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
@@ -0,0 +1,94 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
type: veth
|
||||
interface: veth0
|
||||
tasks:
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- name: Set up gateway ip on veth peer
|
||||
shell: |
|
||||
ip netns add ns1
|
||||
ip link set peer{{ interface }} netns ns1
|
||||
ip netns exec ns1 ip -6 addr add 2001:db8::1/32 dev peer{{ interface }}
|
||||
ip netns exec ns1 ip link set peer{{ interface }} up
|
||||
when:
|
||||
# netns not available on RHEL/CentOS 6
|
||||
- ansible_distribution_major_version != '6'
|
||||
- block:
|
||||
- name: >-
|
||||
TEST: I can configure an interface with static ipv6 config
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
type: ethernet
|
||||
state: up
|
||||
ip:
|
||||
dhcp4: false
|
||||
auto6: false
|
||||
address:
|
||||
- "2001:db8::2/32"
|
||||
- "2001:db8::3/32"
|
||||
- "2001:db8::4/32"
|
||||
gateway6: "2001:db8::1"
|
||||
- include_tasks: tasks/assert_device_present.yml
|
||||
- include_tasks: tasks/assert_profile_present.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
- name: Get ip address information
|
||||
command: "ip addr show {{ interface }}"
|
||||
register: ip_addr
|
||||
- name:
|
||||
debug:
|
||||
var: ip_addr.stdout
|
||||
- name: Assert ipv6 addresses are correctly set
|
||||
assert:
|
||||
that:
|
||||
- >-
|
||||
'inet6 2001:db8::2/32' in ip_addr.stdout
|
||||
- >-
|
||||
'inet6 2001:db8::3/32' in ip_addr.stdout
|
||||
- >-
|
||||
'inet6 2001:db8::4/32' in ip_addr.stdout
|
||||
- name: Get ipv6 routes
|
||||
command: "ip -6 route"
|
||||
register: ipv6_route
|
||||
- name:
|
||||
debug:
|
||||
var: ipv6_route.stdout
|
||||
- name: Assert default ipv6 route is set
|
||||
assert:
|
||||
that:
|
||||
- >-
|
||||
"default via 2001:db8::1 dev {{ interface }}"
|
||||
in ipv6_route.stdout
|
||||
- name: Test gateway can be pinged
|
||||
command: ping6 -c1 2001:db8::1
|
||||
when:
|
||||
- ansible_distribution_major_version != '6'
|
||||
always:
|
||||
- name: "TEARDOWN: remove profiles."
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
ignore_errors: true
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: absent
|
||||
- name: Clean up namespace
|
||||
command: ip netns delete ns1
|
||||
when:
|
||||
- ansible_distribution_major_version != '6'
|
||||
@@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
|
||||
- name: Test configuring ethernet devices
|
||||
hosts: all
|
||||
vars:
|
||||
type: veth
|
||||
interface: ethtest0
|
||||
|
||||
tasks:
|
||||
- name: "set type={{ type }} and interface={{ interface }}"
|
||||
set_fact:
|
||||
type: "{{ type }}"
|
||||
interface: "{{ interface }}"
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- include_tasks: tasks/assert_device_present.yml
|
||||
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
interface_name: "{{ interface }}"
|
||||
type: ethernet
|
||||
ip:
|
||||
ipv6_disabled: true
|
||||
|
||||
- name: Verify nmcli connection ipv6.method
|
||||
shell: |
|
||||
set -euxo pipefail
|
||||
nmcli connection show {{ interface }} | grep ipv6.method
|
||||
register: ipv6_method
|
||||
ignore_errors: yes
|
||||
|
||||
- name: "Assert that ipv6.method disabled is configured correctly"
|
||||
assert:
|
||||
that:
|
||||
- "'disabled' in ipv6_method.stdout"
|
||||
msg: "ipv6.method disabled is configured incorrectly"
|
||||
|
||||
- import_playbook: down_profile.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
# FIXME: assert profile/device down
|
||||
- import_playbook: remove_profile.yml
|
||||
vars:
|
||||
profile: "{{ interface }}"
|
||||
# FIXME: assert profile away
|
||||
- name: Remove interfaces
|
||||
hosts: all
|
||||
tasks:
|
||||
- include_tasks: tasks/manage_test_interface.yml
|
||||
vars:
|
||||
state: absent
|
||||
- include_tasks: tasks/assert_device_absent.yml
|
||||
...
|
||||
@@ -0,0 +1,35 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: testnic1
|
||||
profile: "{{ interface }}"
|
||||
lsr_fail_debug:
|
||||
- __network_connections_result
|
||||
tasks:
|
||||
- debug:
|
||||
msg: "this is: playbooks/tests_states.yml"
|
||||
tags:
|
||||
- always
|
||||
|
||||
|
||||
- block:
|
||||
- include_tasks: tasks/run_test.yml
|
||||
vars:
|
||||
state: present
|
||||
lsr_description: I can manage a veth interface with NM after I
|
||||
managed it with initscripts.
|
||||
lsr_setup:
|
||||
- tasks/setup_test_interface.yml
|
||||
# run role once with defaults but nm provider to ensure that
|
||||
# NetworKManager is running
|
||||
- tasks/provider/default_with_nm.yml
|
||||
- tasks/provider/create_and_remove_with_initscripts.yml
|
||||
lsr_test:
|
||||
- tasks/provider/create_with_nm.yml
|
||||
lsr_assert:
|
||||
- tasks/assert_profile_present.yml
|
||||
lsr_cleanup:
|
||||
- tasks/cleanup_profile+device.yml
|
||||
tags:
|
||||
- tests::provider:initscripts_to_nm
|
||||
@@ -0,0 +1,66 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# This test should check whether the NMDevice.reapply method is called by the
|
||||
# role. This is probably a good candidate to test with pytest directly instead
|
||||
# of via Ansible. Until there is better test support for this, just check the
|
||||
# log output for the respective log message.
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: rpltstbr
|
||||
profile: "{{ interface }}"
|
||||
network_provider: nm
|
||||
pre_tasks:
|
||||
- debug:
|
||||
msg: Inside states tests
|
||||
- include_tasks: tasks/show_interfaces.yml
|
||||
- include_tasks: tasks/assert_device_absent.yml
|
||||
roles:
|
||||
- linux-system-roles.network
|
||||
tasks:
|
||||
- block:
|
||||
# create test profile
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: bridge
|
||||
ip:
|
||||
dhcp4: false
|
||||
auto6: false
|
||||
- include_tasks: tasks/assert_device_present.yml
|
||||
- include_tasks: tasks/assert_profile_present.yml
|
||||
# Use internal module to get output
|
||||
- network_connections:
|
||||
provider: nm
|
||||
connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: bridge
|
||||
ip:
|
||||
address:
|
||||
- 192.0.2.72/31
|
||||
dhcp4: false
|
||||
auto6: false
|
||||
ignore_errors: true
|
||||
register: test_module_run
|
||||
- debug:
|
||||
var: test_module_run
|
||||
- name: Assert that reapply is found in log output
|
||||
assert:
|
||||
fail_msg: Reapply not found in log output
|
||||
that: "{{ 'connection reapplied' in test_module_run.stderr }}"
|
||||
always:
|
||||
- block:
|
||||
# Use internal module directly for speedup
|
||||
- network_connections:
|
||||
provider: nm
|
||||
connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- command: ip link del "{{ interface }}"
|
||||
ignore_errors: true
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
@@ -0,0 +1,30 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: team0
|
||||
profile: "{{ interface }}"
|
||||
lsr_fail_debug:
|
||||
- __network_connections_result
|
||||
tasks:
|
||||
- debug:
|
||||
msg: "this is: playbooks/tests_team.yml"
|
||||
tags:
|
||||
- always
|
||||
|
||||
- block:
|
||||
- include_tasks: tasks/run_test.yml
|
||||
vars:
|
||||
lsr_description: Create a team interface without any port attached
|
||||
lsr_setup:
|
||||
- tasks/delete_interface.yml
|
||||
- tasks/assert_device_absent.yml
|
||||
lsr_test:
|
||||
- tasks/create_team_profile.yml
|
||||
lsr_assert:
|
||||
- tasks/assert_profile_present.yml
|
||||
- tasks/assert_device_present.yml
|
||||
lsr_cleanup:
|
||||
- tasks/cleanup_profile+device.yml
|
||||
tags:
|
||||
- tests::team:create
|
||||
@@ -0,0 +1,40 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- name: remove the NetworkManager-team package
|
||||
package:
|
||||
name: "NetworkManager-team"
|
||||
state: absent
|
||||
|
||||
- name: "get the rpm package facts"
|
||||
package_facts:
|
||||
manager: "auto"
|
||||
|
||||
- name: "Assert NetworkManager-team removed before team configuration"
|
||||
assert:
|
||||
that:
|
||||
- "'NetworkManager-team' not in ansible_facts.packages"
|
||||
msg: "NetworkManager-team is not removed before team configuration"
|
||||
|
||||
- name: "Team interface configuration"
|
||||
include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
# Specify the team profile
|
||||
- name: team0
|
||||
persistent_state: present
|
||||
type: team
|
||||
interface_name: team0
|
||||
|
||||
- name: "get the rpm package facts"
|
||||
package_facts:
|
||||
manager: "auto"
|
||||
|
||||
- name: "Assert NetworkManager-team is installed after team configuration"
|
||||
assert:
|
||||
that:
|
||||
- "'NetworkManager-team' in ansible_facts.packages"
|
||||
msg: "NetworkManager-team is not installed after team configuration"
|
||||
...
|
||||
@@ -0,0 +1,88 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
interface: wlan0
|
||||
tasks:
|
||||
- name: "INIT: wireless tests"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- include_tasks: tasks/setup_mock_wifi.yml
|
||||
- name: Copy client certs
|
||||
copy:
|
||||
src: "{{ item }}"
|
||||
dest: "/etc/pki/tls/{{ item }}"
|
||||
mode: 0644
|
||||
with_items:
|
||||
- client.key
|
||||
- client.pem
|
||||
- cacert.pem
|
||||
- block:
|
||||
- name: "TEST: wireless connection with WPA-PSK"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_allow_restart: true
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: wireless
|
||||
ip:
|
||||
address:
|
||||
- 203.0.113.2/24
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
wireless:
|
||||
ssid: "mock_wifi"
|
||||
key_mgmt: "wpa-psk"
|
||||
password: "p@55w0rD"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
- name: "TEST: wireless connection with 802.1x TLS-EAP"
|
||||
debug:
|
||||
msg: "##################################################"
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_allow_restart: true
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: wireless
|
||||
ip:
|
||||
address:
|
||||
- 203.0.113.2/24
|
||||
dhcp4: "no"
|
||||
auto6: "no"
|
||||
wireless:
|
||||
ssid: "mock_wifi"
|
||||
key_mgmt: "wpa-eap"
|
||||
ieee802_1x:
|
||||
identity: myhost
|
||||
eap: tls
|
||||
private_key: /etc/pki/tls/client.key
|
||||
private_key_password: test
|
||||
private_key_password_flags:
|
||||
- none
|
||||
client_cert: /etc/pki/tls/client.pem
|
||||
ca_cert: /etc/pki/tls/cacert.pem
|
||||
always:
|
||||
- block:
|
||||
- import_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: absent
|
||||
state: down
|
||||
ignore_errors: true
|
||||
- include_tasks: tasks/cleanup_mock_wifi.yml
|
||||
tags:
|
||||
- "tests::cleanup"
|
||||
@@ -0,0 +1,40 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- name: remove the NetworkManager-wifi package
|
||||
package:
|
||||
name: "NetworkManager-wifi"
|
||||
state: absent
|
||||
|
||||
- name: "get the rpm package facts"
|
||||
package_facts:
|
||||
manager: "auto"
|
||||
|
||||
- name: "Assert NetworkManager-wifi removed before wireless configuration"
|
||||
assert:
|
||||
that:
|
||||
- "'NetworkManager-wifi' not in ansible_facts.packages"
|
||||
msg: "NetworkManager-wifi is not removed before wirelss configuration"
|
||||
|
||||
- name: "wireless configuration"
|
||||
include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: wlan0
|
||||
type: wireless
|
||||
wireless:
|
||||
ssid: "My WPA2-PSK Network"
|
||||
key_mgmt: "wpa-psk"
|
||||
password: "p@55w0rD"
|
||||
|
||||
- name: "get the rpm package facts"
|
||||
package_facts:
|
||||
manager: "auto"
|
||||
|
||||
- name: "Assert NetworkManager-wifi installed after wireless configuration"
|
||||
assert:
|
||||
that:
|
||||
- "'NetworkManager-wifi' in ansible_facts.packages"
|
||||
msg: "NetworkManager-wifi is not installed after wireless configured"
|
||||
41
roles/linux-system-roles.network/tests/setup_module_utils.sh
Executable file
41
roles/linux-system-roles.network/tests/setup_module_utils.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ -n "${DEBUG:-}" ] ; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
if [ ! -d "${1:-}" ] ; then
|
||||
echo Either ansible is not installed, or there is no ansible/module_utils
|
||||
echo in $1 - Skipping
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ! -d "${2:-}" ] ; then
|
||||
echo Role has no module_utils - Skipping
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# we need absolute path for $2
|
||||
absmoddir=$( readlink -f "$2" )
|
||||
|
||||
# clean up old links to module_utils
|
||||
for item in "$1"/* ; do
|
||||
if lnitem=$( readlink "$item" ) && test -n "$lnitem" ; then
|
||||
case "$lnitem" in
|
||||
*"${2}"*) rm -f "$item" ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
|
||||
# add new links to module_utils
|
||||
for item in "$absmoddir"/* ; do
|
||||
case "$item" in
|
||||
*__pycache__) continue;;
|
||||
*.pyc) continue;;
|
||||
esac
|
||||
bnitem=$( basename "$item" )
|
||||
ln -s "$item" "$1/$bnitem"
|
||||
done
|
||||
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
...
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include: get_interface_stat.yml
|
||||
- name: "assert that interface {{ interface }} is absent"
|
||||
assert:
|
||||
that: not interface_stat.stat.exists
|
||||
msg: "{{ interface }} exists"
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include: get_interface_stat.yml
|
||||
- name: "assert that interface {{ interface }} is present"
|
||||
assert:
|
||||
that: interface_stat.stat.exists
|
||||
msg: "{{ interface }} does not exist"
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: "Assert that warnings is empty"
|
||||
assert:
|
||||
that:
|
||||
- "'warnings' not in __network_connections_result"
|
||||
msg: "There are unexpected warnings"
|
||||
- name: "Assert that there is output in stderr"
|
||||
assert:
|
||||
that:
|
||||
- "'stderr' in __network_connections_result"
|
||||
msg: "There are no messages in stderr"
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include: get_profile_stat.yml
|
||||
- name: "assert that profile '{{ profile }}' is absent"
|
||||
assert:
|
||||
that: not lsr_net_profile_exists
|
||||
msg: "profile {{ profile }} does exist"
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include: get_profile_stat.yml
|
||||
- name: "assert that profile '{{ profile }}' is present"
|
||||
assert:
|
||||
that: lsr_net_profile_exists
|
||||
msg: "profile {{ profile }} does not exist"
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Remove test interfaces
|
||||
shell: |
|
||||
ip netns delete ns1
|
||||
ip link delete veth1-br
|
||||
ip link delete veth2-br
|
||||
ip link delete br1
|
||||
|
||||
- name: Kill hostapd process
|
||||
shell: pkill hostapd
|
||||
- name: Remove certs and config
|
||||
file:
|
||||
state: absent
|
||||
path: "{{ item }}"
|
||||
with_items:
|
||||
- /etc/pki/tls/hostapd_test
|
||||
- /etc/hostapd/wired.conf
|
||||
- /etc/hostapd/hostapd.eap_user
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- name: Unload mac80211_hwsim module
|
||||
shell: modprobe -r mac80211_hwsim
|
||||
|
||||
- name: Kill hostapd process
|
||||
shell: pkill hostapd
|
||||
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- shell: |
|
||||
nmcli con delete {{ interface }}
|
||||
nmcli con load /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
|
||||
rm -f /etc/sysconfig/network-scripts/ifcfg-{{ interface }}
|
||||
ip link del {{ interface }}
|
||||
ignore_errors: true
|
||||
...
|
||||
@@ -0,0 +1,20 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include_tasks: show_interfaces.yml
|
||||
- include_tasks: manage_test_interface.yml
|
||||
vars:
|
||||
state: absent
|
||||
- include_tasks: show_interfaces.yml
|
||||
- include_tasks: assert_device_absent.yml
|
||||
|
||||
- include_tasks: manage_test_interface.yml
|
||||
vars:
|
||||
state: present
|
||||
- include_tasks: show_interfaces.yml
|
||||
- include_tasks: assert_device_present.yml
|
||||
|
||||
- include_tasks: manage_test_interface.yml
|
||||
vars:
|
||||
state: absent
|
||||
- include_tasks: show_interfaces.yml
|
||||
- include_tasks: assert_device_absent.yml
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: present
|
||||
type: bridge
|
||||
ip:
|
||||
dhcp4: false
|
||||
auto6: false
|
||||
- debug:
|
||||
var: __network_connections_result
|
||||
...
|
||||
@@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
autoconnect: false
|
||||
persistent_state: present
|
||||
type: bridge
|
||||
ip:
|
||||
dhcp4: false
|
||||
auto6: false
|
||||
- debug:
|
||||
var: __network_connections_result
|
||||
...
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
state: up
|
||||
type: dummy
|
||||
ip:
|
||||
address:
|
||||
- "192.0.2.42/30"
|
||||
- debug:
|
||||
var: __network_connections_result
|
||||
...
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
---
|
||||
- include_role:
|
||||
name: linux-system-roles.network
|
||||
vars:
|
||||
network_connections:
|
||||
- name: "{{ interface }}"
|
||||
persistent_state: present
|
||||
type: team
|
||||
ip:
|
||||
dhcp4: false
|
||||
auto6: false
|
||||
- debug:
|
||||
var: __network_connections_result
|
||||
...
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user