Skip to content

Commit

Permalink
Name Changes
Browse files Browse the repository at this point in the history
-Name and formatting changes
-Add userid to result dictionary no matter what

Signed-off-by: Elijah Swift <elijah.swift@ibm.com>
  • Loading branch information
ElijahSwiftIBM committed Dec 4, 2023
1 parent 8a227de commit 000b71f
Show file tree
Hide file tree
Showing 35 changed files with 243 additions and 255 deletions.
4 changes: 2 additions & 2 deletions pyracf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
from .access.access_admin import AccessAdmin
from .common.add_operation_error import AddOperationError
from .common.alter_operation_error import AlterOperationError
from .common.downstream_fatal_error import DownstreamFatalError
from .common.security_request_error import SecurityRequestError
from .common.security_response_error import SecurityResponseError
from .common.segment_error import SegmentError
from .common.segment_trait_error import SegmentTraitError
from .common.userid_error import UserIdError
from .connection.connection_admin import ConnectionAdmin
from .data_set.data_set_admin import DataSetAdmin
from .group.group_admin import GroupAdmin
from .resource.resource_admin import ResourceAdmin
from .scripts.install_precheck import define_precheck_profile
from .scripts.setup_precheck import setup_precheck
from .setropts.setropts_admin import SetroptsAdmin
from .user.user_admin import UserAdmin
66 changes: 66 additions & 0 deletions pyracf/common/downstream_fatal_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Exception to use when no data is returned by IRRSMO00."""
from typing import Union


class DownstreamFatalError(Exception):
"""
Raised when no xml string is returned by IRRSMO00.
"""

def __init__(
self,
xml_str: str,
request_xml: bytes,
run_as_userid: Union[str, None] = None,
result_dict: dict = None,
) -> None:
self.message = "Security request made to IRRSMO00 failed."
self.saf_return_code = xml_str[0]
self.racf_return_code = xml_str[1]
self.racf_reason_code = xml_str[2]
self.request_xml = request_xml.decode("utf-8")
self.message += (
f"\n\nSAF Return Code: {self.saf_return_code}\nRACF Return Code:"
+ f" {self.racf_return_code}\nRACF Reason Code: {self.racf_reason_code}"
)
if result_dict is not None:
self.message += (
"\n\nSee results dictionary "
+ f"'{self.__class__.__name__}.result' for more details.\n"
+ "\n\nYou can also check the specified return and reason codes against"
+ " the IRRSMO00 documented return and reason codes for more information"
+ " about this error.\n"
+ "https://www.ibm.com/docs/en/zos/3.1.0?topic=operations-return-reason-codes"
)
self.result = result_dict
elif (
(self.saf_return_code == 8)
and (self.racf_return_code == 200)
and (self.racf_reason_code == 16)
):
self.message += (
"\n\nCheck to see if the proper RACF permissions are in place.\n"
+ "For `set` or `alter` functions, you must have at least READ "
+ "access to `IRR.IRRSMO00.PRECHECK` in the `XFACILIT` class."
)
elif (
(self.saf_return_code == 8)
and (self.racf_return_code == 200)
and (self.racf_reason_code == 8)
):
self.message += (
"\n\nCheck to see if the proper RACF permissions are in place.\n"
+ "For the `run_as_userid` feature, you must have at least UPDATE"
+ f" access to `{run_as_userid}.IRRSMO00` in the `SURROGAT` class."
)
else:
self.message += (
"\n\nPlease check the specified return and reason codes against"
+ " the IRRSMO00 documented return and reason codes for more information"
+ " about this error.\n"
+ "https://www.ibm.com/docs/en/zos/3.1.0?topic=operations-return-reason-codes"
)
self.message = f"({self.__class__.__name__}) {self.message}"

def __str__(self) -> str:
return self.message
27 changes: 11 additions & 16 deletions pyracf/common/security_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
from datetime import datetime
from typing import Any, List, Tuple, Union

from .downstream_fatal_error import DownstreamFatalError
from .irrsmo00 import IRRSMO00
from .logger import Logger
from .security_request import SecurityRequest
from .security_request_error import SecurityRequestError
from .security_response_error import SecurityResponseError
from .security_result import SecurityResult
from .segment_error import SegmentError
from .segment_trait_error import SegmentTraitError
Expand Down Expand Up @@ -92,14 +92,9 @@ def set_running_userid(self, new_userid: Union[str, None]) -> None:
if new_userid is None:
self.__running_userid = new_userid
return
if (
isinstance(new_userid, str)
and (len(new_userid) <= 8)
and (not new_userid == "")
):
self.__running_userid = new_userid.upper()
return
raise UserIdError(new_userid)
if not isinstance(new_userid, str) or len(new_userid) > 8 or new_userid == "":
raise UserIdError(new_userid)
self.__running_userid = new_userid.upper()

def clear_running_userid(self) -> None:
self.__running_userid = None
Expand Down Expand Up @@ -203,8 +198,8 @@ def _make_request(
if isinstance(result_xml, list):
# When IRRSMO00 encounters some errors, it returns no XML response string.
# When this happens, the c code instead surfaces the return and reason
# codes which causes a SecurityRequestError to be raised.
raise SecurityRequestError(
# codes which causes a DownstreamFatalError to be raised.
raise DownstreamFatalError(
result_xml, request_xml, self.get_running_userid()
)
if self.__debug:
Expand All @@ -223,9 +218,9 @@ def _make_request(
# All return codes greater than 4 are indicative of an issue with
# IRRSMO00 that would stop a command image from being generated.
# The user should interogate the result dictionary attached to the
# SecurityResponseError as well as the return and reason codes to
# SecurityRequestError as well as the return and reason codes to
# resolve the problem.
raise SecurityRequestError(
raise DownstreamFatalError(
[
8,
result_dictionary["securityResult"]["returnCode"],
Expand All @@ -236,12 +231,12 @@ def _make_request(
result_dictionary,
)
if result_dictionary["securityResult"]["returnCode"] != 0:
# All non-zero return codes should cause a SecurityResponseError to be raised.
# All non-zero return codes should cause a SecurityRequestError to be raised.
# Even if a return code of 4 is not indicative of a problem, it it is
# up to the user to interogate the result dictionary attached to the
# SecurityResponseError and decided whether or not the return code 4 is
# SecurityRequestError and decided whether or not the return code 4 is
# indicative of a problem.
raise SecurityResponseError(result_dictionary)
raise SecurityRequestError(result_dictionary)
return result_dictionary

def _to_steps(self, results: Union[List[dict], dict, bytes]) -> Union[dict, bytes]:
Expand Down
74 changes: 21 additions & 53 deletions pyracf/common/security_request_error.py
Original file line number Diff line number Diff line change
@@ -1,66 +1,34 @@
"""Exception to use when no data is returned by IRRSMO00."""
from typing import Union
"""Exception to use when data returned by IRRSMO00 indicates that the request failed."""


class SecurityRequestError(Exception):
"""
Raised when no xml string is returned by IRRSMO00.
Raised when the return code of a security result returned by IRRSMO00 is NOT equal to 0.
"""

def __init__(
self,
xml_str: str,
request_xml: bytes,
run_as_userid: Union[str, None] = None,
result_dict: dict = None,
) -> None:
def __init__(self, result: dict) -> None:
self.message = "Security request made to IRRSMO00 failed."
self.saf_return_code = xml_str[0]
self.racf_return_code = xml_str[1]
self.racf_reason_code = xml_str[2]
self.request_xml = request_xml.decode("utf-8")
self.result = result
self.message += (
f"\n\nSAF Return Code: {self.saf_return_code}\nRACF Return Code:"
+ f" {self.racf_return_code}\nRACF Reason Code: {self.racf_reason_code}"
"\n\nSee results dictionary "
+ f"'{self.__class__.__name__}.result' for more details."
)
if result_dict is not None:
self.message += (
"\n\nSee results dictionary "
+ f"'{self.__class__.__name__}.result' for more details.\n"
+ "\n\nYou can also check the specified return and reason codes against"
+ " the IRRSMO00 documented return and reason codes for more information"
+ " about this error.\n"
+ "https://www.ibm.com/docs/en/zos/3.1.0?topic=operations-return-reason-codes"
)
self.result = result_dict
elif (
(self.saf_return_code == 8)
and (self.racf_return_code == 200)
and (self.racf_reason_code == 16)
):
self.message += (
"\n\nCheck to see if the proper RACF permissions are in place.\n"
+ "For `set` or `alter` functions, you must have at least READ "
+ "access to `IRR.IRRSMO00.PRECHECK` in the `XFACILIT` class."
)
elif (
(self.saf_return_code == 8)
and (self.racf_return_code == 200)
and (self.racf_reason_code == 8)
):
self.message += (
"\n\nCheck to see if the proper RACF permissions are in place.\n"
+ "For the `run_as_userid` feature, you must have at least UPDATE"
+ f" access to `{run_as_userid}.IRRSMO00` in the `SURROGAT` class."
)
else:
self.message += (
"\n\nPlease check the specified return and reason codes against"
+ " the IRRSMO00 documented return and reason codes for more information"
+ " about this error.\n"
+ "https://www.ibm.com/docs/en/zos/3.1.0?topic=operations-return-reason-codes"
)
self.message = f"({self.__class__.__name__}) {self.message}"

def __str__(self) -> str:
return self.message

def contains_error_message(
self, security_definition_tag: str, error_message_id: str
):
"""Checks to see if specific error message id appears in the security request error"""
commands = self.result["securityResult"][security_definition_tag].get(
"commands"
)
if not isinstance(commands, list):
return False
messages = commands[0].get("messages", [])
if error_message_id in "".join(messages):
return True
else:
return False
34 changes: 0 additions & 34 deletions pyracf/common/security_response_error.py

This file was deleted.

9 changes: 1 addition & 8 deletions pyracf/common/security_result.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Generic Security Result Parser."""

