Skip to content

Commit

Permalink
Merge pull request ansible-collections#134 from CICS/rework-exception…
Browse files Browse the repository at this point in the history
…-handling

Rework CCUTL and LISTDS error handling and exceptions
  • Loading branch information
andrewhughes101 authored and GitHub Enterprise committed Dec 21, 2023
2 parents 2f64fed + 4e210ac commit 08156fd
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 45 deletions.
12 changes: 8 additions & 4 deletions plugins/module_utils/data_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,16 @@ def get_target_method(self, target): # type: (str) -> [str | invalid_target_sta
}.get(target, self.invalid_target_state)

def get_data_set_state(self, data_set): # type: (dict) -> dict
listds_executions, ds_status = dataset_utils._run_listds(data_set["name"])
try:
listds_executions, ds_status = dataset_utils._run_listds(data_set["name"])

data_set["exists"] = ds_status["exists"]
data_set["vsam"] = ds_status["vsam"]
data_set["exists"] = ds_status["exists"]
data_set["vsam"] = ds_status["vsam"]

self.result["executions"] = self.result["executions"] + listds_executions
self.result["executions"] = self.result["executions"] + listds_executions
except Exception as e:
self.result["executions"] = self.result["executions"] + e.args[1]
self._fail(e.args[0])

return data_set

Expand Down
21 changes: 10 additions & 11 deletions plugins/module_utils/dataset_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,20 @@

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from typing import Dict, List

from ansible_collections.ibm.ibm_zos_core.plugins.module_utils.mvs_cmd import idcams, ikjeft01
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils.response import _execution, _state


def _dataset_size(unit, primary, secondary): # type: (str,int,int) -> Dict
def _dataset_size(unit, primary, secondary): # type: (str,int,int) -> dict
return {
"unit": unit,
"primary": primary,
"secondary": secondary
}


def _run_idcams(cmd, name, location, delete=False): # type: (str, str, str, bool) -> List
def _run_idcams(cmd, name, location, delete=False): # type: (str, str, str, bool) -> list
executions = []

for x in range(10):
Expand Down Expand Up @@ -73,7 +72,7 @@ def _get_dataset_size_unit(unit_symbol): # type: (str) -> str
}.get(unit_symbol, "MEGABYTES")


def _build_idcams_define_cmd(dataset): # type: (Dict) -> str
def _build_idcams_define_cmd(dataset): # type: (dict) -> str
index_statement = (""" -
INDEX({0})""".format(_build_idcams_define_index_parms(dataset))
if dataset.get("INDEX", None)
Expand All @@ -88,7 +87,7 @@ def _build_idcams_define_cmd(dataset): # type: (Dict) -> str
index_statement)


def _build_idcams_define_cluster_parms(dataset): # type: (Dict) -> str
def _build_idcams_define_cluster_parms(dataset): # type: (dict) -> str

