1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

pids module: Adding pattern and ignore_case options (#2280)

* Adding pattern and ignore_case options

* Adding changelog fragment

* Fixing changelog fragment

* Addressing FreeBSD 11.4/python 3 errors with explicit conversion

* Correcting descriptions

* Reverting back to regex input

* Fixing test syntax errors
This commit is contained in:
Ajpantuso 2021-04-21 06:45:09 -04:00 committed by GitHub
parent cecbc2be2d
commit 68243063d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 94 additions and 7 deletions

View file

@ -0,0 +1,3 @@
---
minor_changes:
- pids - new options ``pattern`` and `ignore_case`` for retrieving PIDs of processes matching a supplied pattern (https://github.com/ansible-collections/community.general/pull/2280).

View file

@ -2,6 +2,7 @@
# Copyright: (c) 2019, Saranya Sridharan # Copyright: (c) 2019, Saranya Sridharan
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -14,12 +15,20 @@ requirements:
- psutil(python module) - psutil(python module)
options: options:
name: name:
description: the name of the process you want to get PID for. description: The name of the process(es) you want to get PID(s) for.
required: true
type: str type: str
pattern:
description: The pattern (regular expression) to match the process(es) you want to get PID(s) for.
type: str
version_added: 3.0.0
ignore_case:
description: Ignore case in pattern if using the I(pattern) option.
type: bool
default: false
version_added: 3.0.0
''' '''
EXAMPLES = ''' EXAMPLES = r'''
# Pass the process name # Pass the process name
- name: Getting process IDs of the process - name: Getting process IDs of the process
community.general.pids: community.general.pids:
@ -29,6 +38,11 @@ EXAMPLES = '''
- name: Printing the process IDs obtained - name: Printing the process IDs obtained
ansible.builtin.debug: ansible.builtin.debug:
msg: "PIDS of python:{{pids_of_python.pids|join(',')}}" msg: "PIDS of python:{{pids_of_python.pids|join(',')}}"
- name: Getting process IDs of processes matching pattern
community.general.pids:
pattern: python(2(\.7)?|3(\.6)?)?\s+myapp\.py
register: myapp_pids
''' '''
RETURN = ''' RETURN = '''
@ -39,9 +53,15 @@ pids:
sample: [100,200] sample: [100,200]
''' '''
from ansible.module_utils.basic import AnsibleModule import re
from os.path import basename
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import to_native
try: try:
import psutil import psutil
HAS_PSUTIL = True HAS_PSUTIL = True
except ImportError: except ImportError:
HAS_PSUTIL = False HAS_PSUTIL = False
@ -66,17 +86,51 @@ def get_pid(name):
return pids return pids
def get_matching_command_pids(pattern, ignore_case):
flags = 0
if ignore_case:
flags |= re.I
regex = re.compile(pattern, flags)
# See https://psutil.readthedocs.io/en/latest/#find-process-by-name for more information
return [p.pid for p in psutil.process_iter(["name", "exe", "cmdline"])
if regex.search(to_native(p.info["name"]))
or (p.info["exe"] and regex.search(basename(to_native(p.info["exe"]))))
or (p.info["cmdline"] and regex.search(to_native(' '.join(p.cmdline()))))
]
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec=dict( argument_spec=dict(
name=dict(required=True, type="str"), name=dict(type="str"),
pattern=dict(type="str"),
ignore_case=dict(type="bool", default=False),
), ),
required_one_of=[
('name', 'pattern')
],
mutually_exclusive=[
('name', 'pattern')
],
supports_check_mode=True, supports_check_mode=True,
) )
if not HAS_PSUTIL: if not HAS_PSUTIL:
module.fail_json(msg="Missing required 'psutil' python module. Try installing it with: pip install psutil") module.fail_json(msg=missing_required_lib('psutil'))
name = module.params["name"] name = module.params["name"]
response = dict(pids=get_pid(name)) pattern = module.params["pattern"]
ignore_case = module.params["ignore_case"]
if name:
response = dict(pids=get_pid(name))
else:
try:
response = dict(pids=get_matching_command_pids(pattern, ignore_case))
except re.error as e:
module.fail_json(msg="'%s' is not a valid regular expression: %s" % (pattern, to_native(e)))
module.exit_json(**response) module.exit_json(**response)

View file

@ -56,6 +56,22 @@
name: "{{ random_name[0:5] }}" name: "{{ random_name[0:5] }}"
register: exactpidmatch register: exactpidmatch
- name: "Checking that patterns can be used with the pattern option"
pids:
pattern: "{{ random_name[0:5] }}"
register: pattern_pid_match
- name: "Checking that case-insensitive patterns can be used with the pattern option"
pids:
pattern: "{{ random_name[0:5] | upper }}"
ignore_case: true
register: caseinsensitive_pattern_pid_match
- name: "Checking that .* includes test pid"
pids:
pattern: .*
register: match_all
- name: "Reading pid from the file" - name: "Reading pid from the file"
slurp: slurp:
src: "{{ output_dir }}/obtainpid.txt" src: "{{ output_dir }}/obtainpid.txt"
@ -67,3 +83,17 @@
- "pids.pids | join(' ') == newpid.content | b64decode | trim" - "pids.pids | join(' ') == newpid.content | b64decode | trim"
- "pids.pids | length > 0" - "pids.pids | length > 0"
- "exactpidmatch.pids == []" - "exactpidmatch.pids == []"
- "pattern_pid_match.pids | join(' ') == newpid.content | b64decode | trim"
- "caseinsensitive_pattern_pid_match.pids | join(' ') == newpid.content | b64decode | trim"
- newpid.content | b64decode | trim | int in match_all.pids
- name: "Register output of bad input pattern"
pids:
pattern: (unterminated
register: bad_pattern_result
ignore_errors: true
- name: "Verify that bad input pattern result is failed"
assert:
that:
- bad_pattern_result is failed