config_validator.py (120 lines of code) (raw):

# Copyright 2024 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Processes and validates SAP Reporting config.json. """ import logging from typing import Union from common.py_libs import resource_validation_helper def validate(cfg: dict) -> Union[dict, None]: """Validates and processes configuration. It will discover and log all issues before returning. Args: cfg (dict): Config dictionary. Returns: dict: Processed config dictionary. None: In case of validation failure """ failed = False if not cfg.get("deploySAP", False): logging.info("SAP is not being deployed. Skipping validation.") return cfg logging.info("Validating SAP configuration.") sap = cfg.get("SAP") if not sap: logging.error("🛑 Missing 'SAP' values in the config file. 🛑") return None missing_sap_attrs = [] for attr in ("deployCDC", "languages", "currencies", "datasets"): if sap.get(attr) is None or sap.get(attr) == "": missing_sap_attrs.append(attr) if missing_sap_attrs: logging.error("🛑 Missing 'SAP values: %s' in the config file. 🛑", missing_sap_attrs) failed = True datasets = sap.get("datasets") flavor = sap.get("SQLFlavor", "ecc").lower() sap["SQLFlavor"] = flavor cfg_sap_ds_cdc = datasets.get("cdc") cfg_sap_ds_cdc_ecc = datasets.get("cdcECC") cfg_sap_ds_cdc_s4 = datasets.get("cdcS4") if flavor == "ecc": if cfg_sap_ds_cdc and not cfg_sap_ds_cdc_ecc: cfg_sap_ds_cdc_ecc = cfg_sap_ds_cdc else: cfg_sap_ds_cdc = cfg_sap_ds_cdc_ecc elif flavor == "s4": if cfg_sap_ds_cdc and not cfg_sap_ds_cdc_s4: cfg_sap_ds_cdc_s4 = cfg_sap_ds_cdc else: cfg_sap_ds_cdc = cfg_sap_ds_cdc_s4 if not cfg_sap_ds_cdc: logging.error(("🛑 Cannot resolve SAP/datasets/cdc|cdcECC|cdcS4 values " "in the config file. 🛑")) failed = True datasets["cdc"] = cfg_sap_ds_cdc datasets["cdcECC"] = cfg_sap_ds_cdc_ecc datasets["cdcS4"] = cfg_sap_ds_cdc_s4 cfg_sap_ds_raw = datasets.get("raw") cfg_sap_ds_raw_ecc = datasets.get("rawECC") cfg_sap_ds_raw_s4 = datasets.get("rawS4") if flavor == "union": if not cfg_sap_ds_raw_ecc or not cfg_sap_ds_raw_s4: logging.error("🛑 SAP/SQLFlavor=union requires " "all parameters for both ECC and S4. 🛑") failed = True elif flavor == "ecc": if cfg_sap_ds_raw and not cfg_sap_ds_raw_ecc: cfg_sap_ds_raw_ecc = cfg_sap_ds_raw else: cfg_sap_ds_raw = cfg_sap_ds_raw_ecc elif flavor == "s4": if cfg_sap_ds_raw and not cfg_sap_ds_raw_s4: cfg_sap_ds_raw_s4 = cfg_sap_ds_raw else: cfg_sap_ds_raw = cfg_sap_ds_raw_s4 if not cfg_sap_ds_raw: logging.error(("🛑 Cannot resolve SAP/datasets/raw|rawECC|rawS4 values " "in the config file. 🛑")) failed = True datasets["raw"] = cfg_sap_ds_raw datasets["rawECC"] = cfg_sap_ds_raw_ecc datasets["rawS4"] = cfg_sap_ds_raw_s4 cfg_sap_ds_reporting = datasets.get("reporting", "REPORTING") datasets["reporting"] = cfg_sap_ds_reporting cfg_sap_mandt = sap.get("mandt") cfg_sap_mandt_ecc = sap.get("mandtECC") cfg_sap_mandt_s4 = sap.get("mandtS4") if flavor == "union": if not cfg_sap_mandt_ecc or not cfg_sap_mandt_s4: logging.error(("🛑 SAP/SQLFlavor=union requires " "all parameters for both ECC and S4. 🛑")) failed = True elif cfg_sap_mandt_ecc == cfg_sap_mandt_s4: logging.error(("🛑 Same ECC and S4 MANDT " "is not allowed for UNION workloads. 🛑")) failed = True elif flavor == "ecc": if cfg_sap_mandt and not cfg_sap_mandt_ecc: cfg_sap_mandt_ecc = cfg_sap_mandt else: cfg_sap_mandt = cfg_sap_mandt_ecc elif flavor == "s4": if cfg_sap_mandt and not cfg_sap_mandt_s4: cfg_sap_mandt_s4 = cfg_sap_mandt else: cfg_sap_mandt = cfg_sap_mandt_s4 if not cfg_sap_mandt: logging.warning("⚠️ Using default SAP Mandt/client = 100.") cfg_sap_mandt = "100" sap["mandt"] = cfg_sap_mandt sap["mandtECC"] = cfg_sap_mandt_ecc or cfg_sap_mandt sap["mandtS4"] = cfg_sap_mandt_s4 or cfg_sap_mandt source = cfg["projectIdSource"] target = cfg["projectIdTarget"] location = cfg["location"] datasets = [ resource_validation_helper.DatasetConstraints( f"{source}.{cfg_sap_ds_raw}", True, cfg.get("testData", False), location), resource_validation_helper.DatasetConstraints( f"{source}.{cfg_sap_ds_cdc}", True, True, location), resource_validation_helper.DatasetConstraints( f"{target}.{cfg_sap_ds_reporting}", False, True, location) ] if not resource_validation_helper.validate_resources([], datasets): logging.error("🛑 'SAP' resource validation failed. 🛑") failed = True if failed: logging.error("🛑 SAP configuration is invalid. 🛑") return None else: logging.info("✅ SAP configuration is good. ✅") return cfg