clusterStr = "NAME({0}) -\n {1}({2} {3})".format(
dataset["name"],
Expand All @@ -111,7 +110,7 @@ def _build_idcams_define_cluster_parms(dataset): # type: (Dict) -> str
return clusterStr


def _build_idcams_define_data_parms(dataset): # type: (Dict) -> str
def _build_idcams_define_data_parms(dataset): # type: (dict) -> str
dataStr = "NAME({0}.DATA)".format(dataset["name"])
if isinstance(dataset["DATA"], dict):
dataStr += " -\n "
Expand All @@ -128,7 +127,7 @@ def _build_idcams_define_data_parms(dataset): # type: (Dict) -> str
return dataStr


def _build_idcams_define_index_parms(dataset): # type: (Dict) -> str
def _build_idcams_define_index_parms(dataset): # type: (dict) -> str
indexStr = "NAME({0}.INDEX)".format(dataset["name"])
if isinstance(dataset["INDEX"], dict):
indexStr += " -\n "
Expand All @@ -145,7 +144,7 @@ def _build_idcams_define_index_parms(dataset): # type: (Dict) -> str
return indexStr


def _run_listds(location): # type: (str) -> [List, _state]
def _run_listds(location): # type: (str) -> [list, _state]
cmd = " LISTDS '{0}'".format(location)
executions = []

Expand All @@ -162,7 +161,7 @@ def _run_listds(location): # type: (str) -> [List, _state]
break

if location.upper() not in stdout.upper():
raise Exception("LISTDS Command output not recognised")
raise Exception("LISTDS Command output not recognised", executions)

# DS Name in output, good output

Expand All @@ -172,7 +171,7 @@ def _run_listds(location): # type: (str) -> [List, _state]
# Exists

if rc != 0:
raise Exception("RC {0} running LISTDS Command".format(rc))
raise Exception("RC {0} running LISTDS Command".format(rc), executions)

# Exists, RC 0

Expand All @@ -186,7 +185,7 @@ def _run_listds(location): # type: (str) -> [List, _state]
return executions, _state(exists=True, vsam=True)


def _data_set(size, name, state, exists, vsam, **kwargs): # type: (_dataset_size, str, str, bool, bool, Dict) -> Dict
def _data_set(size, name, state, exists, vsam, **kwargs): # type: (_dataset_size, str, str, bool, bool, dict) -> dict
data_set = {
"size": size,
"name": name,
Expand Down
17 changes: 9 additions & 8 deletions plugins/module_utils/local_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from ansible_collections.ibm.ibm_zos_core.plugins.module_utils.dd_statement import StdoutDefinition, DatasetDefinition, DDStatement
from ansible_collections.ibm.ibm_zos_core.plugins.module_utils.zos_mvs_raw import MVSCmd
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils.dataset_utils import _data_set
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils.response import _execution
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils.data_set import _dataset_constants as ds_constants

Expand All @@ -26,22 +27,22 @@ def _get_ccmutl_dds(catalog):
]


def _run_dfhccutl(starting_catalog):
def _run_dfhccutl(starting_catalog): # type: (_data_set) -> [_execution]
executions = []
dfhccutl_response = _execute_dfhccutl(starting_catalog)

if dfhccutl_response.rc != 0:
raise Exception(
"DFHCCUTL failed with RC {0}".format(
dfhccutl_response.rc
)
)
executions.append(_execution(
name="DFHCCUTL - Initialise Local Catalog",
rc=dfhccutl_response.rc,
stdout=dfhccutl_response.stdout,
stderr=dfhccutl_response.stderr))

if dfhccutl_response.rc != 0:
raise Exception(
"DFHCCUTL failed with RC {0}".format(
dfhccutl_response.rc
), executions
)
return executions


Expand All @@ -53,7 +54,7 @@ def _execute_dfhccutl(starting_catalog):
debug=False)


def _get_idcams_cmd_lcd(dataset):
def _get_idcams_cmd_lcd(dataset): # type: (dict) -> dict
defaults = {
"CLUSTER": {
"RECORDSIZE": "{0} {1}".format(_local_catalog_constants["RECORD_COUNT_DEFAULT"], _local_catalog_constants["RECORD_SIZE_DEFAULT"]),
Expand Down
24 changes: 12 additions & 12 deletions plugins/modules/global_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@
_run_dfhrmutl, _get_idcams_cmd_gcd)
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils.data_set import DataSet
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils.dataset_utils import (
_dataset_size, _run_listds, _data_set, _build_idcams_define_cmd)
_dataset_size, _data_set, _build_idcams_define_cmd)
from ansible_collections.ibm.ibm_zos_core.plugins.module_utils.better_arg_parser import BetterArgParser
from typing import Dict

Expand Down Expand Up @@ -484,24 +484,24 @@ def get_target_method(self, target):
}.get(target, self.invalid_target_state)

def get_data_set_state(self, data_set):
listds_executions, ds_status = _run_listds(data_set["name"])

