Build Windows Templates in RHV

This commit is contained in:
2021-05-03 13:47:44 -04:00
parent 595021d449
commit 28c9375b0d
290 changed files with 10931 additions and 159 deletions

View 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

View 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

View 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

View 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

View File

@@ -0,0 +1,5 @@
---
extraction:
python:
python_setup:
version: 2

View 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

View File

@@ -0,0 +1 @@
style '.mdl_style.rb'

View 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

View 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

View 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

View File

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

View 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!!*

View 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'

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

View 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

View File

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

View File

@@ -0,0 +1 @@
../tests/playbooks/down_profile.yml

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

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

View File

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

View File

@@ -0,0 +1 @@
../tests/playbooks/remove_profile.yml

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
# SPDX-License-Identifier: BSD-3-Clause
class LsrNetworkNmError(Exception):
pass

View File

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

View File

@@ -0,0 +1,3 @@
# SPDX-License-Identifier: MIT
# Write extra requirements for running molecule here:

View File

@@ -0,0 +1,5 @@
# SPDX-License-Identifier: MIT
# Write extra requirements for running pylint here:
mock
pytest

View File

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

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

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

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

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

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

View File

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

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

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

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

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

View 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}"

View 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

View 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"

View File

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

View File

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

View 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}"

View File

@@ -0,0 +1 @@
../module_utils/

View File

@@ -0,0 +1 @@
../library/

View File

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

View File

@@ -0,0 +1 @@
../files

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,6 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- name: Run the tasklist {{ task }}
hosts: all
tasks:
- include_tasks: "{{ task }}"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

@@ -0,0 +1,9 @@
# SPDX-License-Identifier: BSD-3-Clause
---
- include_role:
name: linux-system-roles.network
vars:
network_connections:
- name: "{{ interface }}"
state: up
...

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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