diff --git a/doc/apis.md b/doc/apis.md index a790938..35efcf6 100644 --- a/doc/apis.md +++ b/doc/apis.md @@ -75,7 +75,7 @@ | _List spool files_ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | _Read spool file_ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | _Get job JCL_ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | -| _Submit job_ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | +| _Submit job_ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | _Delete job_ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Cancel job | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ 1 | | Hold job | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ➖ 2 | diff --git a/native/CHANGELOG.md b/native/CHANGELOG.md index 5ebc0e6..2ede9fc 100644 --- a/native/CHANGELOG.md +++ b/native/CHANGELOG.md @@ -27,6 +27,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how - `c`: Added check for maximum data set pattern length before making a list request. Now, requests with patterns longer than 44 characters are rejected. [#185](https://github.com/zowe/zowe-native-proto/pull/185) - `c,golang`: Fixed issue where submit JCL handler did not convert input data from UTF-8 and did not support an `--encoding` option. [#198](https://github.com/zowe/zowe-native-proto/pull/198) - `c`: Fixed issue where submit JCL handler did not support raw bytes from stdin when the binary is directly invoked through a shell. [#198](https://github.com/zowe/zowe-native-proto/pull/198) +- `c,golang`: Added `submitUss` function. [#184](https://github.com/zowe/zowe-native-proto/pull/184) ## [Unreleased] diff --git a/native/c/zowex.cpp b/native/c/zowex.cpp index 54a7b2a..4880d39 100644 --- a/native/c/zowex.cpp +++ b/native/c/zowex.cpp @@ -42,6 +42,7 @@ int handle_job_view_file(ZCLIResult); int handle_job_view_jcl(ZCLIResult); int handle_job_submit(ZCLIResult); int handle_job_submit_jcl(ZCLIResult); +int handle_job_submit_uss(ZCLIResult); int handle_job_delete(ZCLIResult); int handle_job_cancel(ZCLIResult); int handle_job_hold(ZCLIResult); @@ -312,6 +313,18 @@ int main(int argc, char *argv[]) job_submit_jcl.get_options().push_back(encoding_option); job_group.get_verbs().push_back(job_submit_jcl); + ZCLIVerb job_submit_uss("submit-uss"); + job_submit_uss.get_aliases().push_back("sub-u"); + job_submit_uss.set_description("submit a job from USS files"); + job_submit_uss.set_zcli_verb_handler(handle_job_submit_uss); + ZCLIPositional job_uss_file("file-path"); + job_uss_file.set_required(true); + job_uss_file.set_description("USS file containing JCL"); + job_submit_uss.get_positionals().push_back(job_uss_file); + + job_submit_uss.get_options().push_back(job_jobid_only); + job_group.get_verbs().push_back(job_submit_uss); + ZCLIVerb job_delete("delete"); job_delete.get_aliases().push_back("del"); job_delete.set_description("delete a job"); @@ -790,6 +803,44 @@ int handle_job_submit(ZCLIResult result) return RTNCD_SUCCESS; } +int handle_job_submit_uss(ZCLIResult result) +{ + int rc = 0; + ZJB zjb = {0}; + string file(result.get_positional("file-path")->get_value()); + + ZUSF zusf = {0}; + string response; + rc = zusf_read_from_uss_file(&zusf, file, response); + if (0 != rc) + { + cerr << "Error: could not view USS file: '" << file << "' rc: '" << rc << "'" << endl; + cerr << " Details:\n" + << zusf.diag.e_msg << endl + << response << endl; + return RTNCD_FAILURE; + } + + vector jobs; + string jobid; + rc = zjb_submit(&zjb, response, jobid); + + if (0 != rc) + { + cerr << "Error: could not submit JCL: '" << file << "' rc: '" << rc << "'" << endl; + cerr << " Details: " << zjb.diag.e_msg << endl; + return RTNCD_FAILURE; + } + + string only_jobid(result.get_option("--only-jobid")->get_value()); + if ("true" == only_jobid) + cout << jobid << endl; + else + cout << "Submitted " << file << ", " << jobid << endl; + + return RTNCD_SUCCESS; +} + int handle_job_submit_jcl(ZCLIResult result) { int rc = 0; diff --git a/native/golang/cmds/definitions.go b/native/golang/cmds/definitions.go index a6718bc..fbbe60e 100644 --- a/native/golang/cmds/definitions.go +++ b/native/golang/cmds/definitions.go @@ -51,6 +51,7 @@ func initializeJobHandlers(disp *CmdDispatcher) { "readSpool": HandleReadSpoolRequest, "submitJob": HandleSubmitJobRequest, "submitJcl": HandleSubmitJclRequest, + "submitUss": HandleSubmitUssRequest, "cancelJob": HandleCancelJobRequest, "deleteJob": HandleDeleteJobRequest, "holdJob": HandleHoldJobRequest, diff --git a/native/golang/cmds/jobs.go b/native/golang/cmds/jobs.go index 58113a1..1748884 100644 --- a/native/golang/cmds/jobs.go +++ b/native/golang/cmds/jobs.go @@ -262,7 +262,29 @@ func HandleSubmitJobRequest(conn *utils.StdioConn, params []byte) (result any, e result = jobs.SubmitJobResponse{ Success: true, Dsname: request.Dsname, - JobId: strings.TrimSpace(string(out)), + JobId: string(out), + } + return +} + +// HandleSubmitUssRequest handles a SubmitUssRequest by invoking the `zowex job submit-uss` command +func HandleSubmitUssRequest(conn *utils.StdioConn, params []byte) (result any, e error) { + request, err := utils.ParseCommandRequest[jobs.SubmitUssRequest](params) + if err != nil { + return nil, err + } + + out, err := conn.ExecCmd([]string{"job", "submit-uss", request.Path, "--only-jobid", "true"}) + + if err != nil { + e = fmt.Errorf("Failed to submit job: %v", err) + return + } + + result = jobs.SubmitUssResponse{ + Success: true, + Path: request.Path, + JobId: string(out), } return } @@ -309,7 +331,7 @@ func HandleSubmitJclRequest(conn *utils.StdioConn, params []byte) (result any, e result = jobs.SubmitJclResponse{ Success: true, - JobId: strings.TrimSpace(string(out)), + JobId: string(out), } return } diff --git a/native/golang/types/jobs/requests.go b/native/golang/types/jobs/requests.go index 1f57c25..92cd060 100644 --- a/native/golang/types/jobs/requests.go +++ b/native/golang/types/jobs/requests.go @@ -64,6 +64,13 @@ type SubmitJobRequest struct { Dsname string `json:"dsname"` } +type SubmitUssRequest struct { + common.CommandRequest `tstype:",extends"` + Command string `json:"command" tstype:"\"submitUss\""` + // File path w/ contents to submit as JCL + Path string `json:"fspath"` +} + type SubmitJclRequest struct { common.CommandRequest `tstype:",extends"` Command string `json:"command" tstype:"\"submitJcl\""` diff --git a/native/golang/types/jobs/responses.go b/native/golang/types/jobs/responses.go index 802c3e5..6abe878 100644 --- a/native/golang/types/jobs/responses.go +++ b/native/golang/types/jobs/responses.go @@ -60,6 +60,16 @@ type SubmitJobResponse struct { Dsname string `json:"dsname"` } +type SubmitUssResponse struct { + common.CommandResponse `tstype:",extends"` + // Whether the job was successfully submitted + Success bool `json:"success"` + // The job ID of the newly-submitted job + JobId string `json:"jobId"` + // The USS file where the JCL was read from + Path string `json:"fspath"` +} + type SubmitJclResponse struct { common.CommandResponse `tstype:",extends"` // Whether the JCL was successfully submitted diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index a424180..d970473 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -12,6 +12,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how - Added support for cancelling jobs. [#138](https://github.com/zowe/zowe-native-proto/pull/138) - Added support for holding and releasing jobs. [#182](https://github.com/zowe/zowe-native-proto/pull/182) - Updated error handling for listing data sets. [#185](https://github.com/zowe/zowe-native-proto/pull/185) +- Added `zssh submit uss-file|local-file|data-set` commands. [#184](https://github.com/zowe/zowe-native-proto/pull/184) ## [Unreleased] diff --git a/packages/cli/src/submit/Submit.definition.ts b/packages/cli/src/submit/Submit.definition.ts index fe49e28..44734b6 100644 --- a/packages/cli/src/submit/Submit.definition.ts +++ b/packages/cli/src/submit/Submit.definition.ts @@ -12,7 +12,10 @@ import type { ICommandDefinition } from "@zowe/imperative"; import { SshSession } from "@zowe/zos-uss-for-zowe-sdk"; import { Constants } from "../Constants"; +import { SubmitDsDefinition } from "./ds/Dataset.definition"; +import { SubmitLocalFileDefinition } from "./local-file/LocalFile.definition"; import { SubmitStdinDefinition } from "./stdin/Stdin.definition"; +import { SubmitUssDefinition } from "./uss/Uss.definition"; const SubmitDefinition: ICommandDefinition = { name: "submit", @@ -20,7 +23,7 @@ const SubmitDefinition: ICommandDefinition = { summary: "Submit contents", description: "Submit resource contents or requests to a mainframe system", type: "group", - children: [SubmitStdinDefinition], + children: [SubmitStdinDefinition, SubmitDsDefinition, SubmitUssDefinition, SubmitLocalFileDefinition], passOn: [ { property: "options", diff --git a/packages/cli/src/submit/ds/Dataset.definition.ts b/packages/cli/src/submit/ds/Dataset.definition.ts new file mode 100644 index 0000000..0628f51 --- /dev/null +++ b/packages/cli/src/submit/ds/Dataset.definition.ts @@ -0,0 +1,37 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import type { ICommandDefinition } from "@zowe/imperative"; + +export const SubmitDsDefinition: ICommandDefinition = { + handler: `${__dirname}/Dataset.handler`, + description: "Submit a job from JCL written in a dataset.", + type: "command", + name: "data-set", + aliases: ["ds"], + summary: "Submit a job from a dataset", + examples: [ + { + description: 'Submit a job from the dataset "IBMUSER.PUBLIC.CNTL(IEFBR14)"', + options: '"IBMUSER.PUBLIC.CNTL(IEFBR14)"', + }, + ], + positionals: [ + { + name: "name", + description: "The dataset containing the JCL to submit", + type: "string", + required: true, + }, + ], + profile: { optional: ["ssh"] }, + outputFormatOptions: true, +}; diff --git a/packages/cli/src/submit/ds/Dataset.handler.ts b/packages/cli/src/submit/ds/Dataset.handler.ts new file mode 100644 index 0000000..53a3e65 --- /dev/null +++ b/packages/cli/src/submit/ds/Dataset.handler.ts @@ -0,0 +1,30 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { text } from "node:stream/consumers"; +import type { IHandlerParameters } from "@zowe/imperative"; +import type { ZSshClient, jobs } from "zowe-native-proto-sdk"; +import { SshBaseHandler } from "../../SshBaseHandler"; + +export default class SubmitDsHandler extends SshBaseHandler { + public async processWithClient(params: IHandlerParameters, client: ZSshClient): Promise { + const dsname = params.arguments.name; + const response = await client.jobs.submitJob({ dsname }); + + const msg = `Job submitted: ${response.jobId}`; + params.response.data.setMessage(msg); + params.response.data.setObj(response); + if (response.success) { + params.response.console.log(msg); + } + return response; + } +} diff --git a/packages/cli/src/submit/local-file/LocalFile.definition.ts b/packages/cli/src/submit/local-file/LocalFile.definition.ts new file mode 100644 index 0000000..c967006 --- /dev/null +++ b/packages/cli/src/submit/local-file/LocalFile.definition.ts @@ -0,0 +1,37 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import type { ICommandDefinition } from "@zowe/imperative"; + +export const SubmitLocalFileDefinition: ICommandDefinition = { + handler: `${__dirname}/LocalFile.handler`, + description: "Submit a job from JCL written in a local file.", + type: "command", + name: "local-file", + aliases: ["lf"], + summary: "Submit a job from local files", + examples: [ + { + description: 'Submit a job from the file "my_jcl.txt"', + options: '"my_jcl.txt"', + }, + ], + positionals: [ + { + name: "fspath", + description: "The path to the JCL to submit", + type: "string", + required: true, + }, + ], + profile: { optional: ["ssh"] }, + outputFormatOptions: true, +}; diff --git a/packages/cli/src/submit/local-file/LocalFile.handler.ts b/packages/cli/src/submit/local-file/LocalFile.handler.ts new file mode 100644 index 0000000..5deec65 --- /dev/null +++ b/packages/cli/src/submit/local-file/LocalFile.handler.ts @@ -0,0 +1,40 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import { readFileSync } from "node:fs"; +import { type IHandlerParameters, ImperativeError } from "@zowe/imperative"; +import { B64String, type ZSshClient, type jobs } from "zowe-native-proto-sdk"; +import { SshBaseHandler } from "../../SshBaseHandler"; + +export default class SubmitLocalFileHandler extends SshBaseHandler { + public async processWithClient(params: IHandlerParameters, client: ZSshClient): Promise { + const fspath = params.arguments.fspath; + let JclString: Buffer; + try { + JclString = readFileSync(fspath); + } catch (err) { + throw new ImperativeError({ + msg: "Failed to read local file", + additionalDetails: err.toString(), + causeErrors: err, + }); + } + const response = await client.jobs.submitJcl({ jcl: B64String.encode(JclString) }); + + const msg = `Job submitted: ${response.jobId}`; + params.response.data.setMessage(msg); + params.response.data.setObj(response); + if (response.success) { + params.response.console.log(msg); + } + return response; + } +} diff --git a/packages/cli/src/submit/uss/Uss.definition.ts b/packages/cli/src/submit/uss/Uss.definition.ts new file mode 100644 index 0000000..f293a9a --- /dev/null +++ b/packages/cli/src/submit/uss/Uss.definition.ts @@ -0,0 +1,37 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import type { ICommandDefinition } from "@zowe/imperative"; + +export const SubmitUssDefinition: ICommandDefinition = { + handler: `${__dirname}/Uss.handler`, + description: "Submit a job from JCL written in a USS file.", + type: "command", + name: "uss-file", + aliases: ["uss"], + summary: "Submit a job from USS files", + examples: [ + { + description: 'Submit a job from the USS file "my_jcl.txt"', + options: '"my_jcl.txt"', + }, + ], + positionals: [ + { + name: "fspath", + description: "The USS path to the JCL to submit", + type: "string", + required: true, + }, + ], + profile: { optional: ["ssh"] }, + outputFormatOptions: true, +}; diff --git a/packages/cli/src/submit/uss/Uss.handler.ts b/packages/cli/src/submit/uss/Uss.handler.ts new file mode 100644 index 0000000..36ece5f --- /dev/null +++ b/packages/cli/src/submit/uss/Uss.handler.ts @@ -0,0 +1,29 @@ +/** + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-v20.html + * + * SPDX-License-Identifier: EPL-2.0 + * + * Copyright Contributors to the Zowe Project. + * + */ + +import type { IHandlerParameters } from "@zowe/imperative"; +import type { ZSshClient, jobs } from "zowe-native-proto-sdk"; +import { SshBaseHandler } from "../../SshBaseHandler"; + +export default class SubmitUssHandler extends SshBaseHandler { + public async processWithClient(params: IHandlerParameters, client: ZSshClient): Promise { + const fspath = params.arguments.fspath; + const response = await client.jobs.submitUss({ fspath }); + + const msg = `Job submitted: ${response.jobId}`; + params.response.data.setMessage(msg); + params.response.data.setObj(response); + if (response.success) { + params.response.console.log(msg); + } + return response; + } +} diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 9423e92..02ad40a 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -9,6 +9,7 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how - Added `ds.restoreDataset` function. [#38](https://github.com/zowe/zowe-native-proto/pull/38) - Added support for cancelling jobs. [#138](https://github.com/zowe/zowe-native-proto/pull/138) - Added support for holding and releasing jobs. [#182](https://github.com/zowe/zowe-native-proto/pull/182) +- Added `jobs.submitUss` function. [#184](https://github.com/zowe/zowe-native-proto/pull/184) ## [Unreleased] diff --git a/packages/sdk/src/AbstractRpcClient.ts b/packages/sdk/src/AbstractRpcClient.ts index b7b8168..f5b18c0 100644 --- a/packages/sdk/src/AbstractRpcClient.ts +++ b/packages/sdk/src/AbstractRpcClient.ts @@ -53,6 +53,8 @@ export abstract class AbstractRpcClient { this.request({ command: "deleteJob", ...request }), submitJob: (request: Omit): Promise => this.request({ command: "submitJob", ...request }), + submitUss: (request: Omit): Promise => + this.request({ command: "submitUss", ...request }), submitJcl: (request: Omit): Promise => this.request({ command: "submitJcl", ...request }), holdJob: (request: Omit): Promise => diff --git a/packages/sdk/src/doc/gen/jobs.ts b/packages/sdk/src/doc/gen/jobs.ts index 7d9e49f..464cc3d 100644 --- a/packages/sdk/src/doc/gen/jobs.ts +++ b/packages/sdk/src/doc/gen/jobs.ts @@ -74,6 +74,13 @@ export interface SubmitJobRequest extends common.CommandRequest { */ dsname: string; } +export interface SubmitUssRequest extends common.CommandRequest { + command: "submitUss"; + /** + * File path w/ contents to submit as JCL + */ + fspath: string; +} export interface SubmitJclRequest extends common.CommandRequest { command: "submitJcl"; /** @@ -173,6 +180,20 @@ export interface SubmitJobResponse extends common.CommandResponse { */ dsname: string; } +export interface SubmitUssResponse extends common.CommandResponse { + /** + * Whether the job was successfully submitted + */ + success: boolean; + /** + * The job ID of the newly-submitted job + */ + jobId: string; + /** + * The USS file where the JCL was read from + */ + fspath: string; +} export interface SubmitJclResponse extends common.CommandResponse { /** * Whether the JCL was successfully submitted