data_set["exists"] = ds_status['exists']
data_set["vsam"] = ds_status['vsam']

self.result["executions"] = self.result["executions"] + listds_executions
super().get_data_set_state(data_set)

if data_set["exists"] and data_set["vsam"]:
dfhrmutl_executions, catalog_status = _run_dfhrmutl(
data_set["name"], data_set[ds_constants["SDFHLOAD_ALIAS"]])
try:
dfhrmutl_executions, catalog_status = _run_dfhrmutl(
data_set["name"], data_set[ds_constants["SDFHLOAD_ALIAS"]])

data_set["autostart_override"] = catalog_status['autostart_override']
data_set["nextstart"] = catalog_status['next_start']
data_set["autostart_override"] = catalog_status['autostart_override']
data_set["nextstart"] = catalog_status['next_start']

self.result["executions"] = self.result["executions"] + dfhrmutl_executions
self.result["executions"] = self.result["executions"] + dfhrmutl_executions
except Exception as e:
self.result["executions"] = self.result["executions"] + e.args[1]
self._fail(e.args[0])
else:
data_set["autostart_override"] = ""
data_set["nextstart"] = ""

return data_set

def main(self):
Expand Down
8 changes: 6 additions & 2 deletions plugins/modules/local_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,12 @@ def init_data_set(self):
if not self.data_set["exists"]:
self.create_data_set()

ccutl_executions = _run_dfhccutl(self.data_set)
self.result["executions"] = self.result["executions"] + ccutl_executions
try:
ccutl_executions = _run_dfhccutl(self.data_set)
self.result["executions"] = self.result["executions"] + ccutl_executions
except Exception as e:
self.result["executions"] = self.result["executions"] + e.args[1]
self._fail(e.args[0])


def main():
Expand Down
41 changes: 35 additions & 6 deletions tests/unit/module_utils/test_dataset_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils import dataset_utils
import pytest
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils.response import _execution
try:
from unittest.mock import MagicMock
except ImportError:
Expand Down Expand Up @@ -347,16 +347,19 @@ def test__run_listds_exists_not_vsam():

def test__run_listds_bad_rc():

name = "IKJEFT01 - Get Data Set Status - Run 1"
rc = 16
stdout = ""
stdout = "ANSIBIT.CICS.TESTS.A365D7A.DFHGCD"
stderr = ""
dataset_utils.ikjeft01 = MagicMock(return_value=[rc, stdout, stderr])

with pytest.raises(Exception) as e_info:
result_exececutions, result_status = dataset_utils._run_listds(
"ANSIBIT.CICS.TESTS.A365D7A.DFHGCD")
expected_executions = [_execution(name=name, rc=rc, stdout=stdout, stderr=stderr)]

assert e_info == "LISTDS Command output not recognised"
try:
dataset_utils._run_listds("ANSIBIT.CICS.TESTS.A365D7A.DFHGCD")
except Exception as e:
assert e.args[0] == "RC 16 running LISTDS Command"
assert e.args[1] == expected_executions


def test__run_listds_not_exists():
Expand Down Expand Up @@ -391,3 +394,29 @@ def test__run_listds_not_exists():
"exists": False,
"vsam": False,
}


def test__run_listds_with_no_zoau_response():
rc = 0
stdout = ""
stderr = ""
dataset_utils.ikjeft01 = MagicMock(return_value=[rc, stdout, stderr])

expected_executions = [
_execution(name="IKJEFT01 - Get Data Set Status - Run 1", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 2", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 3", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 4", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 5", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 6", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 7", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 8", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 9", rc=rc, stdout=stdout, stderr=stderr),
_execution(name="IKJEFT01 - Get Data Set Status - Run 10", rc=rc, stdout=stdout, stderr=stderr)
]

