Add a few things; nfs_lazy_reboot2.yml/nfs_lazy_reboot3.yml are valid; v2 is best POC
This commit is contained in:
@ -14,6 +14,7 @@ timeout = 30
|
||||
host_key_checking = false
|
||||
display_skipped_hosts = false
|
||||
deprecation_warnings = false
|
||||
# task_timeout = 10
|
||||
|
||||
# callback_whitelist is deprecated
|
||||
# we only include here for backwards compatibility
|
||||
|
44
nfs_lazy_reboot.yml
Normal file
44
nfs_lazy_reboot.yml
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
- name: Something
|
||||
hosts: temp
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
# With NFS share(s) being in a hung state, we cannot utilize `gather_facts`
|
||||
# as that too hangs when it tries to figure out the current mounts on the
|
||||
# system
|
||||
tasks:
|
||||
- name: Capture NFS mounts on host
|
||||
ansible.builtin.set_fact:
|
||||
captured_nfs_mounts: "{{ ansible_mounts | selectattr('fstype', 'search', 'nfs') }}"
|
||||
|
||||
- name: Verify mount status and reboot
|
||||
block:
|
||||
- name: Verify mount status
|
||||
ansible.builtin.command: "ls {{ item['mount'] }}"
|
||||
timeout: 5
|
||||
register: r_verify_mounts
|
||||
loop: "{{ captured_nfs_mounts }}"
|
||||
loop_control:
|
||||
label: "{{ item['mount'] }}"
|
||||
|
||||
rescue:
|
||||
- name: Debug item
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ r_verify_mounts }}"
|
||||
|
||||
- name: Group failed shares together
|
||||
ansible.builtin.set_fact:
|
||||
__failed_nfs_shares:
|
||||
"{{ r_verify_mounts['results'] | selectattr('failed') | map(attribute='item') | list }}"
|
||||
|
||||
- name: Lazily unmount failed shares
|
||||
ansible.builtin.command: "umount -f -l {{ item['mount'] }}"
|
||||
loop: "{{ __failed_nfs_shares }}"
|
||||
loop_control:
|
||||
label: "{{ item['mount'] }}"
|
||||
|
||||
always:
|
||||
- name: Reboot host # noqa: no-handler
|
||||
ansible.builtin.import_role:
|
||||
name: verified_reboot
|
54
nfs_lazy_reboot2 copy.yml
Normal file
54
nfs_lazy_reboot2 copy.yml
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
- name: Something
|
||||
hosts: temp
|
||||
become: true
|
||||
gather_facts: false
|
||||
|
||||
# With NFS share(s) being in a hung state, we cannot properly utilize
|
||||
# `gather_facts` as that too hangs when it tries to figure out the current
|
||||
# mounts on the system
|
||||
tasks:
|
||||
- name: Check for mounted NFS shares # noqa: command-instead-of-module
|
||||
ansible.builtin.command: mount -t nfs,nfs4
|
||||
register: nfs_mounts_result
|
||||
changed_when: false
|
||||
failed_when: nfs_mounts_result['rc'] not in [0, 32]
|
||||
|
||||
- name: Create a list of NFS mount points from command output
|
||||
ansible.builtin.set_fact:
|
||||
nfs_mount_list: "{{ nfs_mounts_result['stdout_lines'] | map('split') | map(attribute=2) | list }}"
|
||||
|
||||
- name: Verify mount status and reboot
|
||||
block:
|
||||
- name: Verify mount status
|
||||
ansible.builtin.command: "ls {{ item }}"
|
||||
timeout: 5
|
||||
register: r_verify_mounts
|
||||
loop: "{{ nfs_mount_list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
rescue:
|
||||
- name: Debug item
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ r_verify_mounts }}"
|
||||
|
||||
- name: Group failed shares together
|
||||
ansible.builtin.set_fact:
|
||||
failed_nfs_shares:
|
||||
"{{ r_verify_mounts['results'] | selectattr('failed') | map(attribute='item') | list }}"
|
||||
|
||||
- name: Debugb failed_nfs_shares
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ failed_nfs_shares }}"
|
||||
|
||||
- name: Lazily unmount failed shares
|
||||
ansible.builtin.command: "umount -f -l {{ item }}"
|
||||
loop: "{{ failed_nfs_shares }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
always:
|
||||
- name: Reboot host if file changes # noqa: no-handler
|
||||
ansible.builtin.import_role:
|
||||
name: verified_reboot
|
49
nfs_lazy_reboot2.yml
Normal file
49
nfs_lazy_reboot2.yml
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
- name: Something
|
||||
hosts: temp
|
||||
become: true
|
||||
gather_facts: false
|
||||
|
||||
# With NFS share(s) being in a hung state, we cannot utilize `gather_facts`
|
||||
# as that too hangs when it tries to figure out the current mounts on the
|
||||
# system
|
||||
tasks:
|
||||
- name: Check for mounted NFS shares # noqa: command-instead-of-module
|
||||
ansible.builtin.command: mount -t nfs,nfs4
|
||||
register: nfs_mounts_result
|
||||
changed_when: false
|
||||
failed_when: nfs_mounts_result['rc'] not in [0, 32]
|
||||
|
||||
- name: Create a list of NFS mount points
|
||||
ansible.builtin.set_fact:
|
||||
nfs_mount_list: "{{ nfs_mounts_result['stdout_lines'] | map('split') | map(attribute=2) | list }}"
|
||||
|
||||
- name: Verify mount status and reboot host
|
||||
block:
|
||||
- name: Verify mount status
|
||||
ansible.builtin.command: "ls {{ item }}"
|
||||
timeout: 5
|
||||
register: r_verify_mounts
|
||||
loop: "{{ nfs_mount_list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
rescue:
|
||||
- name: Group shares that failed check
|
||||
ansible.builtin.set_fact:
|
||||
failed_nfs_shares:
|
||||
"{{ r_verify_mounts['results'] | selectattr('failed') | map(attribute='item') | list }}"
|
||||
|
||||
- name: Lazily unmount the failed shares
|
||||
ansible.builtin.command: "umount -f -l {{ item }}"
|
||||
register: r_lazy_unmount
|
||||
async: 30
|
||||
poll: 0
|
||||
loop: "{{ failed_nfs_shares }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
always:
|
||||
- name: Reboot host # noqa: no-handler
|
||||
ansible.builtin.import_role:
|
||||
name: verified_reboot
|
46
nfs_lazy_reboot3.yml
Normal file
46
nfs_lazy_reboot3.yml
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
- name: Something
|
||||
hosts: temp
|
||||
become: true
|
||||
gather_facts: false
|
||||
|
||||
# With NFS share(s) being in a hung state, we cannot utilize `gather_facts`
|
||||
# as that too hangs when it tries to figure out the current mounts on the
|
||||
# system
|
||||
tasks:
|
||||
- name: Check for mounted NFS shares # noqa: command-instead-of-module
|
||||
ansible.builtin.command: mount -t nfs,nfs4
|
||||
register: nfs_mounts_result
|
||||
changed_when: false
|
||||
failed_when: nfs_mounts_result['rc'] not in [0, 32]
|
||||
|
||||
- name: Create a list of NFS mount points from command output
|
||||
ansible.builtin.set_fact:
|
||||
nfs_mount_list: "{{ nfs_mounts_result['stdout_lines'] | map('split') | map(attribute=2) | list }}"
|
||||
|
||||
- name: Verify mount status
|
||||
ansible.builtin.command: "ls {{ item }}"
|
||||
timeout: 5
|
||||
register: r_verify_mounts
|
||||
ignore_errors: true
|
||||
loop: "{{ nfs_mount_list }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
- name: Group failed shares together
|
||||
ansible.builtin.set_fact:
|
||||
failed_nfs_shares:
|
||||
"{{ r_verify_mounts['results'] | selectattr('failed') | map(attribute='item') | list }}"
|
||||
|
||||
- name: Lazily unmount failed shares
|
||||
ansible.builtin.command: "umount -f -l {{ item }}"
|
||||
async: 30
|
||||
poll: 0
|
||||
register: r_lazy_unmount
|
||||
loop: "{{ failed_nfs_shares }}"
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
|
||||
- name: Reboot host # noqa: no-handler
|
||||
ansible.builtin.import_role:
|
||||
name: verified_reboot
|
23
nfs_lazy_reboot_debug.yml
Normal file
23
nfs_lazy_reboot_debug.yml
Normal file
@ -0,0 +1,23 @@
|
||||
---
|
||||
- name: Gather NFS mounts without using Ansible facts
|
||||
hosts: temp
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Check for mounted NFS shares 🔎 # noqa: command-instead-of-module
|
||||
ansible.builtin.command: mount -t nfs,nfs4
|
||||
register: nfs_mounts_result
|
||||
changed_when: false
|
||||
failed_when: nfs_mounts_result.rc not in [0, 32]
|
||||
|
||||
- name: Debug nfs_mounts_result 🔎
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ nfs_mounts_result }}"
|
||||
|
||||
- name: Create a list of NFS mount points from command output 📝
|
||||
ansible.builtin.set_fact:
|
||||
nfs_mount_list: "{{ nfs_mounts_result.stdout_lines | map('split') | map(attribute=2) | list }}"
|
||||
|
||||
- name: Display the discovered NFS mount points ✅
|
||||
ansible.builtin.debug:
|
||||
msg: "Discovered NFS mounts: {{ nfs_mount_list }}"
|
@ -1,20 +1,8 @@
|
||||
---
|
||||
# -l, --lazy
|
||||
# Lazy unmount. Detach the filesystem from the file hierarchy now,
|
||||
# and clean up all references to this filesystem as soon as it
|
||||
# is not busy anymore.
|
||||
|
||||
# A system reboot would be expected in near future if you’re going to use
|
||||
# this option for network filesystem or local filesystem with submounts.
|
||||
#
|
||||
# The recommended use-case for umount -l is to prevent hangs on shutdown
|
||||
# due to an unreachable network share where a normal umount will hang
|
||||
# due to a downed server or a network partition. Remounts of the share
|
||||
# will not be possible.
|
||||
- name: Something
|
||||
hosts: temp
|
||||
become: true
|
||||
gather_facts: false
|
||||
gather_facts: true
|
||||
|
||||
vars:
|
||||
__nfs_src: 10.10.42.180
|
||||
@ -22,18 +10,17 @@
|
||||
__nfs_mnt_pnt: /nfs/backups
|
||||
|
||||
tasks:
|
||||
- name: Lazily unmount the NFS share
|
||||
ansible.builtin.command: "umount -f -l {{ __nfs_mnt_pnt }}"
|
||||
- name: Verify mount status and reboot
|
||||
block:
|
||||
- name: Verify mount status
|
||||
ansible.builtin.command: df
|
||||
timeout: 5
|
||||
|
||||
- name: Reboot host if file changes # noqa: no-handler
|
||||
ansible.builtin.import_role:
|
||||
name: verified_reboot
|
||||
rescue:
|
||||
- name: Lazily unmount the NFS share
|
||||
ansible.builtin.command: "umount -f -l {{ __nfs_mnt_pnt }}"
|
||||
|
||||
- name: Unlazily re-mount the file system
|
||||
ansible.posix.mount:
|
||||
state: mounted
|
||||
src: "{{ __nfs_src }}:{{ __nfs_share }}"
|
||||
path: "{{ __nfs_mnt_pnt }}"
|
||||
opts: rw,noatime
|
||||
boot: false
|
||||
fstype: nfs
|
||||
always:
|
||||
- name: Reboot host if file changes # noqa: no-handler
|
||||
ansible.builtin.import_role:
|
||||
name: verified_reboot
|
||||
|
60
scripts/write_file_msg2.py
Normal file
60
scripts/write_file_msg2.py
Normal file
@ -0,0 +1,60 @@
|
||||
import os
|
||||
import readline
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import time
|
||||
|
||||
# Tab completion setup for file paths
|
||||
def complete_path(text, state):
|
||||
expanded = os.path.expanduser(os.path.expandvars(text))
|
||||
|
||||
if os.path.isdir(expanded):
|
||||
try:
|
||||
entries = os.listdir(expanded)
|
||||
matches = [os.path.abspath(os.path.join(expanded, entry)) + '/'
|
||||
if os.path.isdir(os.path.join(expanded, entry))
|
||||
else os.path.abspath(os.path.join(expanded, entry))
|
||||
for entry in entries]
|
||||
except FileNotFoundError:
|
||||
matches = []
|
||||
else:
|
||||
dirname = os.path.dirname(expanded) or '.'
|
||||
basename = os.path.basename(expanded)
|
||||
try:
|
||||
entries = [entry for entry in os.listdir(dirname) if entry.startswith(basename)]
|
||||
matches = [os.path.abspath(os.path.join(dirname, entry)) for entry in entries]
|
||||
except FileNotFoundError:
|
||||
matches = []
|
||||
|
||||
matches.sort()
|
||||
try:
|
||||
return matches[state]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
readline.set_completer_delims(' \t\n;')
|
||||
readline.set_completer(complete_path)
|
||||
readline.parse_and_bind('tab: complete')
|
||||
|
||||
# Parse command-line arguments
|
||||
parser = argparse.ArgumentParser(description="Write messages to a file.")
|
||||
parser.add_argument("filename", nargs="?", help="Path to the file to write to.")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Ask for filename if not provided
|
||||
file_path = args.filename or input("Enter filename: ")
|
||||
|
||||
# Message writing loop
|
||||
name = "hi"
|
||||
age = 30
|
||||
max_iterations = 1000
|
||||
|
||||
try:
|
||||
for i in range(max_iterations):
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
message = "[{}] My name is {} and I am {} years old.\n".format(timestamp, name, age)
|
||||
with open(file_path, "a") as file:
|
||||
file.write(message)
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
print("\n[Interrupted] Ctrl+C detected. Stopped writing to file.")
|
62
scripts/write_file_msg3.py
Normal file
62
scripts/write_file_msg3.py
Normal file
@ -0,0 +1,62 @@
|
||||
import os
|
||||
import readline
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import time
|
||||
|
||||
# --- Tab Completion ---
|
||||
def complete_path(text, state):
|
||||
expanded = os.path.expanduser(os.path.expandvars(text))
|
||||
if os.path.isdir(expanded):
|
||||
try:
|
||||
entries = os.listdir(expanded)
|
||||
matches = [os.path.abspath(os.path.join(expanded, entry)) + '/'
|
||||
if os.path.isdir(os.path.join(expanded, entry))
|
||||
else os.path.abspath(os.path.join(expanded, entry))
|
||||
for entry in entries]
|
||||
except FileNotFoundError:
|
||||
matches = []
|
||||
else:
|
||||
dirname = os.path.dirname(expanded) or '.'
|
||||
basename = os.path.basename(expanded)
|
||||
try:
|
||||
entries = [entry for entry in os.listdir(dirname) if entry.startswith(basename)]
|
||||
matches = [os.path.abspath(os.path.join(dirname, entry)) for entry in entries]
|
||||
except FileNotFoundError:
|
||||
matches = []
|
||||
matches.sort()
|
||||
try:
|
||||
return matches[state]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
readline.set_completer_delims(' \t\n;')
|
||||
readline.set_completer(complete_path)
|
||||
readline.parse_and_bind('tab: complete')
|
||||
|
||||
# --- Argument Parsing ---
|
||||
parser = argparse.ArgumentParser(description="Write messages to a file with optional verbosity and interval.")
|
||||
parser.add_argument("filename", nargs="?", help="Path to the file to write to.")
|
||||
parser.add_argument("--verbose", action="store_true", help="Print each message to console.")
|
||||
parser.add_argument("--interval", type=float, default=1.0, help="Delay between writes in seconds.")
|
||||
args = parser.parse_args()
|
||||
|
||||
# --- Filename prompt fallback ---
|
||||
file_path = args.filename or input("Enter filename: ")
|
||||
|
||||
# --- Message writing loop ---
|
||||
name = "hi"
|
||||
age = 30
|
||||
max_iterations = 1000
|
||||
|
||||
try:
|
||||
for i in range(max_iterations):
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
message = f"[{timestamp}] My name is {name} and I am {age} years old.\n"
|
||||
with open(file_path, "a") as file:
|
||||
file.write(message)
|
||||
if args.verbose:
|
||||
print(message.strip())
|
||||
time.sleep(args.interval)
|
||||
except KeyboardInterrupt:
|
||||
print("\n[Interrupted] Ctrl+C detected. Stopped writing to file.")
|
22
timeout_test1.yml
Normal file
22
timeout_test1.yml
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
- name: Demonstrate module timeout
|
||||
hosts: localhost
|
||||
connection: local
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Check if network share is hung and reboot
|
||||
block:
|
||||
- name: Check mounts
|
||||
ansible.builtin.command: sleep 30
|
||||
timeout: 10
|
||||
|
||||
rescue:
|
||||
- name: Lazily unmount the file system
|
||||
ansible.builtin.debug:
|
||||
msg: unmount stuff goes here
|
||||
|
||||
always:
|
||||
- name: Reboot the host
|
||||
ansible.builtin.debug:
|
||||
msg: include_role verified_reboot
|
31
timeout_test2.yml
Normal file
31
timeout_test2.yml
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
- name: Demonstrate module timeout
|
||||
hosts: temp
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Check mounts
|
||||
ansible.builtin.command: umount -f -l /nfs/backups
|
||||
register: r_check_mounts
|
||||
async: 300
|
||||
poll: 0
|
||||
|
||||
- name: Debug r_check_mounts
|
||||
ansible.builtin.debug:
|
||||
var: r_check_mounts
|
||||
|
||||
# - name: Check polling
|
||||
# ansible.builtin.async_status:
|
||||
# jid: "{{ r_check_mounts['ansible_job_id'] }}"
|
||||
# register: async_check
|
||||
# until: async_check['finished']
|
||||
# retries: 10
|
||||
# delay: 3
|
||||
|
||||
# - name: Debug async_check
|
||||
# ansible.builtin.debug:
|
||||
# var: async_check
|
||||
|
||||
# - name: Hi
|
||||
# ansible.builtin.debug:
|
||||
# msg: "hi"
|
Reference in New Issue
Block a user