import getpass
import platform
import re
from typing import Union
from xml.etree.ElementTree import Element # Only used for type hints.
Expand All @@ -25,7 +24,7 @@ def __init__(
else:
self.__result_dictionary["securityResult"][
"runningUserid"
] = self.__get_current_userid()
] = getpass.getuser().lower()

def __extract_results(self) -> None:
"""Extract XML results into a dictionary."""
Expand Down Expand Up @@ -143,12 +142,6 @@ def __to_pascal_case(self, key: str) -> str:
case _:
return key

def __get_current_userid(self) -> str:
if platform.system() == "OS/390":
return getpass.getuser().lower()
else:
return "testuser"

def get_result_dictionary(self) -> dict:
"""Return result dictionary."""
return self.__result_dictionary
6 changes: 3 additions & 3 deletions pyracf/data_set/data_set_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pyracf.common.add_operation_error import AddOperationError
from pyracf.common.alter_operation_error import AlterOperationError
from pyracf.common.security_admin import SecurityAdmin
from pyracf.common.security_response_error import SecurityResponseError
from pyracf.common.security_request_error import SecurityRequestError

from .data_set_request import DataSetRequest

Expand Down Expand Up @@ -117,7 +117,7 @@ def add(
)
if self._get_field(profile, "base", "name") == data_set.lower():
raise AddOperationError(data_set, self._profile_type)
except SecurityResponseError as exception:
except SecurityRequestError as exception:
if not exception.contains_error_message(self._profile_type, "ICH35003I"):
raise exception
self._build_segment_trait_dictionary(traits)
Expand All @@ -142,7 +142,7 @@ def alter(
profile = self.extract(
data_set, volume=volume, generic=generic, profile_only=True
)
except SecurityResponseError:
except SecurityRequestError:
raise AlterOperationError(data_set, self._profile_type)
if not self._get_field(profile, "base", "name") == data_set.lower():
raise AlterOperationError(data_set, self._profile_type)
Expand Down
6 changes: 3 additions & 3 deletions pyracf/group/group_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pyracf.common.add_operation_error import AddOperationError
from pyracf.common.alter_operation_error import AlterOperationError
from pyracf.common.security_admin import SecurityAdmin
from pyracf.common.security_response_error import SecurityResponseError
from pyracf.common.security_request_error import SecurityRequestError

from .group_request import GroupRequest

Expand Down Expand Up @@ -131,7 +131,7 @@ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]:
return self._make_request(group_request)
try:
self.extract(group)
except SecurityResponseError as exception:
except SecurityRequestError as exception:
if not exception.contains_error_message(self._profile_type, "ICH51003I"):
raise exception
self._build_segment_trait_dictionary(traits)
Expand All @@ -149,7 +149,7 @@ def alter(self, group: str, traits: dict) -> Union[dict, bytes]:
return self._make_request(group_request, irrsmo00_precheck=True)
try:
self.extract(group)
except SecurityResponseError:
except SecurityRequestError:
raise AlterOperationError(group, self._profile_type)
self._build_segment_trait_dictionary(traits)
group_request = GroupRequest(group, "set")
Expand Down
6 changes: 3 additions & 3 deletions pyracf/resource/resource_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pyracf.common.add_operation_error import AddOperationError
from pyracf.common.alter_operation_error import AlterOperationError
from pyracf.common.security_admin import SecurityAdmin
from pyracf.common.security_response_error import SecurityResponseError
from pyracf.common.security_request_error import SecurityRequestError

from .resource_request import ResourceRequest

Expand Down Expand Up @@ -510,7 +510,7 @@ def add(
profile = self.extract(resource, class_name, profile_only=True)
if self._get_field(profile, "base", "name") == resource.lower():
raise AddOperationError(resource, class_name)
except SecurityResponseError as exception:
except SecurityRequestError as exception:
if not exception.contains_error_message(self._profile_type, "ICH13003I"):
raise exception
self._build_segment_trait_dictionary(traits)
Expand All @@ -527,7 +527,7 @@ def alter(self, resource: str, class_name: str, traits: dict) -> Union[dict, byt
return self._make_request(profile_request, irrsmo00_precheck=True)
try:
profile = self.extract(resource, class_name, profile_only=True)
except SecurityResponseError:
except SecurityRequestError:
raise AlterOperationError(resource, class_name)
if not self._get_field(profile, "base", "name") == resource.lower():
raise AlterOperationError(resource, class_name)
Expand Down
Loading

0 comments on commit 000b71f

Please sign in to comment.