try:
dataset_utils._run_listds("LOCATION THATS NOT IN STDOUT")
except Exception as e:
assert e.args[0] == "LISTDS Command output not recognised"
assert e.args[1] == expected_executions
67 changes: 65 additions & 2 deletions tests/unit/module_utils/test_local_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@
# Apache License, Version 2.0 (see https://opensource.org/licenses/Apache-2.0)

from __future__ import absolute_import, division, print_function
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils.response import _execution

from ansible_collections.ibm.ibm_zos_core.plugins.module_utils.zos_mvs_raw import MVSCmdResponse
__metaclass__ = type
from ansible_collections.ibm.ibm_zos_cics.plugins.modules import local_catalog
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils import local_catalog as local_catalog_utils
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils import dataset_utils
import pytest
import sys

try:
from unittest.mock import MagicMock
except ImportError:
from mock import MagicMock


@pytest.mark.skipif(sys.version_info.major < 3, reason="Requires python 3 language features")
def test_get_idcams_cmd_megabytes():
Expand All @@ -22,7 +31,7 @@ def test_get_idcams_cmd_megabytes():
state="initial",
exists=False,
vsam=False)
idcams_cmd_lcd = dataset_utils._build_idcams_define_cmd(local_catalog._get_idcams_cmd_lcd(catalog))
idcams_cmd_lcd = dataset_utils._build_idcams_define_cmd(local_catalog_utils._get_idcams_cmd_lcd(catalog))
assert idcams_cmd_lcd == '''
DEFINE CLUSTER (NAME(ANSI.CYLS.DFHLCD) -
MEGABYTES(3 1) -
Expand All @@ -49,7 +58,7 @@ def test_get_idcams_cmd_cylinders():
state="initial",
exists=False,
vsam=False)
idcams_cmd_lcd = dataset_utils._build_idcams_define_cmd(local_catalog._get_idcams_cmd_lcd(catalog))
idcams_cmd_lcd = dataset_utils._build_idcams_define_cmd(local_catalog_utils._get_idcams_cmd_lcd(catalog))
assert idcams_cmd_lcd == '''
DEFINE CLUSTER (NAME(ANSI.CYLS.DFHLCD) -
CYLINDERS(3 1) -
Expand Down Expand Up @@ -86,3 +95,57 @@ def test_local_catalog_class():
"exists": False,
"vsam": False,
}


def test_ccutl_response():
local_catalog = {
"exists": False,
"name": "ANSI.TEST.DFHLCD",
"size": {
"primary": 5,
"secondary": 1,
"unit": "M"
},
"state": "initial",
"vsam": False,
"sdfhload": "CICSTS.IN56.SDFHLOAD",
}

expected_executions = [
_execution(name="DFHCCUTL - Initialise Local Catalog", rc=0, stdout="stdout", stderr="stderr"),
]

local_catalog_utils._execute_dfhccutl = MagicMock(return_value=MVSCmdResponse(rc=0, stdout="stdout", stderr="stderr"))
executions = local_catalog_utils._run_dfhccutl(local_catalog)

assert executions == expected_executions


def test_bad_ccutl_response():
local_catalog = {
"exists": False,
"name": "ANSI.TEST.DFHLCD",
"size": {
"primary": 5,
"secondary": 1,
"unit": "M"
},
"state": "initial",
"vsam": False,
"sdfhload": "CICSTS.IN56.SDFHLOAD",
}

expected_executions = [
_execution(name="DFHCCUTL - Initialise Local Catalog", rc=99, stdout="stdout", stderr="stderr"),
]

local_catalog_utils._execute_dfhccutl = MagicMock(return_value=MVSCmdResponse(rc=99, stdout="stdout", stderr="stderr"))

try:
local_catalog_utils._run_dfhccutl(local_catalog)
except Exception as e:
error_message = e.args[0]
executions = e.args[1]

assert error_message == "DFHCCUTL failed with RC 99"
assert executions == expected_executions
Loading

0 comments on commit 08156fd

Please sign in to comment.