JCL Templates
Use templates to generate JCL dynamically in Grace workflows.
Grace offers powerful JCL templating capabilities, allowing you to customize the Job Control Language (JCL) generated for your z/OS job modules (compile, linkedit, execute). While Grace provides sensible default JCL templates for these job types, you can supply your own template files using the job.jcl field with a file:// prefix.
When Grace processes a job with jcl: file://path/to/mytemplate.jcl.tmpl (and the --no-compile flag is not used), it reads this file and processes it using Go's built-in text/template engine. This allows you to use template variables and functions to dynamically construct your JCL based on data exposed by Grace from your grace.yml and resolved values.
If your
file://JCL source does not contain any Go template directives ({{ ... }}), Grace will treat it as a static JCL file, and the "rendering" process will output its content verbatim.
Enabling JCL templating
To use JCL templating for a specific z/OS job:
-
Create a JCL template file (e.g.,
my_compile_job.jcl.tmpl) in your project, typically within a./templatesor./jclsubdirectory. -
In your
grace.ymlfor the desired job, set thejclfield to point to this file:
When grace deck runs (without --no-compile), it will read mycomp.jcl.tmpl, populate it with the available data context, and write the rendered JCL to .grace/deck/MYCOMP.jcl
Available data context (JCLTemplateData)
Grace exposes a structured set of data to your JCL templates. This data, referred to internally as JCLTemplateData, allows you to access resolved values from your grace.yml and Grace's internal processing.
Here are the top-level fields available:
General job data
-
{{ .JobName }}(String) : Thenameof the current job fromgrace.yml.- e.g.
MYCOMPILE
- e.g.
-
{{ .WorkflowId }}(String) : The unique UUID of the current workflow run.- Note: This will be an empty string if
grace deckis run outside the context of a fullgrace runorgrace submit(asdeckitself doesn't produce a workflow UUID). Useful for adding unique qualifiers if needed, but rely on Grace'szos-temp://hashing for DSN uniqueness.
- Note: This will be an empty string if
-
{{ .Type }}(String) : Thetypeof the current job (e.g.,compile,linkedit,execute).
Program and library data
These are resolved considering global config.defaults and job-level overrides.
-
{{ .ProgramName }}(String) :- For
type: execute: The name of the program to execute (fromjob.program). - For
type: linkedit: The name of the output load module (fromjob.program). - For
type: compile: The value ofjob.programif specified (often for metadata or if a subsequent link-edit uses it by convention).
- For
-
{{ .LoadLib }}(String) : The DSN of the resolved load library (fromdatasets.loadlibor job-leveldatasetsoverride). -
Compiler specific (available for all z/OS job types, but most relevant for
type: compile):{{ .CompilerPgm }}(String) : Resolved program name for the compiler (e.g.IGYCRCTL).{{ .CompilerParms }}(String) : Resolved compiler parameters.{{ .CompilerSteplib }}(String) : ResolvedSTEPLIBDSN for the compiler (can be empty).
-
Linker specific (available for all z/OS job types, but most relevant for
type: linkedit):{{ .LinkerPgm }}(String) : Resolved program name for the linkage editor (e.g.IEWL).{{ .LinkerParms }}(String) : Resolved linkage editor parameters.{{ .LinkerSteplib }}(String) : ResolvedSTEPLIBDSN for the linkage editor (can be empty).
Input and output DD data
You have two way to include DD statements for your job's inputs and outputs:
-
{{ .DDStatements }}- Type:
String - Description: A pre-rendered block of JCL DD statements for all
inputsandoutputsdefined for the job. Grace generates this block using standard JCL formatting and the resolved DSNs, dispositions, DCB, and space parameters. - Usage: Simply place
{{ .DDStatements }}where you want these DDs to appear. This is the easiest way if you don't need to heavily customize individual DDs or intersperse them with other custom DD statements. - Example in template:
- Type:
-
{{ .Inputs }}/{{ .Outputs }}(granular control)- Type:
[]Object- These are arrays of
ResolvedDDobjects.
- These are arrays of
- Description: These provide access to each resolved input and output individually, allowing you to loop through them and construct DD statements with custom formatting or logic.
- Structure:
{{ .Name }}(String) : The DDName (e.g.SYSIN,CUSTFILE).{{ .DSN }}(String) : The fully resolved physical DSN (e.g.IBMUSER.PROJ.SRC(MYPROG),IBMUSER.TEMP.H123AB.SYSLIN).{{ .DISP }}(String) : The resolved JCL disposition (e.g.SHR,(NEW,CATLG,DELETE)). This considersjob.dispfor outputs, and is overridden bykeep.{{ .Space }}(String,outputsonly) : The resolved JCLSPACEparameter (e.g.(TRK,(5,2),RLSE)).{{ .DCB }}(String,outputsonly) : The resolved JCLDCBparameter (e.g.RECFM=FB,LRECL=80).{{ .IsOutput }}(Boolean) :trueif this is from theoutputsarray,falseif frominputs. (Useful if you process them in a combined loop, though ranging separately is common practice).
- Example in template:
Choose either
{{ .DDStatements }}or the{{ range .Inputs/Outputs - }}method for defining your data DDs. Using both for the same set of inputs/outputs will lead to duplicate DD statements. - Type:
Available template functions
Grace makes a few utility functions available in JCL templates:
{{ ToUpper .StringValue }}
Converts a string to uppercase.
- e.g.
//{{ .JobName | ToUpper }} JOB ...results in//MYJOB JOB ...
{{ Default "fallback" .PossiblyEmptyValue }}
Provides a fallback value if .PossiblyEmptyValue is null or an empty string.
- e.g.
//PARM='{{ Default "NOLIST" .LinkerParms }}'- If
.LinkerParmsis"", this becomesPARM='NOLIST'. - If
.LinkerParmsis"LIST,MAP", this becomesPARM='LIST,MAP'.
- If
Example JCL template (mycomp.jcl.tmpl)
Tips for writing JCL templates
- Start simple: Begin by copying one of Grace's internal templates (from the
internal/templates/files/directory in the Grace source code) and modify it. - Test iteratively: Use
grace deck --only JOBNAMEto quickly regenerate and inspect the JCL in.grace/deck/JOBNAME.jclafter making changes to your template. - Refer to Go's
text/templatedocs: For advanced templating logic (conditionals, loops, custom functions) beyond what is described here, consult the official Gotext/templatedocumentation. - Whitespace control: Use
{{ - ... - }}(hyphens) to control whitespace around template actions if needed, to keep your generated JCL clean.
By leveraging JCL templating, you gain precise control and extensibility over the JCL submitted for your z/OS jobs while still benefitting from Grace's data resolution and workflow orchestration mechanisms.