Creating a Python building block

You can extend the Wazi Deploy Python translator that runs the Python building blocks. You can create your own Python building blocks and call them from the deployment method to implement your own action steps.

This scenario is the continuation of the Static deployment with the Python translator scenario.

For example, you might want to implement a new action after the copy to the target PDS. This action submits the JCL that was deployed from the package. Implementing a new action consists in providing a new Python building block that complies with the Wazi Deploy API.

  1. Create a folder and name it modules for example.
  2. In this folder, create a my_job_submit.py Python building block with the following contents:
    from wazideploy_translator.service.evidences import EvidenceStatus
    from wazideploy_translator.service.python_module import PythonModule
    import re
    
    class JobSubmit (PythonModule):
        """
        JobSubmit module for use to trigger a JCL in the scope of the deployment.
        
        Its extend the base PythonModule class.
        """
        def __init__(self):
            super().__init__()
    
        def process(self, deployment_plan:dict, activity:dict, action:dict,
                    step:dict, environment:dict, working_folder:str,
                    extra_vars:dict, dry_run:bool, verbose:bool, evidences:dict, **kwargs):
            """
            Submit the jobs listed in the current step.
        
            Returns
            =======
            list[status, status message, evidences collected]
        
            Parameters
            ==========
            `deployment_plan` : dict
                The Full Deployment Plan
            `activity` : dict
                The current activity in the Deployment Plan
            `action` : dict
                The current action in the Deployment Plan
            `step` : dict
                The current step in the Deployment Plan
            `environment` : dict
                The environment configuration (--envFile option of wazideploy-deploy)
            `working_folder` : str
                The current working folder (--workingFolder option of wazideploy-deploy)
            `extra_vars` : dict
                The extra environment variables (--extraVars option of wazideploy-deploy)
            `evidences` : dict
                The evidences at the beginning of the execution of the building block. This dictionary is a readonly dictionary.
    
            Other Parameters
            ================
            `dry_run` : bool
                Dry Run (must not modify the target)
        
            `verbose` : bool
                Enable verbose messages.
            """
            super().process(deployment_plan, activity, action, step, environment,
                            working_folder, extra_vars, dry_run, verbose, evidences)
            step_success= True
            if not dry_run:
                step_msg = 'All items completed'
            else:
                step_msg = 'Dry run'
            step_results = []
            # Browse all artifacts
            for artifact in step['artifacts']:
                if not dry_run:
                    # Apply to all applicable types
                    path = PythonModule.get_artifact_path(artifact)
                    if path is None:
                        continue
                    var_type =   PythonModule.get_property(step, 'var_type')
                    if not var_type:
                        var_type = 'types'
                    artifact_items_types = environment.get(var_type, [])
                    for item_type in artifact_items_types:
                        if re.match(item_type['pattern'], path, re.IGNORECASE):
                            job_failed, job, job_result = self.submit_job (
                                            f"{item_type['dataset']}({artifact['name']})",
                                            max_rc=0, verbose=False)
                            if job_failed :
                                print(f"*? ERROR: Job {job.id} failed")
                                job_status = EvidenceStatus.FAILED.value
                                step_success = False
                                job_msg = f"Job {job.id} failed"
                                step_msg = "Job failed"
                            else:
                                job_status = EvidenceStatus.OK.value
                                job_msg = f"Job {job.id} succeeded"
                            result = {"status": job_status, "msg": job_msg,
                                        "results": job_result}
                            step_results.append(result)
            return[step_success, step_msg, step_results]
  3. At the end of the static-deployment-method.yml deployment method, add the following activity to submit the JCL that was deployed from the package:
      - name: "Job Submit Activity"
        description: |
          This activity will submit JOBs in the package 
        actions:
            - name: "Job Submit Action"
              states:
                 - UNDEFINED
              steps:
              - name: "Job Submit Action"
                properties:
                - key: template
                  value: my_job_submit
        types:
          - name: 'jcl'
        is_artifact: True
  4. Provide a new .tar file named package.v3.tar. This file must contain a JCL with the .jcl extension.
    In order for the JCL to be correctly processed, add the new JCL type definition in the Python environment variables file (zos-environment.yml).
    • Enter the common characteristics for this new type as follows:
      ommon_pds_txt_spec:
         type: LIBRARY
         primary_space: 10CYL
         secondary_space: 20CYL
         record_format: FB
         record_length: 80
    • Create a types variable. Under this types variable, enter the jcl pattern as follows:
      types:
        - pattern: .*.JCL$
          dataset: "{{ hlq }}.JCL"
          dataset_backup: "{{ hlq }}.BACK.JCL"
          spec: "{{ common_pds_txt_spec }}"
          #encoding:
          # from: UTF-8
          # to: IBM-1047
  5. Generate the deployment plan with the following command:
    wazideploy-generate -dm static-deployment-method.yml -dp deployment_plan.yml -pif package.v3.tar
  6. Trigger the deployment of the last version of the package.
    To do so, enter the following commands. The first command (export DEPLOY_MODULES_PATH) is used to specify the location where the external actions (Python building blocks) of the wazideploy-deploy command are defined. It is a list of folders separated by colons (:) where your building blocks reside.
    export DEPLOY_MODULES_PATH=$PWD/modules
    wazideploy-deploy -dp deployment_plan.yml -pif package.v3.tar -ef zos-environment.yml -wf ./work

