Cutover API
>
Integrations
>
Executing command line scripts with Cutover and Cutover Connect

Executing command line scripts with Cutover and Cutover Connect

Cutover can help you execute command line scripts securely from your Cutover runbook. We do this by sending secure messages to our dedicated on-premise application that you host called Cutover Connect (see note below). Cutover Connect reads messages from the appropriate tasks in your Cutover runbook; when Connect sees the appropriate message, it executes your allowlist command line script.

Once the script has executed, a response is sent back to your Cutover task securely via Cutover Connect. The output from your command line script must conform to Cutover Connect’s Command Line API (see the 'Cutover Connect Command Line API' section below).

Note: Cutover Connect is an on-premise Java application which provides secure connectivity between the Cutover SaaS platform and your existing in-house applications such as Ansible Tower, Jenkins and command line scripts. For more information about Cutover Connect, please speak to your Customer Success Manager (CSM).

Setup and configuration

The integration required to execute your scripts will be set up and configured by Cutover. We will work with you to configure your allowlist of scripts that Cutover Connect can execute. See the 'Configuring Cutover Connect' section below for details on how to set up your allowlist.

If the command line scripts have parameters, custom fields can be set up as part of the command line task to enable users to select these values when interacting with the runbook. The custom fields will be configured by us.

Cutover Connect Command Line API

Your command line script must accept at least one command line argument named CutoverTransformKey. The CutoverTransformKey value is used to track an integration request between Cutover and your systems. See the 'Sample Python script' section below for an example starter script.

Your script must respond with a single JSON object:

{
    "cutoverTransformKey": "e251cfa42265e9c7d4efe383e1f922", // REQUIRED
    "status": "Failed", // REQUIRED: Failed | Success | Running,
    "params": { // OPTIONAL 
        "Comments": "Internal process has failed, please contact help devops@mybank.com",
        "Description": "Proxy failure"
    }
}
  
Copy to clipboard

You can add any key-value pairs into the params object. The status is a required value. If the script has completed successfully, it will return a Success status. If there has been a problem, it will return a Failed status. If the script has begun execution of a long-running process, it will return a Running status.

Wrapper script

If you have a large number of scripts to run to accomplish a particular goal, we recommend that you create a wrapper script to perform the series of steps in a controlled way. Cutover Connect’s allowlist can then be configured to execute your wrapper script. See the 'Sample Python script' section below for an example starter script.

Starting the script execution

These are the steps to execute a script:

1. Start the Cutover task.
2. A message is sent securely and received by Cutover Connect (hosted in your environment).
3. Cutover Connect executes the script and receives a response from the process it started (the status is 'running').
4. A 'running' status is returned as part of the response sent back to the task in the Cutover runbook that initiated the script execution.

Note: If you are executing a call to an HTTP endpoint from your script, we require the full response you get from that call returned to us.

For example, if you are executing a request to start a Rundeck integration build, the response you get back in your script will look something like this:

{
    "id": 202,
    "href": "https://rundeck.myinstance/api/41/execution/202",
    "permalink": "https://rundeck.myinstance/project/Run_5minutes/execution/show/202",
    "status": "running",
    "project": "Run_5minutes",
    "executionType": "user",
    "user": "admin",
    "date-started":
    {
        "unixtime": 1671101202632,
        "date": "2022-12-15T10:46:42Z"
    },
    "job":
    {
        "id": "3ac2c456-dea7-4a9e-9692-92653acedf52",
        "averageDuration": 300352,
        "name": "job_5minutes",
        "group": "",
        "project": "Run_5minutes",
        "description": "",
        "href": "https://rundeck.myinstance/api/41/job/3ac2c456-dea7-4a9e-9692-92653acedf52",
        "permalink": "https://rundeck.myinstance/project/Run_5minutes/job/show/3ac2c456-dea7-4a9e-9692-92653acedf52"
    },
    "description": "sleep 300",
    "argstring": null,
    "serverUUID": "1425d02b-30da-43e3-9089-b1316b54ebc7"
}
  
Copy to clipboard

