mirror of
https://github.com/ansible-collections/ansible.posix.git
synced 2026-01-11 15:15:26 +01:00
Compare commits
19 commits
59fef9a11f
...
f02fbfaa23
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f02fbfaa23 | ||
|
|
b39ee97ccc | ||
|
|
72a6eb9729 | ||
|
|
9651a19805 | ||
|
|
413ab782a8 | ||
|
|
9343c6f56f | ||
|
|
9dc73a686a | ||
|
|
cda2e0657f | ||
|
|
d05a5c70b5 | ||
|
|
572167b9c1 | ||
|
|
2c8aad9f39 | ||
|
|
70b838f031 | ||
|
|
5a16ef3bea | ||
|
|
841a0f3314 | ||
|
|
5bc6f636f7 | ||
|
|
284025660c | ||
|
|
f7f54f242d | ||
|
|
966df79767 | ||
|
|
5ee818ec86 |
13 changed files with 202 additions and 22 deletions
|
|
@ -4,7 +4,8 @@
|
||||||
# SPDX-FileCopyrightText: 2024, Ansible Project
|
# SPDX-FileCopyrightText: 2024, Ansible Project
|
||||||
|
|
||||||
skip_list:
|
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/
|
- fqcn[deep] # This rule produces false positives for files in tests/unit/plugins/action/fixtures/
|
||||||
|
- sanity[cannot-ignore] # This rule is skipped to keep backward compatibility with Python 2
|
||||||
exclude_paths:
|
exclude_paths:
|
||||||
- changelogs/
|
- changelogs/
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ pool: Standard
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- stage: Sanity_devel
|
- stage: Sanity_devel
|
||||||
displayName: Ansible devel sanity
|
displayName: Ansible devel Sanity & Units & Lint
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
jobs:
|
jobs:
|
||||||
- template: templates/matrix.yml
|
- template: templates/matrix.yml
|
||||||
|
|
@ -58,7 +58,7 @@ stages:
|
||||||
- name: Lint
|
- name: Lint
|
||||||
test: lint
|
test: lint
|
||||||
- stage: Sanity_2_19
|
- stage: Sanity_2_19
|
||||||
displayName: Ansible 2.19 sanitay & Units & Lint
|
displayName: Ansible 2.19 Sanity & Units & Lint
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
jobs:
|
jobs:
|
||||||
- template: templates/matrix.yml
|
- template: templates/matrix.yml
|
||||||
|
|
@ -73,7 +73,7 @@ stages:
|
||||||
- name: Lint
|
- name: Lint
|
||||||
test: lint
|
test: lint
|
||||||
- stage: Sanity_2_18
|
- stage: Sanity_2_18
|
||||||
displayName: Ansible 2.18 sanity & Units & Lint
|
displayName: Ansible 2.18 Sanity & Units & Lint
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
jobs:
|
jobs:
|
||||||
- template: templates/matrix.yml
|
- template: templates/matrix.yml
|
||||||
|
|
@ -88,7 +88,7 @@ stages:
|
||||||
- name: Lint
|
- name: Lint
|
||||||
test: lint
|
test: lint
|
||||||
- stage: Sanity_2_17
|
- stage: Sanity_2_17
|
||||||
displayName: Ansible 2.17 sanity & Units & Lint
|
displayName: Ansible 2.17 Sanity & Units & Lint
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
jobs:
|
jobs:
|
||||||
- template: templates/matrix.yml
|
- template: templates/matrix.yml
|
||||||
|
|
@ -103,7 +103,7 @@ stages:
|
||||||
- name: Lint
|
- name: Lint
|
||||||
test: lint
|
test: lint
|
||||||
- stage: Sanity_2_16
|
- stage: Sanity_2_16
|
||||||
displayName: Ansible 2.16 sanity & Units & Lint
|
displayName: Ansible 2.16 Sanity & Units & Lint
|
||||||
dependsOn: []
|
dependsOn: []
|
||||||
jobs:
|
jobs:
|
||||||
- template: templates/matrix.yml
|
- template: templates/matrix.yml
|
||||||
|
|
@ -115,6 +115,8 @@ stages:
|
||||||
test: sanity
|
test: sanity
|
||||||
- name: Units
|
- name: Units
|
||||||
test: units
|
test: units
|
||||||
|
- name: Lint
|
||||||
|
test: lint
|
||||||
## Docker
|
## Docker
|
||||||
- stage: Docker_devel
|
- stage: Docker_devel
|
||||||
displayName: Docker devel
|
displayName: Docker devel
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<!-- Add CI and code coverage badges here. Samples included below. -->
|
<!-- Add CI and code coverage badges here. Samples included below. -->
|
||||||
[](https://dev.azure.com/ansible/ansible.posix/_build?definitionId=26)
|
https://dev.azure.com/ansible/ansible.posix/_apis/build/status/CI?branchName=main)](https://dev.azure.com/ansible/ansible.posix/_build?definitionId=26)
|
||||||
[]() <!--[](https://codecov.io/gh/ansible-collections/ansible.posix)-->
|
[](https://codecov.io/gh/ansible-collections/ansible.posix)
|
||||||
|
|
||||||
## Communication
|
## Communication
|
||||||
|
|
||||||
|
|
|
||||||
3
changelogs/fragments/569_keep_mountpoint.yml
Normal file
3
changelogs/fragments/569_keep_mountpoint.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
minor_changes:
|
||||||
|
- keep_mountpoint - added keep_mountpoint option with default value false. If set to true keep_mountpoint changes the behaviour of state\: absent by keeping the mountpoint.
|
||||||
3
changelogs/fragments/639_fix_authorized_key.yml
Normal file
3
changelogs/fragments/639_fix_authorized_key.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
bugfixes:
|
||||||
|
- ansible.posix.authorized_key - fixes error on permission denied in authorized_key module (https://github.com/ansible-collections/ansible.posix/issues/462).
|
||||||
4
changelogs/fragments/682_update_ci_20250929.yml
Normal file
4
changelogs/fragments/682_update_ci_20250929.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
trivial:
|
||||||
|
- Updatng AZP CI matrix to ignore ansible-bad-import-from on six(https://github.com/ansible-collections/ansible.posix/pull/682).
|
||||||
|
- Skipped sanity[cannot-ignore] to keep backward compatibility with Python2.
|
||||||
|
- Consolidate all ansible-lint option locations into .ansible-lint file.
|
||||||
|
|
@ -225,6 +225,8 @@ import os.path
|
||||||
import tempfile
|
import tempfile
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
|
import errno
|
||||||
|
import traceback
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
|
|
||||||
from ansible.module_utils._text import to_native
|
from ansible.module_utils._text import to_native
|
||||||
|
|
@ -475,16 +477,18 @@ def parsekey(module, raw_key, rank=None):
|
||||||
return (key, key_type, options, comment, rank)
|
return (key, key_type, options, comment, rank)
|
||||||
|
|
||||||
|
|
||||||
def readfile(filename):
|
def readfile(module, filename):
|
||||||
|
|
||||||
if not os.path.isfile(filename):
|
|
||||||
return ''
|
|
||||||
|
|
||||||
f = open(filename)
|
|
||||||
try:
|
try:
|
||||||
|
with open(filename, 'r') as f:
|
||||||
return f.read()
|
return f.read()
|
||||||
finally:
|
except IOError as e:
|
||||||
f.close()
|
if e.errno == errno.EACCES:
|
||||||
|
module.fail_json(msg="Permission denied on file or path for authorized keys file: %s" % filename,
|
||||||
|
exception=traceback.format_exc())
|
||||||
|
elif e.errno == errno.ENOENT:
|
||||||
|
return ''
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
def parsekeys(module, lines):
|
def parsekeys(module, lines):
|
||||||
|
|
@ -597,7 +601,7 @@ def enforce_state(module, params):
|
||||||
# check current state -- just get the filename, don't create file
|
# check current state -- just get the filename, don't create file
|
||||||
do_write = False
|
do_write = False
|
||||||
params["keyfile"] = keyfile(module, user, do_write, path, manage_dir)
|
params["keyfile"] = keyfile(module, user, do_write, path, manage_dir)
|
||||||
existing_content = readfile(params["keyfile"])
|
existing_content = readfile(module, params["keyfile"])
|
||||||
existing_keys = parsekeys(module, existing_content)
|
existing_keys = parsekeys(module, existing_content)
|
||||||
|
|
||||||
# Add a place holder for keys that should exist in the state=present and
|
# Add a place holder for keys that should exist in the state=present and
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,8 @@ options:
|
||||||
real source. V(absent) does not unmount recursively, and the module will
|
real source. V(absent) does not unmount recursively, and the module will
|
||||||
fail if multiple devices are mounted on the same mount point. Using
|
fail if multiple devices are mounted on the same mount point. Using
|
||||||
V(absent) with a mount point that is not registered in the I(fstab) has
|
V(absent) with a mount point that is not registered in the I(fstab) has
|
||||||
no effect, use V(unmounted) instead.
|
no effect, use V(unmounted) instead. You can set O(keep_mountpoint) to
|
||||||
|
True to keep the mountpoint.
|
||||||
- V(remounted) specifies that the device will be remounted for when you
|
- V(remounted) specifies that the device will be remounted for when you
|
||||||
want to force a refresh on the mount itself (added in 2.9). This will
|
want to force a refresh on the mount itself (added in 2.9). This will
|
||||||
always return RV(ignore:changed=true). If O(opts) is set, the options will be
|
always return RV(ignore:changed=true). If O(opts) is set, the options will be
|
||||||
|
|
@ -132,6 +133,16 @@ options:
|
||||||
the original file back if you somehow clobbered it incorrectly.
|
the original file back if you somehow clobbered it incorrectly.
|
||||||
type: bool
|
type: bool
|
||||||
default: false
|
default: false
|
||||||
|
keep_mountpoint:
|
||||||
|
description:
|
||||||
|
- Change the default behaviour of state=absent by keeping the mountpoint
|
||||||
|
- With keep_mountpoint=true, state=absent is like unmounted plus the
|
||||||
|
fstab update.
|
||||||
|
- Use it if you care about finding original mountpoint content without failing
|
||||||
|
and want to remove the entry in fstab. If you have no entry to clean in
|
||||||
|
fstab you can use state=unmounted
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
notes:
|
notes:
|
||||||
- As of Ansible 2.3, the O(name) option has been changed to O(path) as
|
- As of Ansible 2.3, the O(name) option has been changed to O(path) as
|
||||||
default, but O(name) still works as well.
|
default, but O(name) still works as well.
|
||||||
|
|
@ -175,6 +186,23 @@ EXAMPLES = r'''
|
||||||
path: /tmp/mnt-pnt
|
path: /tmp/mnt-pnt
|
||||||
state: remounted
|
state: remounted
|
||||||
|
|
||||||
|
# The following will fail on first run
|
||||||
|
# if /home/mydir is not empty after unmounting,
|
||||||
|
# though unmount and remove from fstab are successfull.
|
||||||
|
# It will be successfull on subsequent runs (already unmounted).
|
||||||
|
- name: Unmount and remove from fstab, then if unmount was necessary try to remove mountpoint /home/mydir
|
||||||
|
ansible.posix.mount:
|
||||||
|
path: /home/mydir
|
||||||
|
state: absent
|
||||||
|
# The following will not fail on first run
|
||||||
|
# if /home/mydir is not empty after unmounting.
|
||||||
|
# It will leave /home/mydir and its content (if any) after unmounting.
|
||||||
|
- name: Unmount and remove from fstab, but keep /home/mydir
|
||||||
|
ansible.posix.mount:
|
||||||
|
path: /home/mydir
|
||||||
|
state: absent
|
||||||
|
keep_mountpoint: true
|
||||||
|
|
||||||
# The following will not save changes to fstab, and only be temporary until
|
# The following will not save changes to fstab, and only be temporary until
|
||||||
# a reboot, or until calling "state: unmounted" followed by "state: mounted"
|
# a reboot, or until calling "state: unmounted" followed by "state: mounted"
|
||||||
# on the same "path"
|
# on the same "path"
|
||||||
|
|
@ -779,6 +807,7 @@ def main():
|
||||||
src=dict(type='path'),
|
src=dict(type='path'),
|
||||||
backup=dict(type='bool', default=False),
|
backup=dict(type='bool', default=False),
|
||||||
state=dict(type='str', required=True, choices=['absent', 'absent_from_fstab', 'mounted', 'present', 'unmounted', 'remounted', 'ephemeral']),
|
state=dict(type='str', required=True, choices=['absent', 'absent_from_fstab', 'mounted', 'present', 'unmounted', 'remounted', 'ephemeral']),
|
||||||
|
keep_mountpoint=dict(type='bool', default=False),
|
||||||
),
|
),
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
required_if=(
|
required_if=(
|
||||||
|
|
@ -893,7 +922,7 @@ def main():
|
||||||
module.fail_json(
|
module.fail_json(
|
||||||
msg="Error unmounting %s: %s" % (name, msg))
|
msg="Error unmounting %s: %s" % (name, msg))
|
||||||
|
|
||||||
if os.path.exists(name):
|
if os.path.exists(name) and module.params['keep_mountpoint'] is False:
|
||||||
try:
|
try:
|
||||||
os.rmdir(name)
|
os.rmdir(name)
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
# -------------------------------------------------------------
|
||||||
|
# check permissions
|
||||||
|
|
||||||
|
- name: Create a file that is not accessible
|
||||||
|
ansible.builtin.file:
|
||||||
|
state: touch
|
||||||
|
path: "{{ output_dir | expanduser }}/file_permissions"
|
||||||
|
owner: root
|
||||||
|
mode: '0000'
|
||||||
|
|
||||||
|
- name: Create unprivileged user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: nopriv
|
||||||
|
create_home: true
|
||||||
|
|
||||||
|
- name: Try to delete a key from an unreadable file
|
||||||
|
become: true
|
||||||
|
become_user: nopriv
|
||||||
|
ansible.posix.authorized_key:
|
||||||
|
user: root
|
||||||
|
key: "{{ dss_key_basic }}"
|
||||||
|
state: absent
|
||||||
|
path: "{{ output_dir | expanduser }}/file_permissions"
|
||||||
|
register: result
|
||||||
|
ignore_errors: true
|
||||||
|
|
||||||
|
- name: Assert that the key deletion has failed
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
|
||||||
|
- name: Remove the file
|
||||||
|
ansible.builtin.file:
|
||||||
|
state: absent
|
||||||
|
path: "{{ output_dir | expanduser }}/file_permissions"
|
||||||
|
|
||||||
|
- name: Remove the user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: nopriv
|
||||||
|
state: absent
|
||||||
|
|
@ -34,3 +34,6 @@
|
||||||
|
|
||||||
- name: Test for specifying key as a path
|
- name: Test for specifying key as a path
|
||||||
ansible.builtin.import_tasks: check_path.yml
|
ansible.builtin.import_tasks: check_path.yml
|
||||||
|
|
||||||
|
- name: Test for permission denied files
|
||||||
|
ansible.builtin.import_tasks: check_permissions.yml
|
||||||
|
|
|
||||||
|
|
@ -1132,3 +1132,85 @@
|
||||||
loop:
|
loop:
|
||||||
- /tmp/myfs.img
|
- /tmp/myfs.img
|
||||||
- /tmp/myfs
|
- /tmp/myfs
|
||||||
|
|
||||||
|
- name: Block to test keep_mountpoint option
|
||||||
|
block:
|
||||||
|
- name: Create the mount point
|
||||||
|
ansible.builtin.file:
|
||||||
|
state: directory
|
||||||
|
path: '/tmp/myfs'
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Create empty file for FS aaa
|
||||||
|
community.general.filesize:
|
||||||
|
path: /tmp/myfs.img
|
||||||
|
size: 20M
|
||||||
|
|
||||||
|
- name: Format FS bbb
|
||||||
|
community.general.filesystem:
|
||||||
|
fstype: xfs
|
||||||
|
dev: /tmp/myfs.img
|
||||||
|
|
||||||
|
- name: Put data in the mount point before mounting
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: 'Testing
|
||||||
|
This is the data before mounting
|
||||||
|
'
|
||||||
|
dest: '/tmp/myfs/test_file'
|
||||||
|
mode: '0644'
|
||||||
|
register: file_before_info
|
||||||
|
|
||||||
|
- name: Mount with fstab
|
||||||
|
ansible.posix.mount:
|
||||||
|
path: '/tmp/myfs'
|
||||||
|
fstype: xfs
|
||||||
|
state: mounted
|
||||||
|
src: '/tmp/myfs.img'
|
||||||
|
|
||||||
|
- name: Check data disappears - stat data
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: '/tmp/myfs/test_file'
|
||||||
|
register: file_stat_after_mount
|
||||||
|
- name: Check data disappears - file does not exist
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- file_stat_after_mount['stat']['exists'] == false
|
||||||
|
- name: Put data in the mount point after mounting
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: 'Testing
|
||||||
|
This is the data updated after mounting
|
||||||
|
'
|
||||||
|
dest: '/tmp/myfs/test_file'
|
||||||
|
mode: '0644'
|
||||||
|
register: file_after_info
|
||||||
|
- name: Umount with keep_mountpoint
|
||||||
|
ansible.posix.mount:
|
||||||
|
path: '/tmp/myfs'
|
||||||
|
fstype: xfs
|
||||||
|
state: absent
|
||||||
|
keep_mountpoint: true
|
||||||
|
- name: Check original data reappears - stat data
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: '/tmp/myfs/test_file'
|
||||||
|
register: file_stat_after_umount
|
||||||
|
- name: Check original data reappears - compare checksums
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- file_stat_after_umount['stat']['checksum'] == file_before_info['checksum']
|
||||||
|
always:
|
||||||
|
- name: Remove the first test file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /tmp/myfs/test_file
|
||||||
|
state: absent
|
||||||
|
- name: Unmount FS
|
||||||
|
ansible.posix.mount:
|
||||||
|
path: /tmp/myfs
|
||||||
|
state: absent
|
||||||
|
- name: Remove the test FS and the second test file
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: '{{ item }}'
|
||||||
|
state: absent
|
||||||
|
loop:
|
||||||
|
- /tmp/myfs/test_file
|
||||||
|
- /tmp/myfs.img
|
||||||
|
- /tmp/myfs
|
||||||
|
|
|
||||||
|
|
@ -1 +1,10 @@
|
||||||
tests/utils/shippable/timing.py shebang
|
tests/utils/shippable/timing.py shebang
|
||||||
|
plugins/action/synchronize.py pylint:ansible-bad-import-from
|
||||||
|
plugins/callback/cgroup_perf_recap.py pylint:ansible-bad-import-from
|
||||||
|
plugins/modules/mount.py pylint:ansible-bad-import-from
|
||||||
|
plugins/modules/sysctl.py pylint:ansible-bad-import-from
|
||||||
|
plugins/shell/csh.py pylint:ansible-bad-import-from
|
||||||
|
plugins/shell/fish.py pylint:ansible-bad-import-from
|
||||||
|
tests/unit/mock/procenv.py pylint:ansible-bad-import-from
|
||||||
|
tests/unit/mock/yaml_helper.py pylint:ansible-bad-import-from
|
||||||
|
tests/unit/modules/conftest.py pylint:ansible-bad-import-from
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,5 @@ command -v ansible
|
||||||
pip install --upgrade --user pip
|
pip install --upgrade --user pip
|
||||||
pip install --upgrade --user ansible-lint
|
pip install --upgrade --user ansible-lint
|
||||||
|
|
||||||
PATH="${PATH/\~/${HOME}}" ansible-lint \
|
# To specify additional options, you can specify them into .ansible-lint file.
|
||||||
--exclude changelogs/ \
|
PATH="${PATH/\~/${HOME}}" ansible-lint
|
||||||
--profile=production
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue