mirror of
https://github.com/ansible-collections/ansible.posix.git
synced 2026-01-12 07:35:31 +01:00
Compare commits
16 commits
2244bcbd12
...
43a0758078
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43a0758078 | ||
|
|
1994b2cf1c | ||
|
|
2f224e6a6a | ||
|
|
96ec2097cc | ||
|
|
7b9b1f4957 | ||
|
|
d05a5c70b5 | ||
|
|
572167b9c1 | ||
|
|
2c8aad9f39 | ||
|
|
70b838f031 | ||
|
|
5a16ef3bea | ||
|
|
841a0f3314 | ||
|
|
5bc6f636f7 | ||
|
|
284025660c | ||
|
|
f7f54f242d | ||
|
|
966df79767 | ||
|
|
5ee818ec86 |
9 changed files with 163 additions and 22 deletions
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.
|
||||
|
|
@ -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).
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
@ -196,7 +216,7 @@ class CallbackModule(CallbackBase):
|
|||
# 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)
|
||||
|
|
|
|||
|
|
@ -87,7 +87,8 @@ options:
|
|||
real source. V(absent) does not unmount recursively, and the module will
|
||||
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
|
||||
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
|
||||
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
|
||||
|
|
@ -132,6 +133,16 @@ options:
|
|||
the original file back if you somehow clobbered it incorrectly.
|
||||
type: bool
|
||||
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:
|
||||
- As of Ansible 2.3, the O(name) option has been changed to O(path) as
|
||||
default, but O(name) still works as well.
|
||||
|
|
@ -175,6 +186,23 @@ EXAMPLES = r'''
|
|||
path: /tmp/mnt-pnt
|
||||
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
|
||||
# a reboot, or until calling "state: unmounted" followed by "state: mounted"
|
||||
# on the same "path"
|
||||
|
|
@ -779,6 +807,7 @@ def main():
|
|||
src=dict(type='path'),
|
||||
backup=dict(type='bool', default=False),
|
||||
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,
|
||||
required_if=(
|
||||
|
|
@ -896,7 +925,7 @@ def main():
|
|||
module.fail_json(
|
||||
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:
|
||||
os.rmdir(name)
|
||||
except (OSError, IOError) as e:
|
||||
|
|
|
|||
|
|
@ -1132,3 +1132,85 @@
|
|||
loop:
|
||||
- /tmp/myfs.img
|
||||
- /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
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
Loading…
Reference in a new issue