Place that JSON response in the Cutover Connect Command Line API response:

response = {
    "cutoverTransformKey": callback_url,
    "Status": status, # REQUIRED: Failed | Success | Running
    "Params":
        {
            "RundeckResponse": resp_body
        }
}

  
Copy to clipboard

Printing out the above response is the final action the script performs. Remember that this script has been executed in a thread started by Cutover Connect. Cutover Connect needs valid JSON returned in order to send this response back to Cutover once the script has finished executing.

Checking the status of a running process

At this point, you will want to check periodically on the status of the process you've started, be it a Jenkins job, a Rundeck project, or, indeed, whatever process your script has started.

Cutover can handle the polling for you. The Cutover task that started off the script execution can send requests to get the status, once it receives confirmation that the process has started.

Alternative to checking the status of a running process

There may be occasions when you are calling a script that may take a long time to execute, and you want to control when updates about this script execution's status are sent back to Cutover.

For example, you may want to execute a remote script in your network via Secure Shell Protocol (SSH), which could be a very long running job. 

In this case, you should look to have the wrapper script return a 'Running' status response, and then end the script execution thread in Cutover Connect. Once the thread has ended, this 'Running' status will be returned to the task in Cutover.

At a later time, Cutover Connect will perform a 'Poll Script' execution which will result in either 'Running' because the remote execution script has not yet returned a response to your shell script, or 'Success/Failed' because it has already returned either of those statuses.

To support this, your shell script(s) will need a way of assigning a CutoverTransformKey to a particular running shell execution script.

Configuring Cutover Connect

To use command line scripts with Cutover Connect, you must configure an allowlist of script aliases in your application.properties file. Each script alias refers to the actual command Cutover Connect is expected to execute, along with any arguments.

In the example below, there are two entries - one to start a script execution, and another script to check on the status.

# Command line apps to execute. No trailing commas!
connect.integration.scriptExecutor.commands={ \
  'allowed_script_alias':'./scripts/wrapper_script.sh [__CRQID__] [__UserId__]
[__HostName__] [__CutoverTransformKey__] ' , \
  'uat_generate_user':'python3 [__UserId__] [__HostName__]
[__CutoverTransformKey__]' \
}
  
Copy to clipboard

Your command must accept the CutoverTransformKey (string) parameter and return the same CutoverTransformKey value in response.

The alias (for example allowed_script_alias uat_generate_user) will be supplied as part of the message read by Cutover Connect.

Note: Only script aliases in the allowlist will be executed by Cutover Connect.

If a message read by Cutover Connect does not match up with any aliases defined in the application.properties file, then an error message will be displayed to the user in their web browser.

Encoding the script

For added security, Cutover Connect by default will encode the full command it needs to execute. Taking the example above, if [__HostName__] contains a full path such as:

/londona-e45try9/rhel9/vm-xyz123

Then this will be encoded and passed to the script as:

%2Flondona-e45try9%2Frhel9%2Fvm-xyz123

You can either decode this in your wrapper script, or you can switch off encoding in Cutover Connect by adding this setting to the application.properties file:

connect.integration.scriptExecutor.disableUriEncoding = true

Sample Python script

This sample Python script is compatible with the Cutover Connect Command Line API.

#!usr/bin/env python
import sys
import datetime
import os
import json
# import ansible.runner

import sys;print(sys.version)

print("Do what the script needs to do here script \r\n")
# do whatever your script needs to do here
# eg run another script, add in functionality directly here
# depending on the result of the script return a status code
print("Processing request for CutoverTransformKey: \r\n")
# Do step 1
# Do step 2
# Collect responses

# Respond back to Cutover Connect
response = {
    "CutoverTransformKey": "5kef77eWqR69ab0e6248b0c26d0146",
    "Status": "Success",
    "Params":
    {
        "comment": "Success - 1 row created.",
        "cutover_custom_field1": "some value",
        "cutover_custom_field2": "another value"
    }
}   

print(json.dumps(response))
  
Copy to clipboard

Thank you for using our integration. If you have any feedback or suggestions for improving this documentation, please send it to docs@cutover.com.