Scripting with ICM
As of release 2023.3 of InterSystems IRIS, InterSystems Cloud Manager (ICM) is deprecated; it will be removed from future versions.
This page describes how to issue a series of ICM commands from a script and how to identify and coordinate containers and services across a deployment.
ICM Exit Status
ICM sets the UNIX exit status after each command, providing a simple way to determine whether a given ICM command succeeded. The following examples examine the special variable $? after each command:
# icm inventory
Machine IP Address DNS Name Region Zone
------- ---------- -------- ------ ----
Acme-DATA-TEST-0001 54.191.233.2 ec2-54-191-233-2.amazonaws.com us-east1 b
Acme-DATA-TEST-0002 54.202.223.57 ec2-54-202-223-57.amazonaws.com us-east1 b
Acme-DATA-TEST-0003 54.202.223.58 ec2-54-202-223-58.amazonaws.com us-east1 b
# echo $?
0
# icm publish
Unrecognized goal: 'publish' (try "icm -help")
# echo $?
1
# icm ps -role QM
Unrecognized role 'QM'
# echo $?
1
# icm session
Error: Interactive commands cannot match more than one instance
# echo $?
1
ICM Logging
ICM logs its output to a file (default icm.log) and to the console. Whereas all output is sent to the log file, its console output can be captured and split into stdout and stderr. The following example completes without error:
# icm inventory > std.out 2> std.err
# cat std.out
Machine IP Address DNS Name Region Zone
------- ---------- -------- ------ ----
Acme-DATA-TEST-0001 54.191.233.2 ec2-54-191-233-2.amazonaws.com us-east1 b
Acme-DATA-TEST-0002 54.202.223.57 ec2-54-202-223-57.amazonaws.com us-east1 b
Acme-DATA-TEST-0003 54.202.223.58 ec2-54-202-223-58.amazonaws.com us-east1 b
# cat std.err
The following example contains error output:
# icm publish > std.out 2> std.err
# cat std.out
# cat std.err
Unrecognized goal: 'publish' (try "icm -help")
Remote Script Invocation
Commands can be used in combination to copy scripts to a host or container and remotely invoke them. The following example copies an exported InterSystems IRIS routine into an InterSystems IRIS cluster, then compiles and runs it:
# icm scp -localPath Routine1.xml -remotePath /tmp/
# icm session -command 'Do ##class(%SYSTEM.OBJ).Load("/tmp/Routine1.xml", "c-d")'
# icm session -command 'Do ^Routine1'
This example copies a shell script to the host, changes its permissions, and executes it:
# icm scp -localPath script1.sh -remotePath /tmp/
# icm ssh -command 'sudo chmod a+x /tmp/script1.sh'
# icm ssh -command '/tmp/script1.sh abc 123'
This example does the same thing, but within a custom or third-party container:
# icm cp -localPath script2.sh -remotePath /tmp/ -container gracie
# icm exec -command 'chmod a+x /tmp/script2.sh' -container gracie
# icm exec -command '/tmp/script2.sh abc 123' -container gracie
Using JSON Mode
Your script may need to gather information from ICM about the state of the cluster. Examples would be:
-
What is the IP address of the InterSystems IRIS data server?
-
What is the status of my custom/third-party container?
Parsing the human-readable output of ICM is difficult and prone to breakage. A more reliable solution is to have ICM generate its output in JSON format using the json option. The output is written to a file named response.json in the current working directory.
Normal Output
Most ICM commands do not result in any output upon success, in which case the exit value will be 0, no output will be written to stderr, and the JSON will be the empty array:
# icm exec -command "ls /" -json
# cat response.json
[]
ICM commands that produce useful output on success are detailed in the following. Note that the order of fields is not guaranteed.
icm provision
The format of the icm provision output is an object containing name-value pairs which describe the input (that is, configuration) and output (that is, state) files used during provisioning. The names, which match their corresponding command-line argument, are defaults, definitions, instances, and stateDir, as shown in this example:
# icm provision -json
...
Machine IP Address DNS Name Region Zone
------- ---------- -------- ------ ----
Acme-DATA-TEST-0001 54.191.233.2 ec2-54-191-233-2.amazonaws.com us-east1 b
Acme-DATA-TEST-0002 54.202.223.57 ec2-54-202-223-57.amazonaws.com us-east1 b
Acme-DATA-TEST-0003 54.202.223.58 ec2-54-202-223-58.amazonaws.com us-east1 b
To destroy: icm unprovision [-cleanUp] [-force]
# cat response.json
{
"defaults" : "defaults.json",
"definitions" : "definitions.json",
"instances" : "instances.json",
"stateDir" : "/Samples/AWS/state/"
}
icm inventory
The format of the icm inventory command is an array whose elements correspond to each provisioned instance; each element in turn contains a list of the name-value pairs MachineName, Role, IPAddress, and DNSName, as shown in the following:
# icm inventory -json
Machine IP Address DNS Name Region Zone
------- ---------- -------- ------ ----
Acme-DATA-TEST-0001 54.191.233.2 ec2-54-191-233-2.amazonaws.com us-east1 b
Acme-DATA-TEST-0002 54.202.223.57 ec2-54-202-223-57.amazonaws.com us-east1 b
Acme-DATA-TEST-0003 54.202.223.58 ec2-54-202-223-58.amazonaws.com us-east1 b
# cat response.json
[
{
“Provider”: “AWS”,
"MachineName":"Acme-DATA-TEST-0001",
"Role":"DATA",
"IPAddress":"54.191.233.2",
"DNSName":"54_191_233_2.amazonaws.com",
“Region”: “us-east-1”,
“Zone”: “us-east-1b”
},
{
“Provider”: “AWS”,
"MachineName ":"Acme-DATA-TEST-0002",
"Role":"DATA",
"IPAddress":"54.202.223.57",
"DNSName":"54_202_223_57.amazonaws.com,
“Region”: “us-east-1”,
“Zone”: “us-east-1b”"
},
{
“Provider”: “AWS”,
"MachineName":"Acme-DATA-TEST-0003",
"Role":"DATA",
"IPAddress":"54202.223.58",
"DNSName":"54_202_223_58.amazonaws.com,
“Region”: “us-east-1”,
“Zone”: “us-east-1b”"
}
]
icm ps
In container mode, the output of the icm ps command is an array whose elements correspond to each container; each element in turn is a list of the name-value pairs MachineName, Role, IPAddress, DNSName, Container, DockerImage, Status, and MirrorStatus (if applicable):
# icm ps -container iris -json
Machine IP Address Container Status Health Image
------- ---------- --------- ------ ----- -----
Acme-DATA-TEST-0001 54.191.233.2 iris Up healthy isc/iris:latest-em
Acme-DATA-TEST-0002 54.202.223.57 iris Up healthy isc/iris:latest-em
Acme-DATA-TEST-0003 54.202.223.58 iris Up healthy isc/iris:latest-em
# cat response.json
[
{
"MachineName":"Acme-DATA-TEST-0001",
"Role":"DATA",
"IPAddress":"54.191.233.2",
"DNSName":"54_191_233_2.amazonaws.com"
"Container":"iris",
"DockerImage":"isc/iris:latest-em",
"Status":"Up",
"Health":"healthy"
},
{
"MachineName ":"Acme-DATA-TEST-0002",
"Role":"DATA",
"IPAddress":"54.202.223.57",
"DNSName":"54_202_223_57.amazonaws.com"
"Container":"iris",
"DockerImage":"isc/iris:latest-em",
"Status":"Up"",
"Health":"healthy"
},
{
"MachineName ":"Acme-DATA-TEST-0003",
"Role":"DATA",
"IPAddress":"54.202.223.57",
"DNSName":"54_202_223_57.amazonaws.com"
"Container":"iris",
"DockerImage":"isc/iris:latest-em",
"Status":"Up",
"Health":"healthy"
},
]
The icm ps output fields in containerless mode are MachineName, Role, IPAddress, DNSName, ISCInstance (always IRIS in a container provided by InterSystems), Kit, Status, and MirrorStatus (if applicable):
# icm ps -json
Machine IP Address Instance Kit Status Health
------- ---------- -------- --- ------ ------
Acme-DATA-TEST-0001 54.67.2.117 IRIS 2017.3.0.392.0 running ok
Acme-DATA-TEST-0002 54.153.96.236 IRIS 2017.3.0.392.0 running ok
Acme-DATA-TEST-0002 54.153.90.66 IRIS 2017.3.0.392.0 running ok
# cat response.json
[
{
"MachineName":"Acme-DATA-TEST-0001",
"Role":"DATA",
"IPAddress":"54.191.233.2",
"DNSName":"54_191_233_2.amazonaws.com"
"ISCInstance":"IRIS",
"Kit":"2017.3.0.392.0",
"Status":"running",
"Health":"ok"
},
{
"MachineName ":"Acme-DATA-TEST-0002",
"Role":"DATA",
"IPAddress":"54.202.223.57",
"DNSName":"54_202_223_57.amazonaws.com"
"ISCInstance":"IRIS",
"Kit":"2017.3.0.392.0",
"Status":"running"",
"Health":"ok"
},
{
"MachineName ":"Acme-DATA-TEST-0003",
"Role":"DATA",
"IPAddress":"54.202.223.57",
"DNSName":"54_202_223_57.amazonaws.com"
"ISCInstance":"IRIS",
"Kit":"2017.3.0.392.0",
"Status":"running"",
"Health":"ok"
}
]
Abnormal Output
When an error occurs, the format of the JSON output depends on whether the error occurred local to the ICM application or was from a target application on the host or instance.
Local Errors
When an ICM command results in an error, the JSON will contain an object and a name-value pair describing the error, as follows:
# icm ps -role QM -json
Unrecognized role 'QM'
# cat response.json
{
"error": "Unrecognized role 'QM'"
}
Remote Errors
A remote error is considered to have occurred when one or more of the following is true:
-
Non-zero exit status
-
Output to stderr
When a remote error occurs, the JSON will be an array of objects containing name-value pairs; the name corresponds to that of the target machine, and the value is another object containing a list of name-value pairs including one or more of the following:
-
error: A description of the problem that occurred; most of the text of an exception
-
file: A file containing more detail about the problem
-
exitValue: The (non-zero) exit value of an underlying process
Here is an example:
# icm ssh -command "ls file.txt" -json
Executing command 'ls file.txt' on host Acme-DATA-TEST-0001...
ls: cannot access file.txt: No such file or directory
Error: See tmp/DATA-TEST/DATA-TEST-0001/ssh.err
Errors occurred during execution; aborting operation
# cat response.json
[
{
"Acme-DATA-TEST-0001": {
"file": "tmp/DATA-TEST/DATA-TEST-0001/ssh.err"
}
}
]
# cat tmp/DATA-TEST/DATA-TEST-0001/ssh.err
ls: cannot access file.txt: No such file or directory