mirror of
https://github.com/ansible-collections/ansible.posix.git
synced 2026-03-26 21:33:32 +00:00
Compare commits
55 Commits
2.0.0
...
263ebd83f4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
263ebd83f4 | ||
|
|
2d2df3989e | ||
|
|
df8413f3a0 | ||
|
|
f434c19e1e | ||
|
|
481de3d2dc | ||
|
|
ae90bac688 | ||
|
|
80290d8e06 | ||
|
|
560afe8217 | ||
|
|
571e80cdba | ||
|
|
9ce933f7d0 | ||
|
|
7f8505d693 | ||
|
|
2f5210f362 | ||
|
|
a91bbf6c04 | ||
|
|
b96fad5e5b | ||
|
|
2d350e6073 | ||
|
|
ea6ef5c775 | ||
|
|
9007e20b2f | ||
|
|
508e3d920f | ||
|
|
18e023dd77 | ||
|
|
d3204df536 | ||
|
|
162e72182f | ||
|
|
1c1dd005c8 | ||
|
|
40c27e2bee | ||
|
|
c273ac2a01 | ||
|
|
f978998521 | ||
|
|
c319c856ed | ||
|
|
cdb442ea48 | ||
|
|
f977bffff2 | ||
|
|
dabaca4b70 | ||
|
|
26b9b1438d | ||
|
|
1994b2cf1c | ||
|
|
2f224e6a6a | ||
|
|
96ec2097cc | ||
|
|
7b9b1f4957 | ||
|
|
f0b5f039d3 | ||
|
|
5ceb40b600 | ||
|
|
2cec8cbed5 | ||
|
|
1b8aeb03cb | ||
|
|
eead50b287 | ||
|
|
4ff0e3aa13 | ||
|
|
979f00ce75 | ||
|
|
ed3d322fd5 | ||
|
|
d9f54eb9d4 | ||
|
|
7d8da00f79 | ||
|
|
f087d58cbe | ||
|
|
eb740e97d4 | ||
|
|
44a2151dbf | ||
|
|
83288b9020 | ||
|
|
6280bb8ec8 | ||
|
|
3b79155e68 | ||
|
|
05724a097b | ||
|
|
7e1b76c46e | ||
|
|
505a4aaa09 | ||
|
|
d70d2aaaa7 | ||
|
|
806ff5c1a3 |
@@ -3,8 +3,23 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
# SPDX-FileCopyrightText: 2024, Ansible Project
|
||||
|
||||
# Use a more permissive profile due to documentation parsing issues
|
||||
profile: min
|
||||
|
||||
skip_list:
|
||||
- meta-runtime[unsupported-version] # Tis rule doesn't make any sense
|
||||
- meta-runtime[unsupported-version] # This rule doesn't make any sense
|
||||
- fqcn[deep] # This rule produces false positives for files in tests/unit/plugins/action/fixtures/
|
||||
- no-relative-paths # Temporary skip due to documentation parsing issue
|
||||
- parser-error # Skip documentation parsing errors
|
||||
- syntax-check # Skip syntax check issues in documentation
|
||||
- load-failure # Skip module loading failures during documentation parsing
|
||||
- args # Skip argument validation errors in documentation
|
||||
|
||||
exclude_paths:
|
||||
- changelogs/
|
||||
|
||||
# Enable specific rules we want to keep
|
||||
enable_list:
|
||||
- yaml
|
||||
- name
|
||||
- var-naming
|
||||
|
||||
@@ -37,7 +37,7 @@ variables:
|
||||
resources:
|
||||
containers:
|
||||
- container: default
|
||||
image: quay.io/ansible/azure-pipelines-test-container:6.0.0
|
||||
image: quay.io/ansible/azure-pipelines-test-container:7.0.0
|
||||
|
||||
pool: Standard
|
||||
|
||||
@@ -57,8 +57,23 @@ stages:
|
||||
test: units
|
||||
- name: Lint
|
||||
test: lint
|
||||
- stage: Sanity_2_19
|
||||
displayName: Ansible 2.19 sanitay & Units & Lint
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: "{0}"
|
||||
testFormat: 2.19/{0}
|
||||
targets:
|
||||
- name: Sanity
|
||||
test: sanity
|
||||
- name: Units
|
||||
test: units
|
||||
- name: Lint
|
||||
test: lint
|
||||
- stage: Sanity_2_18
|
||||
displayName: Ansible 2.18 sanity
|
||||
displayName: Ansible 2.18 sanity & Units & Lint
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
@@ -73,7 +88,7 @@ stages:
|
||||
- name: Lint
|
||||
test: lint
|
||||
- stage: Sanity_2_17
|
||||
displayName: Ansible 2.17 sanity
|
||||
displayName: Ansible 2.17 sanity & Units & Lint
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
@@ -88,7 +103,7 @@ stages:
|
||||
- name: Lint
|
||||
test: lint
|
||||
- stage: Sanity_2_16
|
||||
displayName: Ansible 2.16 sanity
|
||||
displayName: Ansible 2.16 sanity & Units & Lint
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
@@ -100,19 +115,6 @@ stages:
|
||||
test: sanity
|
||||
- name: Units
|
||||
test: units
|
||||
- stage: Sanity_2_15
|
||||
displayName: Ansible 2.15 sanity
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
nameFormat: "{0}"
|
||||
testFormat: 2.15/{0}
|
||||
targets:
|
||||
- name: Sanity
|
||||
test: sanity
|
||||
- name: Units
|
||||
test: units
|
||||
## Docker
|
||||
- stage: Docker_devel
|
||||
displayName: Docker devel
|
||||
@@ -122,14 +124,28 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/linux/{0}/1
|
||||
targets:
|
||||
- name: Fedora 40
|
||||
test: fedora40
|
||||
- name: Fedora 42
|
||||
test: fedora42
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu2204
|
||||
- name: Ubuntu 24.04
|
||||
test: ubuntu2404
|
||||
- stage: Docker_2_19
|
||||
displayName: Docker 2.19
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.19/linux/{0}/1
|
||||
targets:
|
||||
- name: Fedora 41
|
||||
test: fedora41
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu2204
|
||||
- name: Ubuntu 24.04
|
||||
test: ubuntu2404
|
||||
- stage: Docker_2_18
|
||||
displayName: Docker devel
|
||||
displayName: Docker 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
@@ -152,8 +168,6 @@ stages:
|
||||
targets:
|
||||
- name: Fedora 39
|
||||
test: fedora39
|
||||
- name: Ubuntu 20.04
|
||||
test: ubuntu2004
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu2204
|
||||
- stage: Docker_2_16
|
||||
@@ -168,27 +182,6 @@ stages:
|
||||
test: centos7
|
||||
- name: Fedora 38
|
||||
test: fedora38
|
||||
- name: Ubuntu 20.04
|
||||
test: ubuntu2004
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu2204
|
||||
|
||||
- stage: Docker_2_15
|
||||
displayName: Docker 2.15
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.15/linux/{0}/1
|
||||
targets:
|
||||
- name: CentOS 7
|
||||
test: centos7
|
||||
- name: Fedora 37
|
||||
test: fedora37
|
||||
- name: openSUSE 15 py3
|
||||
test: opensuse15
|
||||
- name: Ubuntu 20.04
|
||||
test: ubuntu2004
|
||||
- name: Ubuntu 22.04
|
||||
test: ubuntu2204
|
||||
|
||||
@@ -201,14 +194,32 @@ stages:
|
||||
parameters:
|
||||
testFormat: devel/{0}/1
|
||||
targets:
|
||||
- name: RHEL 9.4
|
||||
test: rhel/9.4
|
||||
- name: FreeBSD 14.1
|
||||
test: freebsd/14.1
|
||||
- name: FreeBSD 13.4
|
||||
test: freebsd/13.4
|
||||
- name: RHEL 10.0
|
||||
test: rhel/10.0
|
||||
- name: RHEL 9.6
|
||||
test: rhel/9.6
|
||||
- name: FreeBSD 14.3
|
||||
test: freebsd/14.3
|
||||
- name: FreeBSD 13.5
|
||||
test: freebsd/13.5
|
||||
- stage: Remote_2_19
|
||||
displayName: Remote 2.19
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.19/{0}/1
|
||||
targets:
|
||||
- name: RHEL 10.0
|
||||
test: rhel/10.0
|
||||
- name: RHEL 9.5
|
||||
test: rhel/9.5
|
||||
- name: FreeBSD 14.2
|
||||
test: freebsd/14.2
|
||||
- name: FreeBSD 13.5
|
||||
test: freebsd/13.5
|
||||
- stage: Remote_2_18
|
||||
displayName: Remote devel
|
||||
displayName: Remote 2.18
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
@@ -217,8 +228,8 @@ stages:
|
||||
targets:
|
||||
- name: RHEL 9.4
|
||||
test: rhel/9.4
|
||||
- name: FreeBSD 13.3
|
||||
test: freebsd/13.3
|
||||
- name: FreeBSD 13.5
|
||||
test: freebsd/13.5
|
||||
- stage: Remote_2_17
|
||||
displayName: Remote 2.17
|
||||
dependsOn: []
|
||||
@@ -229,8 +240,8 @@ stages:
|
||||
targets:
|
||||
- name: RHEL 9.3
|
||||
test: rhel/9.3
|
||||
- name: FreeBSD 13.3
|
||||
test: freebsd/13.3
|
||||
- name: FreeBSD 13.5
|
||||
test: freebsd/13.5
|
||||
- stage: Remote_2_16
|
||||
displayName: Remote 2.16
|
||||
dependsOn: []
|
||||
@@ -243,34 +254,12 @@ stages:
|
||||
test: rhel/8.8
|
||||
- name: RHEL 9.2
|
||||
test: rhel/9.2
|
||||
- name: FreeBSD 13.2
|
||||
test: freebsd/13.2
|
||||
|
||||
- stage: Remote_2_15
|
||||
displayName: Remote 2.15
|
||||
dependsOn: []
|
||||
jobs:
|
||||
- template: templates/matrix.yml
|
||||
parameters:
|
||||
testFormat: 2.15/{0}/1
|
||||
targets:
|
||||
- name: RHEL 7.9
|
||||
test: rhel/7.9
|
||||
- name: RHEL 8.7
|
||||
test: rhel/8.7
|
||||
- name: RHEL 9.1
|
||||
test: rhel/9.1
|
||||
- name: FreeBSD 13.2
|
||||
test: freebsd/13.2
|
||||
|
||||
## Finally
|
||||
|
||||
- stage: Summary
|
||||
condition: succeededOrFailed()
|
||||
dependsOn:
|
||||
- Sanity_2_15
|
||||
- Remote_2_15
|
||||
- Docker_2_15
|
||||
- Sanity_2_16
|
||||
- Remote_2_16
|
||||
- Docker_2_16
|
||||
@@ -280,6 +269,9 @@ stages:
|
||||
- Sanity_2_18
|
||||
- Remote_2_18
|
||||
- Docker_2_18
|
||||
- Sanity_2_19
|
||||
- Remote_2_19
|
||||
- Docker_2_19
|
||||
- Sanity_devel
|
||||
- Remote_devel
|
||||
- Docker_devel
|
||||
|
||||
13
README.md
13
README.md
@@ -21,7 +21,7 @@ An Ansible Collection of modules and plugins that target POSIX UNIX/Linux and de
|
||||
* Python:
|
||||
* The Python interpreter version must meet Ansible Core's requirements.
|
||||
* Ansible Core:
|
||||
- ansible-core 2.15 or later
|
||||
- ansible-core 2.16 or later
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -46,10 +46,10 @@ To upgrade the collection to the latest available version, run the following com
|
||||
ansible-galaxy collection install ansible.posix --upgrade
|
||||
```
|
||||
|
||||
You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax to install version 1.0.0:
|
||||
You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax to install version 2.0.0:
|
||||
|
||||
```shell
|
||||
ansible-galaxy collection install ansible.posix:==1.0.0
|
||||
ansible-galaxy collection install ansible.posix:==2.0.0
|
||||
```
|
||||
|
||||
See [using Ansible collections](https://docs.ansible.com/ansible/devel/user_guide/collections_using.html) for more details.
|
||||
@@ -78,11 +78,10 @@ ansible-doc -t callback ansible.posix.profile_tasks
|
||||
|
||||
The following ansible-core versions have been tested with this collection:
|
||||
|
||||
- ansible-core 2.19 (devel)
|
||||
- ansible-core 2.18 (stable) *
|
||||
- ansible-core 2.20 (devel)
|
||||
- ansible-core 2.19 (stable) *
|
||||
- ansible-core 2.18 (stable)
|
||||
- ansible-core 2.17 (stable)
|
||||
- ansible-core 2.16 (stable)
|
||||
- ansible-core 2.15 (stable)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
2
changelogs/fragments/603_bump_version_3.yml
Normal file
2
changelogs/fragments/603_bump_version_3.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
trivial:
|
||||
- Bump version to 3.0.0 for the next release (https://github.com/ansible-collections/ansible.posix/issues/603).
|
||||
2
changelogs/fragments/618_ci_remove_ubuntu2004.yml
Normal file
2
changelogs/fragments/618_ci_remove_ubuntu2004.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
trivial:
|
||||
- Remove ubuntu20.04 from CI tests (https://github.com/ansible-collections/ansible.posix/issues/612).
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
minor_changes:
|
||||
- profile_tasks - Add option to provide a different date/time format (https://github.com/ansible-collections/ansible.posix/issues/279).
|
||||
6
changelogs/fragments/631_fixes_module_path.yml
Normal file
6
changelogs/fragments/631_fixes_module_path.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
bugfixes:
|
||||
- ansible.posix.cgroup_perf_recap - fixes json module load path (https://github.com/ansible-collections/ansible.posix/issues/630).
|
||||
trivial:
|
||||
- ansible.posix.seboolean - remove unnecessary condition from seboolean integration tests (https://github.com/ansible-collections/ansible.posix/issues/630).
|
||||
- ansible.posix.selinux - optimize conditions for selinux integration tests (https://github.com/ansible-collections/ansible.posix/issues/630).
|
||||
2
changelogs/fragments/642_ci_add_rhel10.yml
Normal file
2
changelogs/fragments/642_ci_add_rhel10.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
trivial:
|
||||
- Add Red Hat Enterprise Linux 10.0 to the CI matrix (https://github.com/ansible-collections/ansible.posix/issues/642).
|
||||
2
changelogs/fragments/650-profile_tasks_roles.yml
Normal file
2
changelogs/fragments/650-profile_tasks_roles.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
minor_changes:
|
||||
- "profile_tasks and profile_roles callback plugins - avoid deleted/deprecated callback functions, instead use modern interface that was introduced a longer time ago (https://github.com/ansible-collections/ansible.posix/issues/650)."
|
||||
3
changelogs/fragments/654_ci_bump_core_version.yml
Normal file
3
changelogs/fragments/654_ci_bump_core_version.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
trivial:
|
||||
- Bump ansible-core version to 2.20 of devel branch and add 2.19 to CI
|
||||
2
changelogs/fragments/660_ci_azp_syntax.yml
Normal file
2
changelogs/fragments/660_ci_azp_syntax.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
trivial:
|
||||
- AZP - fixed syntax error in CI test.
|
||||
3
changelogs/fragments/665_update_readme_20250728.yml
Normal file
3
changelogs/fragments/665_update_readme_20250728.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
trivial:
|
||||
- README - Update README to reflect Ansible Core 2.19 release.
|
||||
3
changelogs/fragments/666_azp_update_20250728.yml
Normal file
3
changelogs/fragments/666_azp_update_20250728.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
trivial:
|
||||
- AZP - Update AZP matrix to follow ansible-test changes.
|
||||
2
changelogs/fragments/673_update_ci_20250805.yml
Normal file
2
changelogs/fragments/673_update_ci_20250805.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
trivial:
|
||||
- Update AZP CI matrix (https://github.com/ansible-collections/ansible.posix/issues/673).
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
namespace: ansible
|
||||
name: posix
|
||||
version: 2.0.0
|
||||
version: 3.0.0
|
||||
readme: README.md
|
||||
authors:
|
||||
- Ansible (github.com/ansible)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
requires_ansible: ">=2.15.0"
|
||||
requires_ansible: ">=2.16.0"
|
||||
|
||||
@@ -132,6 +132,7 @@ DOCUMENTATION = '''
|
||||
|
||||
import csv
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
@@ -142,7 +143,7 @@ from functools import partial
|
||||
|
||||
from ansible.module_utils._text import to_bytes, to_text
|
||||
from ansible.module_utils.six import with_metaclass
|
||||
from ansible.parsing.ajson import AnsibleJSONEncoder, json
|
||||
from ansible.parsing.ajson import AnsibleJSONEncoder
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
|
||||
|
||||
@@ -124,10 +124,7 @@ class CallbackModule(CallbackBase):
|
||||
def v2_playbook_on_handler_task_start(self, task):
|
||||
self._record_task(task)
|
||||
|
||||
def playbook_on_setup(self):
|
||||
self._display_tasktime()
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
# Align summary report header with other callback plugin summary
|
||||
self._display.banner("ROLES RECAP")
|
||||
|
||||
|
||||
@@ -52,6 +52,17 @@ DOCUMENTATION = '''
|
||||
- section: callback_profile_tasks
|
||||
key: summary_only
|
||||
version_added: 1.5.0
|
||||
datetime_format:
|
||||
description:
|
||||
- Datetime format, as expected by the C(strftime) and C(strptime) methods.
|
||||
An C(iso8601) alias will be translated to C('%Y-%m-%dT%H:%M:%S.%f') if that datetime standard wants to be used.
|
||||
default: '%A %d %B %Y %H:%M:%S %z'
|
||||
env:
|
||||
- name: PROFILE_TASKS_DATETIME_FORMAT
|
||||
ini:
|
||||
- section: callback_profile_tasks
|
||||
key: datetime_format
|
||||
version_added: 3.0.0
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -72,14 +83,15 @@ sample output: >
|
||||
'''
|
||||
|
||||
import collections
|
||||
import time
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from ansible.module_utils.six.moves import reduce
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
|
||||
|
||||
# define start time
|
||||
t0 = tn = time.time()
|
||||
dt0 = dtn = datetime.now().astimezone()
|
||||
|
||||
|
||||
def secondsToStr(t):
|
||||
@@ -104,17 +116,18 @@ def filled(msg, fchar="*"):
|
||||
|
||||
def timestamp(self):
|
||||
if self.current is not None:
|
||||
elapsed = time.time() - self.stats[self.current]['started']
|
||||
elapsed = (datetime.now().astimezone() - self.stats[self.current]['started']).total_seconds()
|
||||
self.stats[self.current]['elapsed'] += elapsed
|
||||
|
||||
|
||||
def tasktime():
|
||||
global tn
|
||||
time_current = time.strftime('%A %d %B %Y %H:%M:%S %z')
|
||||
time_elapsed = secondsToStr(time.time() - tn)
|
||||
time_total_elapsed = secondsToStr(time.time() - t0)
|
||||
tn = time.time()
|
||||
return filled('%s (%s)%s%s' % (time_current, time_elapsed, ' ' * 7, time_total_elapsed))
|
||||
def tasktime(self):
|
||||
global dtn
|
||||
cdtn = datetime.now().astimezone()
|
||||
datetime_current = cdtn.strftime(self.datetime_format)
|
||||
time_elapsed = secondsToStr((cdtn - dtn).total_seconds())
|
||||
time_total_elapsed = secondsToStr((cdtn - dt0).total_seconds())
|
||||
dtn = cdtn
|
||||
return filled('%s (%s)%s%s' % (datetime_current, time_elapsed, ' ' * 7, time_total_elapsed))
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
@@ -134,6 +147,7 @@ class CallbackModule(CallbackBase):
|
||||
self.sort_order = None
|
||||
self.summary_only = None
|
||||
self.task_output_limit = None
|
||||
self.datetime_format = None
|
||||
|
||||
super(CallbackModule, self).__init__()
|
||||
|
||||
@@ -159,9 +173,14 @@ class CallbackModule(CallbackBase):
|
||||
else:
|
||||
self.task_output_limit = int(self.task_output_limit)
|
||||
|
||||
self.datetime_format = self.get_option('datetime_format')
|
||||
if self.datetime_format is not None:
|
||||
if self.datetime_format == 'iso8601':
|
||||
self.datetime_format = '%Y-%m-%dT%H:%M:%S.%f'
|
||||
|
||||
def _display_tasktime(self):
|
||||
if not self.summary_only:
|
||||
self._display.display(tasktime())
|
||||
self._display.display(tasktime(self))
|
||||
|
||||
def _record_task(self, task):
|
||||
"""
|
||||
@@ -176,10 +195,11 @@ class CallbackModule(CallbackBase):
|
||||
# with the same UUID is executed when `serial` is specified in a playbook.
|
||||
# elapsed: Elapsed time since the first serialized task was started
|
||||
self.current = task._uuid
|
||||
dtn = datetime.now().astimezone()
|
||||
if self.current not in self.stats:
|
||||
self.stats[self.current] = {'started': time.time(), 'elapsed': 0.0, 'name': task.get_name()}
|
||||
self.stats[self.current] = {'started': dtn, 'elapsed': 0.0, 'name': task.get_name()}
|
||||
else:
|
||||
self.stats[self.current]['started'] = time.time()
|
||||
self.stats[self.current]['started'] = dtn
|
||||
if self._display.verbosity >= 2:
|
||||
self.stats[self.current]['path'] = task.get_path()
|
||||
|
||||
@@ -189,14 +209,11 @@ class CallbackModule(CallbackBase):
|
||||
def v2_playbook_on_handler_task_start(self, task):
|
||||
self._record_task(task)
|
||||
|
||||
def playbook_on_setup(self):
|
||||
self._display_tasktime()
|
||||
|
||||
def playbook_on_stats(self, stats):
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
# Align summary report header with other callback plugin summary
|
||||
self._display.banner("TASKS RECAP")
|
||||
|
||||
self._display.display(tasktime())
|
||||
self._display.display(tasktime(self))
|
||||
self._display.display(filled("", fchar="="))
|
||||
|
||||
timestamp(self)
|
||||
|
||||
@@ -56,6 +56,16 @@ options:
|
||||
- Verify token value with the sysctl command and set with C(-w) if necessary.
|
||||
type: bool
|
||||
default: false
|
||||
system_wide:
|
||||
description:
|
||||
- If V(true), uses C(sysctl --system) behavior to reload all sysctl configuration files.
|
||||
- This will reload configuration from C(/etc/sysctl.d/*.conf), C(/run/sysctl.d/*.conf),
|
||||
C(/usr/local/lib/sysctl.d/*.conf), C(/usr/lib/sysctl.d/*.conf), C(/lib/sysctl.d/*.conf),
|
||||
and C(/etc/sysctl.conf) in that order.
|
||||
- If V(false), only reloads the specific sysctl file defined by O(sysctl_file).
|
||||
- Only applies when O(reload) is V(true).
|
||||
type: bool
|
||||
default: false
|
||||
author:
|
||||
- David CHANIAL (@davixx)
|
||||
'''
|
||||
@@ -80,6 +90,13 @@ EXAMPLES = r'''
|
||||
sysctl_file: /tmp/test_sysctl.conf
|
||||
reload: false
|
||||
|
||||
# Enable resource limits management in FreeBSD
|
||||
- ansible.posix.sysctl:
|
||||
name: kern.racct.enable
|
||||
value: '1'
|
||||
sysctl_file: /boot/loader.conf
|
||||
reload: false
|
||||
|
||||
# Set ip forwarding on in /proc and verify token value with the sysctl command
|
||||
- ansible.posix.sysctl:
|
||||
name: net.ipv4.ip_forward
|
||||
@@ -93,6 +110,14 @@ EXAMPLES = r'''
|
||||
sysctl_set: true
|
||||
state: present
|
||||
reload: true
|
||||
|
||||
# Set vm.swappiness and reload all system sysctl configuration files (equivalent to sysctl --system)
|
||||
- ansible.posix.sysctl:
|
||||
name: vm.swappiness
|
||||
value: '10'
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: true
|
||||
'''
|
||||
|
||||
# ==============================================================
|
||||
@@ -101,6 +126,7 @@ import os
|
||||
import platform
|
||||
import re
|
||||
import tempfile
|
||||
import glob
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.six import string_types
|
||||
@@ -114,17 +140,30 @@ class SysctlModule(object):
|
||||
# success or failure.
|
||||
LANG_ENV = {'LANG': 'C', 'LC_ALL': 'C', 'LC_MESSAGES': 'C'}
|
||||
|
||||
# We define a variable to keep all the directories to be read, equivalent to
|
||||
# (/sbin/sysctl --system) option
|
||||
SYSCTL_DIRS = [
|
||||
'/etc/sysctl.d/*.conf',
|
||||
'/run/sysctl.d/*.conf',
|
||||
'/usr/local/lib/sysctl.d/*.conf',
|
||||
'/usr/lib/sysctl.d/*.conf',
|
||||
'/lib/sysctl.d/*.conf',
|
||||
'/etc/sysctl.conf'
|
||||
]
|
||||
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.args = self.module.params
|
||||
|
||||
self.sysctl_cmd = self.module.get_bin_path('sysctl', required=True)
|
||||
self.sysctl_file = self.args['sysctl_file']
|
||||
self.system_wide = self.args['system_wide']
|
||||
|
||||
self.proc_value = None # current token value in proc fs
|
||||
self.file_value = None # current token value in file
|
||||
self.file_lines = [] # all lines in the file
|
||||
self.file_values = {} # dict of token values
|
||||
self.system_wide_file_value = None # current token value from system-wide files
|
||||
|
||||
self.changed = False # will change occur
|
||||
self.set_proc = False # does sysctl need to set value
|
||||
@@ -154,19 +193,36 @@ class SysctlModule(object):
|
||||
if thisname not in self.file_values:
|
||||
self.file_values[thisname] = None
|
||||
|
||||
# if system_wide is enabled, also check system-wide configuration
|
||||
if self.system_wide:
|
||||
system_wide_values = self.read_system_wide_sysctl_files()
|
||||
# If the value exists in system-wide config, use that for comparison
|
||||
if thisname in system_wide_values:
|
||||
self.system_wide_file_value = system_wide_values[thisname]
|
||||
else:
|
||||
self.system_wide_file_value = None
|
||||
else:
|
||||
self.system_wide_file_value = None
|
||||
|
||||
# update file contents with desired token/value
|
||||
self.fix_lines()
|
||||
|
||||
# what do we need to do now?
|
||||
if self.file_values[thisname] is None and self.args['state'] == "present":
|
||||
# Determine the effective current value (system-wide takes precedence if enabled)
|
||||
if self.system_wide and self.system_wide_file_value is not None:
|
||||
current_file_value = self.system_wide_file_value
|
||||
else:
|
||||
current_file_value = self.file_values[thisname]
|
||||
|
||||
if current_file_value is None and self.args['state'] == "present":
|
||||
self.changed = True
|
||||
self.write_file = True
|
||||
elif self.file_values[thisname] is None and self.args['state'] == "absent":
|
||||
elif current_file_value is None and self.args['state'] == "absent":
|
||||
self.changed = False
|
||||
elif self.file_values[thisname] and self.args['state'] == "absent":
|
||||
elif current_file_value and self.args['state'] == "absent":
|
||||
self.changed = True
|
||||
self.write_file = True
|
||||
elif self.file_values[thisname] != self.args['value']:
|
||||
elif current_file_value != self.args['value']:
|
||||
self.changed = True
|
||||
self.write_file = True
|
||||
# with reload=yes we should check if the current system values are
|
||||
@@ -299,15 +355,25 @@ class SysctlModule(object):
|
||||
# https://github.com/ansible/ansible/issues/58158
|
||||
return
|
||||
else:
|
||||
# system supports reloading via the -p flag to sysctl, so we'll use that
|
||||
sysctl_args = [self.sysctl_cmd, '-p', self.sysctl_file]
|
||||
if self.args['ignoreerrors']:
|
||||
sysctl_args.insert(1, '-e')
|
||||
if self.system_wide:
|
||||
for sysctl_file in self.SYSCTL_DIRS:
|
||||
for conf_file in glob.glob(sysctl_file):
|
||||
sysctl_args = [self.sysctl_cmd, '-p', conf_file]
|
||||
if self.args['ignoreerrors']:
|
||||
sysctl_args.insert(1, '-e')
|
||||
rc, out, err = self.module.run_command(sysctl_args, environ_update=self.LANG_ENV)
|
||||
if rc != 0 or self._stderr_failed(err):
|
||||
self.module.fail_json(msg="Failed to reload sysctl: %s" % to_native(out) + to_native(err))
|
||||
else:
|
||||
# system supports reloading via the -p flag to sysctl, so we'll use that
|
||||
sysctl_args = [self.sysctl_cmd, '-p', self.sysctl_file]
|
||||
if self.args['ignoreerrors']:
|
||||
sysctl_args.insert(1, '-e')
|
||||
|
||||
rc, out, err = self.module.run_command(sysctl_args, environ_update=self.LANG_ENV)
|
||||
rc, out, err = self.module.run_command(sysctl_args, environ_update=self.LANG_ENV)
|
||||
|
||||
if rc != 0 or self._stderr_failed(err):
|
||||
self.module.fail_json(msg="Failed to reload sysctl: %s" % to_native(out) + to_native(err))
|
||||
if rc != 0 or self._stderr_failed(err):
|
||||
self.module.fail_json(msg="Failed to reload sysctl: %s" % to_native(out) + to_native(err))
|
||||
|
||||
# ==============================================================
|
||||
# SYSCTL FILE MANAGEMENT
|
||||
@@ -337,6 +403,35 @@ class SysctlModule(object):
|
||||
v = v.strip()
|
||||
self.file_values[k] = v.strip()
|
||||
|
||||
# Get the token value from all system-wide sysctl files
|
||||
def read_system_wide_sysctl_files(self):
|
||||
"""Read all system-wide sysctl configuration files when system_wide=True"""
|
||||
system_values = {}
|
||||
|
||||
for sysctl_pattern in self.SYSCTL_DIRS:
|
||||
for conf_file in glob.glob(sysctl_pattern):
|
||||
if os.path.isfile(conf_file):
|
||||
try:
|
||||
with open(conf_file, "r") as read_file:
|
||||
lines = read_file.readlines()
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
# don't split empty lines or comments or line without equal sign
|
||||
if not line or line.startswith(("#", ";")) or "=" not in line:
|
||||
continue
|
||||
|
||||
k, v = line.split('=', 1)
|
||||
k = k.strip()
|
||||
v = v.strip()
|
||||
# Later files override earlier ones (mimicking sysctl --system behavior)
|
||||
system_values[k] = v.strip()
|
||||
except IOError:
|
||||
# Skip files that can't be read
|
||||
continue
|
||||
|
||||
return system_values
|
||||
|
||||
# Fix the value in the sysctl file content
|
||||
def fix_lines(self):
|
||||
checked = []
|
||||
@@ -394,7 +489,8 @@ def main():
|
||||
reload=dict(default=True, type='bool'),
|
||||
sysctl_set=dict(default=False, type='bool'),
|
||||
ignoreerrors=dict(default=False, type='bool'),
|
||||
sysctl_file=dict(default='/etc/sysctl.conf', type='path')
|
||||
sysctl_file=dict(default='/etc/sysctl.conf', type='path'),
|
||||
system_wide=dict(default=False, type='bool'), # system_wide parameter
|
||||
),
|
||||
supports_check_mode=True,
|
||||
required_if=[('state', 'present', ['value'])],
|
||||
|
||||
@@ -46,6 +46,12 @@
|
||||
path: "{{ test_dir }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Install acl package
|
||||
ansible.builtin.package:
|
||||
name: acl
|
||||
state: present
|
||||
|
||||
##############################################################################
|
||||
- name: Grant ansible user read access to a file
|
||||
ansible.posix.acl:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
needs/privileged
|
||||
needs/root
|
||||
destructive
|
||||
shippable/posix/group1
|
||||
skip/aix
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# SETUP ################################################################################
|
||||
- name: Install dependencies (Linux)
|
||||
ansible.builtin.package:
|
||||
name: e2fsprogs
|
||||
@@ -110,6 +111,42 @@
|
||||
mode: '0644'
|
||||
register: orig_info
|
||||
|
||||
# BIND MOUNT ################################################################################
|
||||
# bind mount check mode
|
||||
- name: Bind mount a filesystem (Linux) (check mode)
|
||||
ansible.posix.mount:
|
||||
src: '{{ output_dir }}/mount_source'
|
||||
name: '{{ output_dir }}/mount_dest'
|
||||
state: mounted
|
||||
fstype: None
|
||||
opts: bind
|
||||
when: ansible_system == 'Linux'
|
||||
register: bind_result_linux_dry_run
|
||||
check_mode: true
|
||||
|
||||
- name: Bind mount a filesystem (FreeBSD) (check mode)
|
||||
ansible.posix.mount:
|
||||
src: '{{ output_dir }}/mount_source'
|
||||
name: '{{ output_dir }}/mount_dest'
|
||||
state: mounted
|
||||
fstype: nullfs
|
||||
when: ansible_system == 'FreeBSD'
|
||||
register: bind_result_freebsd_dry_run
|
||||
check_mode: true
|
||||
|
||||
- name: Attempt to stat bind mounted file
|
||||
ansible.builtin.stat:
|
||||
path: '{{ output_dir }}/mount_dest/test_file'
|
||||
when: ansible_system in ('FreeBSD', 'Linux')
|
||||
register: dest_stat
|
||||
|
||||
- name: Assert the bind mount did not take place
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- not dest_stat['stat']['exists']
|
||||
when: ansible_system in ('FreeBSD', 'Linux')
|
||||
|
||||
# bind mount
|
||||
- name: Bind mount a filesystem (Linux)
|
||||
ansible.posix.mount:
|
||||
src: '{{ output_dir }}/mount_source'
|
||||
@@ -168,6 +205,48 @@
|
||||
- (ansible_system == 'Linux' and not bind_result_linux['changed']) or (ansible_system == 'FreeBSD' and not bind_result_freebsd['changed'])
|
||||
when: ansible_system in ('FreeBSD', 'Linux')
|
||||
|
||||
# remount check mode
|
||||
- name: Remount filesystem with different opts (Linux) (check mode)
|
||||
ansible.posix.mount:
|
||||
src: '{{ output_dir }}/mount_source'
|
||||
name: '{{ output_dir }}/mount_dest'
|
||||
state: mounted
|
||||
fstype: None
|
||||
opts: bind,ro
|
||||
when: ansible_system == 'Linux'
|
||||
register: bind_result_linux
|
||||
check_mode: true
|
||||
|
||||
- name: Remount filesystem with different opts (FreeBSD) (check mode)
|
||||
ansible.posix.mount:
|
||||
src: '{{ output_dir }}/mount_source'
|
||||
name: '{{ output_dir }}/mount_dest'
|
||||
state: mounted
|
||||
fstype: nullfs
|
||||
opts: ro
|
||||
when: ansible_system == 'FreeBSD'
|
||||
register: bind_result_freebsd
|
||||
check_mode: true
|
||||
|
||||
- name: Get mount options
|
||||
ansible.builtin.shell:
|
||||
cmd: set -o pipefail && mount | grep mount_dest | grep -c -E -w '(ro|read-only)'
|
||||
executable: "{{ shell_executable }}"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: new_options_count
|
||||
|
||||
- name: Make sure the filesystem does not have the new opts
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- linux_and_changed or freebsd_and_changed
|
||||
- new_options_count.stdout | int == 0
|
||||
vars:
|
||||
linux_and_changed: "{{ ansible_system == 'Linux' and bind_result_linux_dry_run['changed'] }}"
|
||||
freebsd_and_changed: "{{ ansible_system == 'FreeBSD' and bind_result_freebsd['changed'] }}"
|
||||
when: ansible_system in ('FreeBSD', 'Linux')
|
||||
|
||||
# remount
|
||||
- name: Remount filesystem with different opts (Linux)
|
||||
ansible.posix.mount:
|
||||
src: '{{ output_dir }}/mount_source'
|
||||
@@ -203,6 +282,29 @@
|
||||
- 1 == remount_options.stdout_lines | length
|
||||
when: ansible_system in ('FreeBSD', 'Linux')
|
||||
|
||||
# unmount check mode
|
||||
- name: Unmount the bind mount (check mode)
|
||||
ansible.posix.mount:
|
||||
name: '{{ output_dir }}/mount_dest'
|
||||
state: absent
|
||||
when: ansible_system in ('Linux', 'FreeBSD')
|
||||
register: unmount_result
|
||||
check_mode: true
|
||||
|
||||
- name: Make sure the file still exists in dest
|
||||
ansible.builtin.stat:
|
||||
path: '{{ output_dir }}/mount_dest/test_file'
|
||||
when: ansible_system in ('FreeBSD', 'Linux')
|
||||
register: dest_stat
|
||||
|
||||
- name: Check that we did not unmount
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- unmount_result['changed']
|
||||
- dest_stat['stat']['exists']
|
||||
when: ansible_system in ('FreeBSD', 'Linux')
|
||||
|
||||
# unmount
|
||||
- name: Unmount the bind mount
|
||||
ansible.posix.mount:
|
||||
name: '{{ output_dir }}/mount_dest'
|
||||
@@ -223,9 +325,36 @@
|
||||
- not dest_stat['stat']['exists']
|
||||
when: ansible_system in ('FreeBSD', 'Linux')
|
||||
|
||||
- name: Block to test remounted option
|
||||
# SWAP #############################################################
|
||||
- name: Swap
|
||||
when: ansible_system in ('Linux')
|
||||
block:
|
||||
# mount swap check mode
|
||||
- name: Stat /etc/fstab
|
||||
ansible.builtin.stat:
|
||||
path: /etc/fstab
|
||||
register: stat_fstab_before
|
||||
|
||||
- name: Create fstab record for the first swap file (check mode)
|
||||
ansible.posix.mount:
|
||||
name: none
|
||||
src: /tmp/swap1
|
||||
opts: sw
|
||||
fstype: swap
|
||||
state: present
|
||||
check_mode: true
|
||||
|
||||
- name: Stat /etc/fstab
|
||||
ansible.builtin.stat:
|
||||
path: /etc/fstab
|
||||
register: stat_fstab_after
|
||||
|
||||
- name: Assert that fstab checksum did not change
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- stat_fstab_before.stat.checksum == stat_fstab_after.stat.checksum
|
||||
|
||||
# mount swap1
|
||||
- name: Create fstab record for the first swap file
|
||||
ansible.posix.mount:
|
||||
name: none
|
||||
@@ -250,6 +379,7 @@
|
||||
- swap1_created['changed']
|
||||
- not swap1_created_again['changed']
|
||||
|
||||
# mount swap2
|
||||
- name: Create fstab record for the second swap file
|
||||
ansible.posix.mount:
|
||||
name: none
|
||||
@@ -274,6 +404,30 @@
|
||||
- swap2_created['changed']
|
||||
- not swap2_created_again['changed']
|
||||
|
||||
# remove swap check mode
|
||||
- name: Stat /etc/fstab
|
||||
ansible.builtin.stat:
|
||||
path: /etc/fstab
|
||||
register: stat_fstab_before
|
||||
|
||||
- name: Remove the fstab record for the first swap file (check mode)
|
||||
ansible.posix.mount:
|
||||
name: none
|
||||
src: /tmp/swap1
|
||||
state: absent
|
||||
check_mode: true
|
||||
|
||||
- name: Stat /etc/fstab
|
||||
ansible.builtin.stat:
|
||||
path: /etc/fstab
|
||||
register: stat_fstab_after
|
||||
|
||||
- name: Assert that fstab checksum did not change
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- stat_fstab_before.stat.checksum == stat_fstab_after.stat.checksum
|
||||
|
||||
# remove swap1
|
||||
- name: Remove the fstab record for the first swap file
|
||||
ansible.posix.mount:
|
||||
name: none
|
||||
@@ -294,6 +448,7 @@
|
||||
- swap1_removed['changed']
|
||||
- not swap1_removed_again['changed']
|
||||
|
||||
# remove swap2
|
||||
- name: Remove the fstab record for the second swap file
|
||||
ansible.posix.mount:
|
||||
name: none
|
||||
@@ -314,6 +469,10 @@
|
||||
- swap2_removed['changed']
|
||||
- not swap2_removed_again['changed']
|
||||
|
||||
# FIXUP #############################################################
|
||||
- name: Fix incomplete entry already present in fstab
|
||||
when: ansible_system == 'Linux'
|
||||
block:
|
||||
- name: Create fstab record with missing last two fields
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/fstab
|
||||
@@ -343,6 +502,11 @@
|
||||
- ''' 0 0'' in optional_fields_content.stdout'
|
||||
- 1 == optional_fields_content.stdout_lines | length
|
||||
|
||||
# REMOUNTED #############################################################
|
||||
- name: Block to test remounted option
|
||||
when: ansible_system in ('Linux')
|
||||
block:
|
||||
# setup
|
||||
- name: Create empty file
|
||||
community.general.filesize:
|
||||
path: /tmp/myfs.img
|
||||
@@ -372,6 +536,26 @@
|
||||
ansible.builtin.pause:
|
||||
seconds: 2
|
||||
|
||||
# remount check mode
|
||||
- name: Remount (check mode)
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
state: remounted
|
||||
|
||||
- name: Get again the last write time
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
set -o pipefail && dumpe2fs /tmp/myfs.img 2>/dev/null | grep -i "last write time:" |cut -d: -f2-
|
||||
executable: "{{ shell_executable }}"
|
||||
changed_when: false
|
||||
register: last_write_time_check
|
||||
|
||||
- name: Fail if they are different
|
||||
ansible.builtin.fail:
|
||||
msg: Filesytem was remounted, testing of the module failed!
|
||||
when: last_write_time.stdout != last_write_time_check.stdout
|
||||
|
||||
# remount
|
||||
- name: Test if the FS is remounted
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
@@ -390,6 +574,29 @@
|
||||
msg: Filesytem was not remounted, testing of the module failed!
|
||||
when: last_write is defined and last_write_time2 is defined and last_write_time.stdout == last_write_time2.stdout
|
||||
|
||||
# remount different options check mode
|
||||
- name: Remount filesystem with different opts using remounted option (Linux only)
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
state: remounted
|
||||
opts: rw,noexec
|
||||
check_mode: true
|
||||
|
||||
- name: Get remounted options (Linux only)
|
||||
ansible.builtin.shell:
|
||||
cmd: set -o pipefail && mount | grep myfs | grep -E -w 'noexec' | wc -l
|
||||
executable: "{{ shell_executable }}"
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
register: remounted_options
|
||||
|
||||
- name: Make sure the filesystem now has the new opts after using remounted (Linux only)
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- "'0' in remounted_options.stdout"
|
||||
- "1 == remounted_options.stdout_lines | length"
|
||||
|
||||
# remount different options
|
||||
- name: Remount filesystem with different opts using remounted option (Linux only)
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
@@ -409,6 +616,7 @@
|
||||
- "'1' in remounted_options.stdout"
|
||||
- "1 == remounted_options.stdout_lines | length"
|
||||
|
||||
# backup
|
||||
- name: Mount the FS again to test backup
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
@@ -439,9 +647,11 @@
|
||||
- /tmp/myfs.img
|
||||
- /tmp/myfs
|
||||
|
||||
# BOOT #############################################################
|
||||
- name: Block to test boot option for Linux
|
||||
when: ansible_system in ('Linux')
|
||||
block:
|
||||
# setup
|
||||
- name: Create empty file
|
||||
community.general.filesize:
|
||||
path: /tmp/myfs.img
|
||||
@@ -452,6 +662,7 @@
|
||||
fstype: ext3
|
||||
dev: /tmp/myfs.img
|
||||
|
||||
# noauto
|
||||
- name: Mount the FS with noauto option
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
@@ -472,6 +683,7 @@
|
||||
path: /tmp/myfs
|
||||
state: absent
|
||||
|
||||
# noauto + defaults
|
||||
- name: Mount the FS with noauto option and defaults
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
@@ -499,6 +711,7 @@
|
||||
- /tmp/myfs.img
|
||||
- /tmp/myfs
|
||||
|
||||
# NEWLINE END OF FILE ############################################
|
||||
- name: Block to test missing newline at the EOF of fstab
|
||||
when: ansible_system in ('Linux')
|
||||
block:
|
||||
@@ -537,6 +750,7 @@
|
||||
- /tmp/myfs1
|
||||
- /tmp/test_fstab
|
||||
|
||||
# EPHEMERAL ################################################
|
||||
- name: Block to test ephemeral option
|
||||
environment:
|
||||
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
@@ -552,8 +766,7 @@
|
||||
path: /tmp/myfs_B.img
|
||||
size: 20M
|
||||
|
||||
##### FORMAT FS ON LINUX
|
||||
|
||||
##### FORMAT FS ON LINUX
|
||||
- name: Block to format FS on Linux
|
||||
when: ansible_system == 'Linux'
|
||||
block:
|
||||
@@ -567,8 +780,7 @@
|
||||
fstype: ext3
|
||||
dev: /tmp/myfs_B.img
|
||||
|
||||
##### FORMAT FS ON SOLARIS AND BSD
|
||||
|
||||
##### FORMAT FS ON SOLARIS AND BSD
|
||||
- name: Create loop devices on Solaris and BSD
|
||||
ansible.builtin.shell:
|
||||
cmd: "set -o pipefail && {{ ephemeral_create_loop_dev_cmd }}"
|
||||
@@ -583,14 +795,49 @@
|
||||
changed_when: true
|
||||
when: ephemeral_format_fs_cmd is defined
|
||||
|
||||
##### TESTS
|
||||
|
||||
- name: Create fstab if it does not exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ ephemeral_fstab }}"
|
||||
state: touch
|
||||
mode: '0644'
|
||||
|
||||
# normal ephemeral mount check mode
|
||||
- name: Get checksum of /etc/fstab before mounting anything
|
||||
ansible.builtin.stat:
|
||||
path: '{{ ephemeral_fstab }}'
|
||||
register: fstab_stat_before_mount
|
||||
|
||||
- name: Mount the FS A with ephemeral state (check mode)
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
src: '{{ ephemeral_device_a }}'
|
||||
fstype: '{{ ephemeral_fstype }}'
|
||||
opts: rw
|
||||
state: ephemeral
|
||||
register: ephemeral_mount_info
|
||||
check_mode: true
|
||||
|
||||
- name: Get checksum of /etc/fstab after an ephemeral mount
|
||||
ansible.builtin.stat:
|
||||
path: '{{ ephemeral_fstab }}'
|
||||
register: fstab_stat_after_mount
|
||||
|
||||
- name: Get mountinfo
|
||||
ansible.builtin.shell:
|
||||
cmd: grep -c '/tmp/myfs' <(mount -v)
|
||||
executable: "{{ shell_executable }}"
|
||||
register: check_mountinfo
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Assert the mount occurred and the fstab is unchanged
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- check_mountinfo.stdout|int == 0
|
||||
- ephemeral_mount_info['changed']
|
||||
- fstab_stat_before_mount['stat']['checksum'] == fstab_stat_after_mount['stat']['checksum']
|
||||
|
||||
# normal ephemeral mount
|
||||
- name: Get checksum of /etc/fstab before mounting anything
|
||||
ansible.builtin.stat:
|
||||
path: '{{ ephemeral_fstab }}'
|
||||
@@ -631,6 +878,48 @@
|
||||
- ephemeral_mount_info['changed']
|
||||
- fstab_stat_before_mount['stat']['checksum'] == fstab_stat_after_mount['stat']['checksum']
|
||||
|
||||
# remount different options check mode
|
||||
- name: Get first mount record
|
||||
ansible.builtin.shell:
|
||||
cmd: grep '/tmp/myfs' <(mount -v)
|
||||
executable: "{{ shell_executable }}"
|
||||
register: ephemeral_mount_record_1
|
||||
changed_when: false
|
||||
|
||||
- name: Try to mount FS A where FS A is already mounted (should trigger remount and changed)
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
src: '{{ ephemeral_device_a }}'
|
||||
fstype: '{{ ephemeral_fstype }}'
|
||||
opts: ro
|
||||
state: ephemeral
|
||||
register: ephemeral_mount_info
|
||||
check_mode: true
|
||||
|
||||
- name: Get second mount record (should be different than the first)
|
||||
ansible.builtin.shell:
|
||||
cmd: grep '/tmp/myfs' <(mount -v)
|
||||
executable: "{{ shell_executable }}"
|
||||
register: ephemeral_mount_record_2
|
||||
changed_when: false
|
||||
|
||||
- name: Get mountinfo
|
||||
ansible.builtin.shell:
|
||||
cmd: grep -c '/tmp/myfs' <(mount -v)
|
||||
executable: "{{ shell_executable }}"
|
||||
failed_when: false
|
||||
register: check_mountinfo
|
||||
changed_when: false
|
||||
|
||||
- name: Assert the FS A is still mounted, the options unchanged and the fstab unchanged
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- check_mountinfo.stdout|int == 1
|
||||
- ephemeral_mount_record_1.stdout == ephemeral_mount_record_2.stdout
|
||||
- ephemeral_mount_info['changed']
|
||||
- fstab_stat_before_mount['stat']['checksum'] == fstab_stat_after_mount['stat']['checksum']
|
||||
|
||||
# remount different options
|
||||
- name: Get first mount record
|
||||
ansible.builtin.shell:
|
||||
cmd: grep '/tmp/myfs' <(mount -v)
|
||||
@@ -670,6 +959,7 @@
|
||||
- ephemeral_mount_info['changed']
|
||||
- fstab_stat_before_mount['stat']['checksum'] == fstab_stat_after_mount['stat']['checksum']
|
||||
|
||||
# conflicting mount
|
||||
- name: Try to mount file B on file A mountpoint (should fail)
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
@@ -707,6 +997,39 @@
|
||||
- test_file_stat['stat']['exists']
|
||||
- ephemeral_mount_b_info is failed
|
||||
|
||||
# unmount check mode
|
||||
- name: Unmount FS with state = unmounted
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
state: unmounted
|
||||
check_mode: true
|
||||
|
||||
- name: Get fstab checksum after unmounting an ephemeral mount with state = unmounted
|
||||
ansible.builtin.stat:
|
||||
path: '{{ ephemeral_fstab }}'
|
||||
register: fstab_stat_after_unmount
|
||||
|
||||
- name: Get mountinfo
|
||||
ansible.builtin.shell:
|
||||
cmd: grep -c '/tmp/myfs' <(mount -v)
|
||||
executable: "{{ shell_executable }}"
|
||||
register: check_mountinfo
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
|
||||
- name: Try to stat our test file
|
||||
ansible.builtin.stat:
|
||||
path: /tmp/myfs/test_file
|
||||
register: test_file_stat
|
||||
|
||||
- name: Assert that unmount did not take place and fstab unchanged
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- check_mountinfo.stdout|int == 1
|
||||
- test_file_stat['stat']['exists']
|
||||
- fstab_stat_before_mount['stat']['checksum'] == fstab_stat_after_unmount['stat']['checksum']
|
||||
|
||||
# unmount
|
||||
- name: Unmount FS with state = unmounted
|
||||
ansible.posix.mount:
|
||||
path: /tmp/myfs
|
||||
@@ -759,6 +1082,7 @@
|
||||
- /tmp/myfs_B.img
|
||||
- /tmp/myfs
|
||||
|
||||
# OPTS_NO_LOG ######################################
|
||||
- name: Block to test opts_no_log option
|
||||
when: ansible_system == 'Linux'
|
||||
block:
|
||||
|
||||
@@ -20,5 +20,4 @@
|
||||
ansible.builtin.include_tasks: seboolean.yml
|
||||
when:
|
||||
- ansible_selinux is defined
|
||||
- ansible_selinux
|
||||
- ansible_selinux.status == 'enabled'
|
||||
|
||||
@@ -19,23 +19,21 @@
|
||||
- name: Debug message for when SELinux is disabled
|
||||
ansible.builtin.debug:
|
||||
msg: SELinux is disabled
|
||||
when: ansible_selinux is defined and not ansible_selinux
|
||||
when: ansible_selinux is defined and ansible_selinux.status == 'disabled'
|
||||
|
||||
- name: Debug message for when SELinux is enabled and not disabled
|
||||
ansible.builtin.debug:
|
||||
msg: SELinux is {{ ansible_selinux.status }}
|
||||
when: ansible_selinux is defined and ansible_selinux
|
||||
when: ansible_selinux is defined
|
||||
|
||||
- name: Include_tasks for when SELinux is enabled
|
||||
ansible.builtin.include_tasks: selinux.yml
|
||||
when:
|
||||
- ansible_selinux is defined
|
||||
- ansible_selinux
|
||||
- ansible_selinux.status == 'enabled'
|
||||
|
||||
- name: Include tasks for selogin when SELinux is enabled
|
||||
ansible.builtin.include_tasks: selogin.yml
|
||||
when:
|
||||
- ansible_selinux is defined
|
||||
- ansible_selinux
|
||||
- ansible_selinux.status == 'enabled'
|
||||
|
||||
@@ -140,8 +140,8 @@
|
||||
ansible.posix.sysctl:
|
||||
name: test.invalid
|
||||
value: 1
|
||||
register: sysctl_test3
|
||||
ignore_errors: true
|
||||
register: sysctl_test3
|
||||
|
||||
- name: Debug sysctl_test3
|
||||
ansible.builtin.debug:
|
||||
@@ -229,6 +229,91 @@
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_test4 is failed
|
||||
|
||||
##
|
||||
## sysctl --system
|
||||
##
|
||||
|
||||
- name: Set vm.swappiness to 10 with --system option
|
||||
ansible.posix.sysctl:
|
||||
name: vm.swappiness
|
||||
value: 10
|
||||
state: present
|
||||
reload: false
|
||||
sysctl_set: true
|
||||
system_wide: true
|
||||
register: sysctl_system_test1
|
||||
|
||||
- name: Check with sysctl command
|
||||
ansible.builtin.command: sysctl vm.swappiness
|
||||
changed_when: false
|
||||
register: sysctl_check_system1
|
||||
|
||||
- name: Debug sysctl_system_test1 sysctl_check_system1
|
||||
ansible.builtin.debug:
|
||||
var: item
|
||||
verbosity: 1
|
||||
with_items:
|
||||
- "{{ sysctl_system_test1 }}"
|
||||
- "{{ sysctl_check_system1 }}"
|
||||
|
||||
- name: Validate results for --system option
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_test1 is changed
|
||||
- "'10' in sysctl_check_system1.stdout"
|
||||
|
||||
# Test system_wide with reload=true
|
||||
- name: Set vm.dirty_ratio to 20 with system_wide and reload=true
|
||||
ansible.posix.sysctl:
|
||||
name: vm.dirty_ratio
|
||||
value: 20
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: true
|
||||
register: sysctl_system_reload_test
|
||||
|
||||
- name: Check vm.dirty_ratio value
|
||||
ansible.builtin.command: sysctl -n vm.dirty_ratio
|
||||
changed_when: false
|
||||
register: sysctl_check_dirty_ratio
|
||||
|
||||
- name: Validate system_wide with reload
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_reload_test is changed
|
||||
- sysctl_check_dirty_ratio.stdout == "20"
|
||||
|
||||
# Test system_wide=false behavior (default)
|
||||
- name: Create custom sysctl file for testing
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
# Custom sysctl test file
|
||||
vm.dirty_background_ratio=5
|
||||
dest: "{{ output_dir_test }}/custom_sysctl.conf"
|
||||
mode: "0644"
|
||||
|
||||
- name: Set vm.dirty_background_ratio with system_wide=false
|
||||
ansible.posix.sysctl:
|
||||
name: vm.dirty_background_ratio
|
||||
value: 10
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: false
|
||||
sysctl_file: "{{ output_dir_test }}/custom_sysctl.conf"
|
||||
register: sysctl_system_false_test
|
||||
|
||||
- name: Check custom sysctl file content
|
||||
ansible.builtin.command: cat {{ output_dir_test }}/custom_sysctl.conf
|
||||
changed_when: false
|
||||
register: custom_sysctl_content
|
||||
|
||||
- name: Validate system_wide=false behavior
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_false_test is changed
|
||||
- "'vm.dirty_background_ratio=10' in custom_sysctl_content.stdout"
|
||||
|
||||
|
||||
- name: Test on RHEL VMs
|
||||
when:
|
||||
@@ -366,3 +451,36 @@
|
||||
that:
|
||||
- stat_result.stat.islnk is defined and stat_result.stat.islnk
|
||||
- stat_result.stat.lnk_source == '/tmp/ansible_sysctl_test.conf'
|
||||
|
||||
# Test sysctl: --system
|
||||
- name: Set vm.swappiness to 10 with --system option
|
||||
ansible.posix.sysctl:
|
||||
name: vm.swappiness
|
||||
value: 10
|
||||
state: present
|
||||
reload: false
|
||||
sysctl_set: true
|
||||
system_wide: true
|
||||
register: sysctl_system_test1
|
||||
|
||||
- name: Check with sysctl command
|
||||
ansible.builtin.command: sysctl vm.swappiness
|
||||
changed_when: false
|
||||
register: sysctl_check_system1
|
||||
|
||||
- name: Debug sysctl_system_test1 sysctl_check_system1
|
||||
ansible.builtin.debug:
|
||||
var: item
|
||||
verbosity: 1
|
||||
with_items:
|
||||
- "{{ sysctl_system_test1 }}"
|
||||
- "{{ sysctl_check_system1 }}"
|
||||
|
||||
- name: Validate results for --system option
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_test1 is changed
|
||||
- sysctl_check_system1.stdout_lines == ["vm.swappiness = 10"]
|
||||
|
||||
- name: Include system_wide specific tests
|
||||
ansible.builtin.include_tasks: system_wide_tests.yml
|
||||
|
||||
203
tests/integration/targets/sysctl/tasks/system_wide_tests.yml
Normal file
203
tests/integration/targets/sysctl/tasks/system_wide_tests.yml
Normal file
@@ -0,0 +1,203 @@
|
||||
---
|
||||
# Additional tests specifically for system_wide parameter functionality
|
||||
|
||||
- name: Test system_wide parameter basic functionality
|
||||
block:
|
||||
# Test system_wide with a simple sysctl parameter
|
||||
- name: Set vm.swappiness with system_wide=true (first time)
|
||||
ansible.posix.sysctl:
|
||||
name: vm.swappiness
|
||||
value: 35
|
||||
state: present
|
||||
reload: false
|
||||
system_wide: true
|
||||
register: sysctl_system_wide_first_test
|
||||
|
||||
- name: Debug first test result
|
||||
ansible.builtin.debug:
|
||||
var: sysctl_system_wide_first_test
|
||||
|
||||
- name: Set vm.swappiness with system_wide=true (second time - should not change)
|
||||
ansible.posix.sysctl:
|
||||
name: vm.swappiness
|
||||
value: 35
|
||||
state: present
|
||||
reload: false
|
||||
system_wide: true
|
||||
register: sysctl_system_wide_second_test
|
||||
|
||||
- name: Debug second test result
|
||||
ansible.builtin.debug:
|
||||
var: sysctl_system_wide_second_test
|
||||
|
||||
- name: Validate system_wide basic functionality
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_wide_first_test is changed
|
||||
- sysctl_system_wide_second_test is not changed
|
||||
|
||||
# Test system_wide with reload=true
|
||||
- name: Set vm.dirty_expire_centisecs with system_wide=true and reload
|
||||
ansible.posix.sysctl:
|
||||
name: vm.dirty_expire_centisecs
|
||||
value: 3000
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: true
|
||||
register: sysctl_system_wide_reload_test
|
||||
|
||||
- name: Check vm.dirty_expire_centisecs value
|
||||
ansible.builtin.command: sysctl -n vm.dirty_expire_centisecs
|
||||
changed_when: false
|
||||
register: sysctl_check_dirty_expire
|
||||
|
||||
- name: Validate system_wide with reload=true
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_wide_reload_test is changed
|
||||
- sysctl_check_dirty_expire.stdout == "3000"
|
||||
|
||||
# Test system_wide=false behavior (default)
|
||||
- name: Create custom sysctl file for testing system_wide=false
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
# Custom sysctl test file
|
||||
vm.dirty_background_ratio=5
|
||||
dest: "{{ output_dir_test }}/custom_sysctl.conf"
|
||||
mode: "0644"
|
||||
|
||||
- name: Set vm.dirty_background_ratio with system_wide=false
|
||||
ansible.posix.sysctl:
|
||||
name: vm.dirty_background_ratio
|
||||
value: 10
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: false
|
||||
sysctl_file: "{{ output_dir_test }}/custom_sysctl.conf"
|
||||
register: sysctl_system_false_test
|
||||
|
||||
- name: Check custom sysctl file content
|
||||
ansible.builtin.command: cat {{ output_dir_test }}/custom_sysctl.conf
|
||||
changed_when: false
|
||||
register: custom_sysctl_content
|
||||
|
||||
- name: Validate system_wide=false behavior
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_false_test is changed
|
||||
- "'vm.dirty_background_ratio=10' in custom_sysctl_content.stdout"
|
||||
|
||||
# Test system_wide with check mode
|
||||
- name: Test system_wide in check mode
|
||||
ansible.posix.sysctl:
|
||||
name: vm.swappiness
|
||||
value: 25
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: true
|
||||
check_mode: true
|
||||
register: sysctl_system_wide_check_mode
|
||||
|
||||
- name: Validate check mode works with system_wide
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_wide_check_mode is changed
|
||||
|
||||
# Test system_wide with missing directories (should not fail)
|
||||
- name: Test system_wide with potentially missing directories
|
||||
ansible.posix.sysctl:
|
||||
name: vm.overcommit_memory
|
||||
value: 1
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: true
|
||||
ignoreerrors: true
|
||||
register: sysctl_system_wide_missing_dirs
|
||||
|
||||
- name: Validate system_wide handles missing directories
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_wide_missing_dirs is not failed
|
||||
|
||||
- name: Test system_wide with multiple configuration files (RHEL/CentOS only)
|
||||
when:
|
||||
- ansible_facts.os_family == 'RedHat'
|
||||
- ansible_facts.virtualization_type != 'docker'
|
||||
block:
|
||||
# Test that system_wide processes multiple configuration files
|
||||
- name: Create test sysctl.d file
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
# Test system-wide sysctl reload
|
||||
vm.dirty_writeback_centisecs=500
|
||||
dest: /etc/sysctl.d/99-ansible-test.conf
|
||||
mode: "0644"
|
||||
backup: true
|
||||
register: test_sysctl_file
|
||||
|
||||
- name: Apply setting with system_wide to test multiple file processing
|
||||
ansible.posix.sysctl:
|
||||
name: vm.overcommit_memory
|
||||
value: 1
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: true
|
||||
register: sysctl_multifile_test
|
||||
|
||||
- name: Verify both settings are applied
|
||||
ansible.builtin.shell: |
|
||||
sysctl -n vm.dirty_writeback_centisecs
|
||||
sysctl -n vm.overcommit_memory
|
||||
changed_when: false
|
||||
register: sysctl_multifile_check
|
||||
|
||||
- name: Validate multiple file processing
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_multifile_test is changed
|
||||
- "'500' in sysctl_multifile_check.stdout"
|
||||
- "'1' in sysctl_multifile_check.stdout"
|
||||
|
||||
- name: Cleanup test sysctl.d file
|
||||
ansible.builtin.file:
|
||||
path: /etc/sysctl.d/99-ansible-test.conf
|
||||
state: absent
|
||||
|
||||
- name: Test system_wide parameter combinations
|
||||
block:
|
||||
# Test system_wide with sysctl_set
|
||||
- name: Test system_wide with sysctl_set=true
|
||||
ansible.posix.sysctl:
|
||||
name: vm.swappiness
|
||||
value: 15
|
||||
state: present
|
||||
reload: true
|
||||
system_wide: true
|
||||
sysctl_set: true
|
||||
register: sysctl_system_wide_set_test
|
||||
|
||||
- name: Check vm.swappiness value after system_wide + sysctl_set
|
||||
ansible.builtin.command: sysctl -n vm.swappiness
|
||||
changed_when: false
|
||||
register: sysctl_check_swappiness_set
|
||||
|
||||
- name: Validate system_wide with sysctl_set
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_wide_set_test is changed
|
||||
- sysctl_check_swappiness_set.stdout == "15"
|
||||
|
||||
# Test system_wide with reload=false (should not trigger system reload)
|
||||
- name: Test system_wide with reload=false
|
||||
ansible.posix.sysctl:
|
||||
name: vm.dirty_ratio
|
||||
value: 25
|
||||
state: present
|
||||
reload: false
|
||||
system_wide: true
|
||||
register: sysctl_system_wide_no_reload
|
||||
|
||||
- name: Validate system_wide with reload=false
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- sysctl_system_wide_no_reload is changed
|
||||
1
tests/sanity/ignore-2.20.txt
Normal file
1
tests/sanity/ignore-2.20.txt
Normal file
@@ -0,0 +1 @@
|
||||
tests/utils/shippable/timing.py shebang
|
||||
@@ -62,15 +62,15 @@ else
|
||||
retry pip install "https://github.com/ansible/ansible/archive/stable-${ansible_version}.tar.gz" --disable-pip-version-check
|
||||
fi
|
||||
|
||||
export ANSIBLE_COLLECTIONS_PATHS="${PWD}/../../../"
|
||||
export ANSIBLE_COLLECTIONS_PATH="${PWD}/../../../"
|
||||
|
||||
# START: HACK install dependencies
|
||||
if [ "${ansible_version}" == "2.9" ] || [ "${ansible_version}" == "2.10" ]; then
|
||||
# Note: Since community.general 5.x, Ansible Core versions prior to 2.11 are not supported.
|
||||
# So we need to use 4.8.1 for Ansible 2.9 and Ansible Engine 2.10.
|
||||
retry git clone --depth=1 --single-branch -b 4.8.1 https://github.com/ansible-collections/community.general.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/general"
|
||||
retry git clone --depth=1 --single-branch -b 4.8.1 https://github.com/ansible-collections/community.general.git "${ANSIBLE_COLLECTIONS_PATH}/ansible_collections/community/general"
|
||||
else
|
||||
retry git clone --depth=1 --single-branch https://github.com/ansible-collections/community.general.git "${ANSIBLE_COLLECTIONS_PATHS}/ansible_collections/community/general"
|
||||
retry git clone --depth=1 --single-branch https://github.com/ansible-collections/community.general.git "${ANSIBLE_COLLECTIONS_PATH}/ansible_collections/community/general"
|
||||
fi
|
||||
# Note: we're installing with git to work around Galaxy being a huge PITA (https://github.com/ansible/galaxy/issues/2429)
|
||||
# END: HACK
|
||||
|
||||
Reference in New Issue
Block a user