Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nazare 8838 force option #316

Merged
merged 7 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelogs/fragments/316-update-zos-blockinfile-force.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
minor_changes:
- >
zos_blockinfile - updates the module with a new option named force.
This allows for a user to specifiy that the data set can be shared with
others during an update which results in the data set you are updating to
be simultaneously updated by others.
(https://github.com/ansible-collections/ibm_zos_core/pull/316).
37 changes: 29 additions & 8 deletions plugins/modules/zos_blockinfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,18 @@
required: false
type: str
default: IBM-1047
force:
description:
- Specifies that the data set can be shared with others during an update
which results in the data set you are updating to be simultaneously
updated by others.
- This is helpful when a data set is being used in a long running process
such as a started task and you are wanting to update or read.
- The C(-f) option enables sharing of data sets through the disposition
I(DISP=SHR).
required: false
type: bool
default: false
indentation:
description:
- Defines the number of spaces needed to prepend in every line of the block.
Expand Down Expand Up @@ -242,7 +254,7 @@
description: Constructed ZOAU dmod shell command based on the parameters
returned: success
type: str
sample: dmodhelper -d -b -c IBM-1047 -m "BEGIN\nEND\n# {mark} ANSIBLE MANAGED BLOCK" -e "$ a\\PATH=/dir/bin:$PATH" /etc/profile
sample: dmod -d -b -c IBM-1047 -m "BEGIN\nEND\n# {mark} ANSIBLE MANAGED BLOCK" -e "$ a\\PATH=/dir/bin:$PATH" /etc/profile
msg:
description: The module messages
returned: failure
Expand Down Expand Up @@ -319,7 +331,7 @@ def transformBlock(block, indentation_char, indentation_spaces):
return block


def present(src, block, marker, ins_aft, ins_bef, encoding):
def present(src, block, marker, ins_aft, ins_bef, encoding, force):
"""Replace a block with the matching regex pattern
Insert a block before/after the matching pattern
Insert a block at BOF/EOF
Expand All @@ -337,31 +349,33 @@ def present(src, block, marker, ins_aft, ins_bef, encoding):
- BOF
- '*regex*'
encoding: {str} -- Encoding of the src.
force: {str} -- If not empty passes the -f option to dmod cmd.

Returns:
str -- Information in JSON format. keys:
cmd: {str} -- dmod shell command
found: {int} -- Number of matching regex pattern
changed: {bool} -- Indicates if the destination was modified.
"""
return datasets.blockinfile(src, block=block, marker=marker, ins_aft=ins_aft, ins_bef=ins_bef, encoding=encoding, state=True, debug=True)
return datasets.blockinfile(src, block=block, marker=marker, ins_aft=ins_aft, ins_bef=ins_bef, encoding=encoding, state=True, debug=True, options=force)


def absent(src, marker, encoding):
def absent(src, marker, encoding, force):
"""Delete blocks with matching regex pattern

Arguments:
src: {str} -- The z/OS USS file or data set to modify.
marker: {str} -- Identifies the block to be removed.
encoding: {str} -- Encoding of the src.
force: {str} -- If not empty passes the -f option to dmod cmd.

Returns:
str -- Information in JSON format. keys:
cmd: {str} -- dmod shell command
found: {int} -- Number of matching regex pattern
changed: {bool} -- Indicates if the destination was modified.
"""
return datasets.blockinfile(src, marker=marker, encoding=encoding, state=False, debug=True)
return datasets.blockinfile(src, marker=marker, encoding=encoding, state=False, debug=True, options=force)


def quotedString(string):
Expand Down Expand Up @@ -420,6 +434,10 @@ def main():
type='str',
default='IBM-1047'
),
force=dict(
type='bool',
default=False
),
indentation=dict(
type='int',
required=False,
Expand All @@ -439,6 +457,7 @@ def main():
marker_begin=dict(arg_type='str', default='BEGIN', required=False),
marker_end=dict(arg_type='str', default='END', required=False),
encoding=dict(arg_type='str', default='IBM-1047', required=False),
force=dict(arg_type='bool', default=False, required=False),
backup=dict(arg_type='bool', default=False, required=False),
backup_name=dict(arg_type='data_set_or_pat', required=False, default=None),
mutually_exclusive=[['insertbefore', 'insertafter']],
Expand All @@ -462,6 +481,7 @@ def main():
marker = parsed_args.get('marker')
marker_begin = parsed_args.get('marker_begin')
marker_end = parsed_args.get('marker_end')
force = parsed_args.get('force')
state = parsed_args.get('state')
indentation = parsed_args.get('indentation')

Expand All @@ -480,6 +500,7 @@ def main():
marker_begin = 'BEGIN'
if not marker_end:
marker_end = 'END'
force = '-f' if force else ''

marker = "{0}\\n{1}\\n{2}".format(marker_begin, marker_end, marker)
block = transformBlock(block, ' ', indentation)
Expand Down Expand Up @@ -512,10 +533,10 @@ def main():
module.fail_json(msg="creating backup has failed")
# state=present, insert/replace a block with matching regex pattern
# state=absent, delete blocks with matching regex pattern
if state == 'present':
return_content = present(src, quotedString(block), quotedString(marker), quotedString(ins_aft), quotedString(ins_bef), encoding)
if parsed_args.get('state') == 'present':
return_content = present(src, quotedString(block), quotedString(marker), quotedString(ins_aft), quotedString(ins_bef), encoding, force)
else:
return_content = absent(src, quotedString(marker), encoding)
return_content = absent(src, quotedString(marker), encoding, force)
stdout = return_content.stdout_response
stderr = return_content.stderr_response
rc = return_content.rc
Expand Down
103 changes: 103 additions & 0 deletions tests/functional/modules/test_zos_blockinfile_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,16 @@
insertbefore="ZOAU_ROOT=", block="unset ZOAU_ROOT\nunset ZOAU_HOME\nunset ZOAU_DIR", state="present"),
test_uss_block_insertafter_eof=dict(
insertafter="EOF", block="export ZOAU_ROOT\nexport ZOAU_HOME\nexport ZOAU_DIR", state="present"),
test_uss_block_insert_with_force_option_as_true=dict(
insertafter="EOF", block="export ZOAU_ROOT\nexport ZOAU_HOME\nexport ZOAU_DIR", state="present", force=True),
test_uss_block_insert_with_force_option_as_false=dict(
insertafter="EOF", block="export ZOAU_ROOT\nexport ZOAU_HOME\nexport ZOAU_DIR", state="present", force=False),
test_uss_block_insertbefore_bof=dict(
insertbefore="BOF", block="# this is file is for setting env vars",
state="present"),
test_uss_block_absent=dict(block="", state="absent"),
test_uss_block_absent_with_force_option_as_true=dict(block="", state="absent", force=True),
test_uss_block_absent_with_force_option_as_false=dict(block="", state="absent", force=True),
test_uss_block_replace_insertafter_regex=dict(
insertafter="PYTHON_HOME=", block="ZOAU_ROOT=/mvsutil-develop_dsed\nZOAU_HOME=\\$ZOAU_ROOT\nZOAU_DIR=\\$ZOAU_ROOT",
state="present"),
Expand All @@ -182,6 +188,10 @@
test_ds_block_insertafter_eof=dict(test_name="T3"),
test_ds_block_insertbefore_bof=dict(test_name="T4"),
test_ds_block_absent=dict(test_name="T5"),
test_ds_block_insert_with_force_option_as_true=dict(block="export ZOAU_ROOT\nexport ZOAU_HOME\nexport ZOAU_DIR", state="present", force=True),
test_ds_block_absent_with_force_option_as_true=dict(block="", state="absent", force=True),
test_ds_block_insert_with_force_option_as_false=dict(block="export ZOAU_ROOT\nexport ZOAU_HOME\nexport ZOAU_DIR", state="present", force=False),
test_ds_block_absent_with_force_option_as_false=dict(block="", state="absent", force=False),
test_ds_block_insert_with_indentation_level_specified=dict(test_name="T7"),
expected=dict(test_uss_block_insertafter_regex_defaultmarker="""if [ -z STEPLIB ] && tty -s;
then
Expand Down Expand Up @@ -1088,6 +1098,42 @@ def test_uss_block_replace_insertbefore_bof_custommarker(ansible_zos_module):
TEST_ENV["TEST_CONT"] = TEST_CONTENT


@pytest.mark.uss
def test_uss_block_insert_with_force_option_as_true(ansible_zos_module):
UssGeneral(
"test_uss_block_insertafter_eof_defaultmarker", ansible_zos_module,
TEST_ENV, TEST_INFO["test_uss_block_insert_with_force_option_as_true"],
TEST_INFO["expected"]["test_uss_block_insertafter_eof_defaultmarker"])


@pytest.mark.uss
def test_uss_block_insert_with_force_option_as_false(ansible_zos_module):
UssGeneral(
"test_uss_block_insertafter_eof_defaultmarker", ansible_zos_module,
TEST_ENV, TEST_INFO["test_uss_block_insert_with_force_option_as_false"],
TEST_INFO["expected"]["test_uss_block_insertafter_eof_defaultmarker"])


@pytest.mark.uss
def test_uss_block_absent_with_force_option_as_true(ansible_zos_module):
TEST_ENV["TEST_CONT"] = TEST_CONTENT_DEFAULTMARKER
UssGeneral(
"test_uss_block_absent_defaultmarker", ansible_zos_module, TEST_ENV,
TEST_INFO["test_uss_block_absent_with_force_option_as_true"],
TEST_INFO["expected"]["test_uss_block_absent"])
TEST_ENV["TEST_CONT"] = TEST_CONTENT


@pytest.mark.uss
def test_uss_block_absent_with_force_option_as_false(ansible_zos_module):
TEST_ENV["TEST_CONT"] = TEST_CONTENT_DEFAULTMARKER
UssGeneral(
"test_uss_block_absent_defaultmarker", ansible_zos_module, TEST_ENV,
TEST_INFO["test_uss_block_absent_with_force_option_as_false"],
TEST_INFO["expected"]["test_uss_block_absent"])
TEST_ENV["TEST_CONT"] = TEST_CONTENT


@pytest.mark.uss
def test_uss_block_insert_with_indentation_level_specified(ansible_zos_module):
UssGeneral(
Expand Down Expand Up @@ -1236,6 +1282,63 @@ def test_ds_block_absent(ansible_zos_module, dstype, encoding):
TEST_ENV["TEST_CONT"] = TEST_CONTENT


@pytest.mark.ds
@pytest.mark.parametrize("dstype", DS_TYPE)
@pytest.mark.parametrize("encoding", ENCODING)
def test_ds_block_insert_with_force_option_as_true(ansible_zos_module, dstype, encoding):
TEST_ENV["DS_TYPE"] = dstype
TEST_ENV["ENCODING"] = encoding
DsGeneral(
"T6",
ansible_zos_module, TEST_ENV,
TEST_INFO["test_ds_block_insert_with_force_option_as_true"],
TEST_INFO["expected"]["test_uss_block_insertafter_eof_defaultmarker"]
)


@pytest.mark.ds
@pytest.mark.parametrize("dstype", DS_TYPE)
@pytest.mark.parametrize("encoding", ENCODING)
def test_ds_block_absent_with_force_option_as_true(ansible_zos_module, dstype, encoding):
TEST_ENV["DS_TYPE"] = dstype
TEST_ENV["ENCODING"] = encoding
TEST_ENV["TEST_CONT"] = TEST_CONTENT_DEFAULTMARKER
DsGeneral(
"T7", ansible_zos_module,
TEST_ENV, TEST_INFO["test_ds_block_absent_with_force_option_as_true"],
TEST_INFO["expected"]["test_uss_block_absent"]
)
TEST_ENV["TEST_CONT"] = TEST_CONTENT


@pytest.mark.ds
@pytest.mark.parametrize("dstype", DS_TYPE)
@pytest.mark.parametrize("encoding", ENCODING)
def test_ds_block_insert_with_force_option_as_false(ansible_zos_module, dstype, encoding):
TEST_ENV["DS_TYPE"] = dstype
TEST_ENV["ENCODING"] = encoding
DsGeneral(
"T8", ansible_zos_module,
TEST_ENV, TEST_INFO["test_ds_block_insert_with_force_option_as_false"],
TEST_INFO["expected"]["test_uss_block_insertafter_eof_defaultmarker"]
)


@pytest.mark.ds
@pytest.mark.parametrize("dstype", DS_TYPE)
@pytest.mark.parametrize("encoding", ENCODING)
def test_ds_block_absent_with_force_option_as_false(ansible_zos_module, dstype, encoding):
TEST_ENV["DS_TYPE"] = dstype
TEST_ENV["ENCODING"] = encoding
TEST_ENV["TEST_CONT"] = TEST_CONTENT_DEFAULTMARKER
DsGeneral(
"T9", ansible_zos_module,
TEST_ENV, TEST_INFO["test_ds_block_absent_with_force_option_as_false"],
TEST_INFO["expected"]["test_uss_block_absent"]
)
TEST_ENV["TEST_CONT"] = TEST_CONTENT


@pytest.mark.ds
@pytest.mark.parametrize("dstype", DS_TYPE)
@pytest.mark.parametrize("encoding", ENCODING)
Expand Down