diff --git a/.gitignore b/.gitignore index c2658d7..b8e0d43 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules/ +ca.pem +test.sh diff --git a/README.md b/README.md index df97ad5..9d22cef 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This CLI tool has been tested against This project is licensed under the Apache 2.0 License - see the LICENSE file for details These tools are provided as-is and without warranty or support. They do not constitute part of the Software AG product suite. Users are free to use, fork and modify them, subject to the license agreement. While Software AG welcomes contributions, we cannot guarantee to include every contribution in the master project. -Contact us via the TECHcommunity if you have any questions. +Contact us via the TECHcommunity (https://techcommunity.softwareag.com/) if you have any questions. # Installation ``` @@ -32,39 +32,103 @@ node wmiocli.js --help Usage: wmiocli [options] [command] Options: - -V, --version output the version number - -d, --domain Tenant Doamin Name, e.g. "tenant.int-aws-us.webmethods.io" - -u, --user Tenant User ID - -p, --password Tenant User Password - -t, --timeout timeout in seconds (default: one minute) - --prettyprint Pretty Print JSON output - --verbose Verbose output useful for diagnosing issues - -h, --help display help for command + -V, --version + output the version number + -d, --domain + Tenant Doamin Name, e.g. "tenant.int-aws-us.webmethods.io" + -u, --user + Tenant User ID + -p, --password + Tenant User Password + -t, --timeout + timeout in seconds (default: one minute) + --prettyprint + Pretty Print JSON output + --verbose + Verbose output useful for diagnosing issues + -h, --help + display help for command Commands: - project [project-name] Lists all projects or view an individual project, specified via project name or uid - project-assets Lists project assets from given project name or uid - project-create Create project with given name - project-update Update project with new name - project-delete Delete project with given id + project [project-name] + Lists all projects or view an individual project, specified via project name or uid + project-assets + Lists project assets from given project name or uid + project-create + Create project with given name + project-update + Update project with new name + project-delete + Delete project with given id project-publish Pubilsh project to another tenant with given id - project-deploy deploy published project with given version into tenant - role [role-id] Lists all roles or views an individual role - role-create Create roles and specify the permissions for that role. Roles-list should be provided as follows projectName,r,w,e;project name 2,r; - role-update Create roles and specify the permissions for that role. Roles-list should be provided as follows projectName,r,w,e;project name 2,r; - role-delete Delete a roles with the given role id - user Lists all users - user-role-assignment Assigns a user to roles - workflow-export Export workflow with id from project - workflow-import Import workflow into project from file - workflow-delete Delete workflow from project - workflow-execute Execute workflow from project - workflow-status Gets Execution status for workflow execution - flowservice-export Export FlowService with name from project - flowservice-import Import FlowService from into project - flowservice-delete Delete FlowService from project - flowservice-execute [input-json] Execute FlowService from project with data - help [command] display help for command + project-deploy + deploy published project with given version into tenant + project-param [param-uid] + Lists all project parameters from given project name, or specific parameter with given paramater uid + project-param-create + Creates a project parameter with given values + project-param-update + Updates a project parameter matching the provided UID with given values + project-param-delete + Deletes a project parameter mathcing the given paramater uid + project-webhooks-list + List webhooks in a project + project-webhooks-regenerate + Regenerate a webhook in a project for a given workflow UID + project-webhooks-auth + Set authenatication type (none,login,token) for a webhook in a project for a given workflow UID + role [role-id] + Lists all roles or views an individual role + role-create + Create roles and specify the permissions for that role. Roles-list should be provided as follows projectName,r,w,e;project name 2,r; + role-update + Create roles and specify the permissions for that role. Roles-list should be provided as follows projectName,r,w,e;project name 2,r; + role-delete + Delete a roles with the given role id + user + Lists all users + user-role-assignment + Assigns a user to roles + workflow-export + Export workflow with id from project + workflow-import + Import workflow into project from file + workflow-delete + Delete workflow from project + workflow-execute + Execute workflow from project + workflow-status + Gets Execution status for workflow execution + flowservice-export + Export FlowService with name from project + flowservice-import + Import FlowService from into project + flowservice-delete + Delete FlowService from project + flowservice-execute [input-json] + Execute FlowService from project with data + theme [theme-uid] + Lists themes or views an individual theme, specified via uid + theme-create [footer-text] [about-page] + Create theme with given data + theme-update [footer-text] [about-page] + Update theme with the given UID with given data + theme-delete + Delete theme with the given UID + theme-activate + Activate theme with the given UID + theme-deactivate + Deactivate theme with the given UID + recipe [recipe-uid] + List all Workflow recipes, or get a single recipe with a given recipe UID + recipe-delete + Delete Workflow recipe with a given recipe UID + recipe-create + Create Workfllow Receipt from file + unofficial [recipe-uid] + List all Workflow recipes, or get a single recipe with a given recipe UID + help [command] + display help for command Examples: @@ -122,21 +186,80 @@ Examples: -p password project-assets fl65d3aa87fc1783ea5cf8c8 - /Publish Project to another tenant: + Publish Project to another tenant: $ node wmiocli.js -d tenant.int-aws-us.webmethods.io -u user -p password - project-publish fl65d3aa87fc1783ea5cf8c8 'My deployment' 'target.int-aws-us.webmethods.io' 'targetuser' 'targetpassword' '{"output":{"workflows":["fla73a20e13dd6736cf9c355","fl3cfd145262bbc5d44acff3"],"flows":["mapLeads"],"rest_api":[],"soap_api":[],"listener":[],"messaging":[]}}' + project-publish fl65d3aa87fc1783ea5cf8c8 'My deployment' 'target.int-aws-us.webmethods.io' + 'targetuser' 'targetpassword' + '{"output":{"workflows":["fla73a20e13dd6736cf9c355","fl3cfd145262bbc5d44acff3"], + "flows":["mapLeads"],"rest_api":[],"soap_api":[],"listener":[],"messaging":[]}}' - /Deploy published Project in the tenant with the given name and deploy version: + Deploy published Project in the tenant with the given name and deploy version: $ node wmiocli.js -d tenant.int-aws-us.webmethods.io -u user -p password project-deploy projectName 1 + + List Project Workflow Parameters or gets an individual where name is specified + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + project-param projectName [param-name] + + Create Project Workflow Parameter + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + project-param-create projectName param-name param-value required isPassword + + e.g. node wmiocli.js -d env -u user -p pass project-param-create project name dave false false + + Update Project Workflow Parameter + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + project-param-update projectName param-uid param-name param-value required isPassword + + Delete Project Workflow Parameter + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + project-param-delete projectName param-uid + + Project webhooks List + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + project-webhooks-list [project-uid] + + Regenerate webhook token + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + project-webhooks-regenerate project-uid webhook-uid + + Change webhook Auth + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + project-webhooks-auth project-uid webhook-uid auth-type + + e.g. + node wmiocli.js -d env -u user -p pass project-webhooks-auth flf1111 flf2222 login + + Workflow Export Workflow from a given project (identified from URL in webMethods.io when in workflow canvas, @@ -237,4 +360,85 @@ Examples: -u user -p password role-delete 'roleId' + + + Recipes + + Get recipe list or individual recipe + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + recipe [recipe-Uid] + + Creates a Workflow recipe from a workflow export + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + recipe-create export-flf111111.zip + + Deletes a Workflow recipe with the provided UID + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + recipe-delete fl1771d591cfb4f31e558daf + + + Themes + + Lists whitelabel themes + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + theme [theme-uid] + + The theme settings returned can be use as a way to create the theme. + You can use jq to retrieve the theme settings by piping the output to jq, e.g. + + node wmiocli.js -d env -u user -p pass theme fl40018d9a1a273bb8aa92bf | jq -c .output.settings.theme > ~/dracula-theme.txt + + Deletes a whitelabel theme + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + theme-delete [theme-uid] + + Creates a new whitelabel theme + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + theme-create dracula 'desc' [theme-settings] "Footer Text" "About Page" + + Theme settings can be used from the list example above, e.g. + node wmiocli.js -d env -u user -p pass theme-create dracula7 'updated' "`cat ~/dracula-theme.txt`" 'Footer' 'About' + + Updates a whitelabel theme + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + theme-update themeid dracula 'desc' [theme-settings] "Footer Text" "About Page" + + Theme settings can be used from the list example above, e.g. + node wmiocli.js -d env -u user -p pass theme-update themeid dracula7 'updated' "`cat ~/dracula-theme.txt`" 'Footer' 'About' + + Activates a whitelabel theme + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + theme-activate [theme-uid] + + Deactivates a whitelabel theme + $ node wmiocli.js + -d tenant.int-aws-us.webmethods.io + -u user + -p password + theme-deactivate [theme-uid] + ``` diff --git a/debug.js b/debug.js index b397579..60d1972 100644 --- a/debug.js +++ b/debug.js @@ -4,16 +4,88 @@ * Apache-2.0 */ -var debug = false; + +const white = "\x1b[37m"; +const Dim = "\x1b[2m"; +const Reset = "\x1b[0m"; +const Green = "\x1b[32m"; +const Red = "\x1b[31m"; +const Cyan = "\x1b[36m"; +const Yellow = "\x1b[33m" + + +const lvl_permanent = -1; +const lvl_off = 0; +const lvl_error = 1; +const lvl_warning = 2; +const lvl_info = 3; +const lvl_debug = 4; + + +var defaultLevel = 0; +activeLevel = 0; + +const prefix =""; + function enableDebug(){ - debug = true; - } + // console.log(Yellow + "ENABLED DEBUG" + Reset ); + setLogLevel(lvl_debug); +} + +function setLogLevel(inLevel){ + + activeLevel = inLevel; + // console.log(Yellow + "SETTING ACTIVE LEVEL TO: " + inLevel ); + // console.log(Yellow + "SETTING: " + activeLevel ); +} -function message(inMessage) +function message(inMessage,level) { - if(debug==true){ - console.log("." + inMessage); + + // console.log(Green + "DEBUG Level:" + level + Reset ); + var message = inMessage; + if(level==undefined)level = 4; + if(level==lvl_permanent)console.log(message); + else + { + // console.log(Green + "Using Level:" + level + Reset ); + // console.log(Green + "Defau Level:" + defaultLevel + Reset ); + + + if(level>activeLevel)return; + switch (level) + { + case lvl_off: + //Nothing to do + break; + + case lvl_debug: + message = Dim + "DEBUG:" + prefix +":"+ inMessage + Reset; + console.log(message); + break; + + case lvl_info: + message = white + "INFO:" + prefix +":"+ inMessage + Reset; + console.log(message); + break; + + case lvl_warning: + message = Yellow + "WARN:" + prefix +":"+ inMessage + Reset; + console.log(message); + break; + + case lvl_error: + message = Red + "ERROR:" + prefix + inMessage + Reset; + console.log(message); + break; + } + } + + + + } -module.exports = { enableDebug, message }; + +module.exports = { enableDebug, message, setLogLevel }; diff --git a/experimental.js b/experimental.js new file mode 100644 index 0000000..38bfc8e --- /dev/null +++ b/experimental.js @@ -0,0 +1,830 @@ +/* + * webMethods.io CLI + * Copyright 2022 Software AG + * Apache-2.0 + */ + +// ------------------------------------------------------------------------------ +// PLEASE NOTE - These functions are provided by NON public APIs, and +// therefore unsupported - use these at your own risk! +// ------------------------------------------------------------------------------ + +const request = require("request"); +const rest = require("./rest.js"); + + + +var domainName, username,password,timeout; +var prettyprint = false; +var url; + +var authtoken=""; +var uid=""; +var csrf=""; +var projectId; +var workflowId; +var projectName ; +var executionStatus; +var startDate; +var endDate; +var startOrResume; +var queueOrTopic; +var messagingName; +var nextUrl,formUrl; +var finalCall; +var loginStageCounter = 0; +const maxRunningWorkflows = 20; + + +function debug(message){ + dbg.message(" " + message,4); +} + +function init(inDomainName, inUsername, inPassword,inTimeout,inPrettyprint){ + + dbg.message("EXPERIMENTAL/UNSUPPORTED APIs - USE THESE AT YOUR OWN RISK",4); + domainName = inDomainName; + username = inUsername; + password = inPassword; + timeout = inTimeout; + prettyprint = inPrettyprint; + url = "https://" + domainName; + dbg.message("Username [" + username + "]",4); + dbg.message("URL [" + url + "]",4); + dbg.message("Timeout [" + timeout + "]",4); +} + +function user() +{ + finalCall = execUserInfo; + loginPhase1(); +} + +function stages() +{ + finalCall = stageInfo; + loginPhase1(); +} + +function projectWorkflows(inProjectId) +{ + projectId = inProjectId; + finalCall = projectWorkflowsInfo; + loginPhase1(); +} + +function projectFlowservices(inProjectId) +{ + projectId = inProjectId; + finalCall = projectFlowServicesInfo; + loginPhase1(); +} + +function connectorAccounts(inProjectId) +{ + projectId = inProjectId; + finalCall = usedConnectorAccountsInfo; + loginPhase1(); +} + +function getProjectAccountConfig(inProjectId) +{ + projectId = inProjectId; + finalCall = getProjectAccountConfigInfo; + loginPhase1(); +} + +function projectDeployments(inProjectId) +{ + dbg.message("Listing project deployments for projectId [" + inProjectId + "]",4); + projectId = inProjectId; + finalCall = getProjectDeployments; + loginPhase1(); +} + +function searchProject(inProjectName) +{ + projectName = inProjectName; + finalCall = searchProjectsByName; + loginPhase1(); +} + +function getMonitorInfo(inExecutionStatus,inStartDate,inEndDate,inProjectId,inWorkflowId) +{ + projectId = inProjectId; + workflowId = inWorkflowId; + executionStatus = inExecutionStatus; + startDate = inStartDate; + endDate = inEndDate; + finalCall = getLogs; + loginPhase1(); +} + +function messagingDelete(inQueueOrTopic, inProjectId,inMessagingName) +{ + projectId = inProjectId; + messagingName = inMessagingName; + queueOrTopic = inQueueOrTopic; + finalCall = doMessagingDelete; + loginPhase1(); +} + +function messagingCreate(inQueueOrTopic, inProjectId,inMessagingName) +{ + projectId = inProjectId; + messagingName = inMessagingName; + queueOrTopic = inQueueOrTopic; + finalCall = doMessagingCreate; + loginPhase1(); +} + +function messagingStats(inProjectId,inMessagingName) +{ + projectId = inProjectId; + messagingName = inMessagingName; + finalCall = getMessagingStats; + loginPhase1(); +} + + +function workflowResubmit(instartOrResume, inStartDate,inEndDate, inProjectId,inWorkflowId) +{ + projectId = inProjectId; + workflowId = inWorkflowId; + startDate = inStartDate; + endDate = inEndDate; + startOrResume = instartOrResume; + finalCall = checkResubmissions; + loginPhase1(); +} + +function debugMonitorInfo() +{ + debug("Monitor Project: [" + projectName + "]"); + debug("Monitor workflowId: [" + workflowId + "]"); + debug("Monitor executionStatus: [" + executionStatus + "]"); + debug("Monitor startDate: [" + startDate + "]"); + debug("Monitor endDate: [" + endDate + "]"); +} + +function processMonitorBody() +{ + var body={}; + + if(endDate)body.end_date = endDate; + if(startDate)body.start_date = startDate; + else + { + startDate = new Date(); + startDate.setHours(0); + startDate.setMinutes(0); + startDate.setSeconds(0); + startDate.setMilliseconds(0); + + if(!endDate) + { + endDate = new Date; + endDate.setHours(23); + endDate.setMinutes(59); + endDate.setSeconds(59); + endDate.setMilliseconds(999); + } + body.start_date=startDate; + body.end_date=endDate; + } + + if(projectId)body.projects=[projectId] + if(workflowId)body.workflows = [workflowId]; + if(executionStatus)body.execution_status = [executionStatus]; + body.skip=0; + body.limit=20; + return body; +} + +function setHeaders() +{ + var headers = [ + {name:"authtoken",value:authtoken}, + {name:"accept",value:"application/json"}, + {name:"x-csrf-token",value:csrf}, + ]; + return headers; +} + +function checkResubmissions() +{ + debug("Check Resubmissions") + debugMonitorInfo(); + //Check running + var endPoint = "https://" + domainName + "/enterprise/v1/metrics/workflowexecutions/logs"; + debug("Next URL [" + endPoint + "]"); + var body=processMonitorBody(); + body.execution_status=["running"]; + var headers = setHeaders(); + rest.custom(endPoint,undefined,undefined,timeout,body,undefined,"POST",processRunningResponse,undefined,headers,true,false); +} + +function processResubmissions(reprocessCount) +{ + debug("Process Resubmissions") + debugMonitorInfo(); + //Check running + var endPoint = "https://" + domainName + "/enterprise/v1/metrics/workflowexecutions/logs"; + debug("Next URL [" + endPoint + "]"); + var body=processMonitorBody(); + body.limit=reprocessCount; + body.execution_status=["failed"]; + var headers = setHeaders(); + rest.custom(endPoint,undefined,undefined,timeout,body,undefined,"POST",processListResponse,undefined,headers,true,false); +} + +function processSingleResubmission(a,b, vbid) +{ + dbg.message("Processing Resubmission [" + a + " of " + b + "] Action [" + startOrResume + "] VBID [" + vbid + "]",); + var endPoint = "https://cpointegrationdev.int-aws-de.webmethods.io/enterprise/v1/tenant/account/billlogs/" + vbid; + debug("Next URL [" + endPoint + "]"); + //var body=processMonitorBody(); + //body.limit=reprocessCount; + //body.execution_status=["failed"]; + var headers = setHeaders(); + rest.custom(endPoint,undefined,undefined,timeout,undefined,undefined,"GET",processSingleResubmissionResponse,undefined,headers,true,false); +} + +function finishProcessSingleResubmission(vbid,wfuid,payloaduid,projectuid,flowname,stoptime) +{ + dbg.message("Actioning Resubmission Action [" + startOrResume + "] VBID [" + vbid + "]",3); + var endPoint = "https://" + domainName + "/enterprise/v1/execute/" + wfuid + "/resume" + debug("Next URL [" + endPoint + "]"); + //var body=processMonitorBody(); + //body.limit=reprocessCount; + //body.execution_status=["failed"]; + var headers = [ + {name:"authtoken",value:authtoken}, + {name:"accept",value:"application/json"}, + {name:"x-csrf-token",value:csrf}, + {name:"project_uid",value:projectuid}, + ]; + var body = {"bill_uid":vbid,"__is_checkpoint_run__":true,"payload_uid":payloaduid,"checkpointLogs":[]}; + rest.custom(endPoint,undefined,undefined,timeout,body,undefined,"POST",processFinalSingleResubmissionResponse,undefined,headers,true,false); +} + +function processFinalSingleResubmissionResponse(url,err,body,res){ + if(res.statusCode==200) + { + dbg.message("Processed",3); + } + else + { + dbg.message("Failed to Resubmit entry",1) + dbg.message(body,1); + process.exit(99); + } +} + +function processSingleResubmissionResponse(url,err,body,res){ + if(res.statusCode==200) + { + if(body.output.uid) + { + dbg.message("Found Monitor Entry",3); + dbg.message("VBID [" + body.output.uid + "]",4); + dbg.message("Flow UID [" + body.output.flow_uid + "]",4); + dbg.message("Payload UID [" + body.output.payload_uid + "]",4); + dbg.message("Project_UID [" + body.output.project_uid + "]",4); + dbg.message("Flow Name [" + body.output.flow_name + "]",4); + dbg.message("Stop time [" + body.output.stop_time + "]",4); + finishProcessSingleResubmission(body.output.uid,body.output.flow_uid,body.output.payload_uid,body.output.project_uid,body.output.flow_name,body.output.stop_time); + } + else{ + + dbg.message("Not able to find monitor entry",1); + } + } + else + { + dbg.message("Failed to get Monitor entry",1) + dbg.message(body,1); + process.exit(99); + } +} + +function processRunningResponse(url,err,body,res){ + if(res.statusCode==200) + { + //... do something next + if(body.output.count==0) + { + dbg.message("No Workflows Running",4) + dbg.message("Can Resubmit [" + (maxRunningWorkflows - body.output.count) + "] executions",4); + } + else{ + dbg.message("Workflows Running [" +body.output.count + "]",2) + if(body.output.count