At this stage, the JCL should be deployed and automatically submitted.

The job log should be collected in the evidence file that was produced by the wazideploy-deploy command. You can see where the evidence file is stored in the output console of the wazideploy-deploy command.

Wazi Deploy Python API

Python modules

The Python modules provide utility functions to create building blocks.

  • PythonModule.get_property(entity: dict, property_key: str)
    Description
    This method gets the properties key that is associated with the entity in the deployment plan.
    An entity can be one of the following elements:
    • An activity
    • An action
    • A step
    • An artifact
    Returns
    The value of the properties key
    Return type
    • str
    Parameters
    • entity (dict): The current entity, which is activity, action, step, or artifact in the deployment plan
    • property_key (str): The properties key of the entity in the deployment plan
  • PythonModule.get_artifact_type(artifact: dict)
    Description
    This method gets the value of the type key in the properties of the artifact in the deployment plan. This type is indicated in the deployment method.
    Returns
    The value of the artifact type
    Return type
    • str
    Parameters
    • artifact (dict): The artifact
  • PythonModule.get_artifact_path(artifact: dict)
    Description
    This method gets the value of the path key in the properties of the artifact in the deployment plan. It is the path to the artifact in the package file.
    Returns
    The value of the artifact path
    Return type
    • str
    Parameters
    • artifact (dict): The artifact
  • PythonModule.render_jinja2_template(template_file:str, output_file: str, environment:dict, extra_vars:dict, verbose:bool = True, **kwargs)
    Description
    This method transforms a Jinja2 template into a file where the variables are resolved.
    Returns
    None
    Return type
    None
    Parameters
    • template_file (str): The source Jinja2 file.
    • output_file (str): The output file where the variables are resolved.
    • environment (dict): The z/OS environment configuration file that is used by the Wazi Deploy Python deployment command (wazideploy-deploy).
    • extra_vars (dict): The value of the variables that were added to the environment variables file as extra_vars. These variables can be indicated in the Wazi Deploy Python deployment command (wazideploy-deploy).
    • verbose (bool)
  • PythonModule.submit_job(job_source:str, max_rc:int = -1, wait_time_s:int = -1, verbose:bool = True, **kwargs)
    Description
    This method submits a z/OS job.
    Returns
    (job_status(str), job (ZOAU job), job_result (array))
    Return type
    Tuple
    Parameters
    • job_source (str): The job location (z/OS UNIX System Services or dataset)
    • max_rc (int): The maximum return code of the JCL execution
    • wait_time_s (int): The maximum time in seconds to wait for the job to complete
    • verbose (bool)