
# Control-M enterprise manager by HTTP

## Overview

The template to monitor Control-M by Zabbix that work without any external scripts.


## Requirements

Zabbix version: 7.0 and higher.

## Tested versions

This template has been tested on:
- Control-M 9.21.0

## Configuration

> Zabbix should be configured according to the instructions in the [Templates out of the box](https://www.zabbix.com/documentation/7.0/manual/config/templates_out_of_the_box) section.

## Setup

This template is intended to be used on Control-M Enterprise Manager instances. 

It monitors:
* active SLA services;
* discovers Control-M servers using Low Level Discovery;
* creates host prototypes for discovered servers with the `Control-M server by HTTP` template.

To use this template, you must set macros: **{$API.TOKEN}** and **{$API.URI.ENDPOINT}**. 

To access the API token, use one of the following Control-M interfaces:

> [Control-M WEB user interface](https://documents.bmc.com/supportu/controlm-saas/en-US/Documentation/Creating_an_API_Token.htm);

> [Control-M command line interface tool CTM](https://docs.bmc.com/docs/saas-api/authentication-service-941879068.html).

`{$API.URI.ENDPOINT}` - is the Control-M Automation API endpoint for the API requests, including your server IP, or DNS address, Automation API port and path.

For example, `https://monitored.controlm.instance:8443/automation-api`.

### Macros used

|Name|Description|Default|
|----|-----------|-------|
|{$API.URI.ENDPOINT}|
The API endpoint is a URI - for example, `https://monitored.controlm.instance:8443/automation-api`.
|`<set the api uri endpoint here>`|
|{$API.TOKEN}|
A token to use for API connections.
|`<set the token here>`|

### Items

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Get Control-M servers|
Gets a list of servers.
|HTTP agent|controlm.servers|
|Get SLA services|
Gets all the SLA active services.
|HTTP agent|controlm.services|

### LLD rule Server discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Server discovery|
Discovers the Control-M servers.
|Dependent item|controlm.server.discovery
**Preprocessing**

- 
Discard unchanged with heartbeat: `2h`

|

### LLD rule SLA services discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|SLA services discovery|
Discovers the SLA services in the Control-M environment.
|Dependent item|controlm.services.discovery
**Preprocessing**

- 
JSON Path: `$.activeServices`

⛔️Custom on fail: Set value to: `[]`

- 
Discard unchanged with heartbeat: `1h`

|

### Item prototypes for SLA services discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: stats|
Gets the service statistics.
|Dependent item|service.stats['{#SERVICE.NAME}','{#SERVICE.JOB}']
**Preprocessing**

- 
JSON Path: `$.activeServices.[?(@.serviceName == '{#SERVICE.NAME}')]`

⛔️Custom on fail: Discard value

- 
JSON Path: `$.[?(@.serviceJob == '{#SERVICE.JOB}')].first()`

⛔️Custom on fail: Discard value

|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: status|
Gets the service status.
|Dependent item|service.status['{#SERVICE.NAME}','{#SERVICE.JOB}']
**Preprocessing**

- 
JSON Path: `$.status`

- 
JavaScript: `The text is too long. Please see the template.`

- 
Discard unchanged with heartbeat: `1h`

|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: jobs 'executed'|
Gets the number of jobs in the state - `executed`.
|Dependent item|service.jobs.status['{#SERVICE.NAME}','{#SERVICE.JOB}',executed]
**Preprocessing**

- 
JSON Path: `$.statusByJobs.executed`

- 
Discard unchanged with heartbeat: `1h`

|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: jobs 'waitCondition'|
Gets the number of jobs in the state - `waitCondition`.
|Dependent item|service.jobs.status['{#SERVICE.NAME}','{#SERVICE.JOB}',waitCondition]
**Preprocessing**

- 
JSON Path: `$.statusByJobs.waitCondition`

- 
Discard unchanged with heartbeat: `1h`

|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: jobs 'waitResource'|
Gets the number of jobs in the state - `waitResource`.
|Dependent item|service.jobs.status['{#SERVICE.NAME}','{#SERVICE.JOB}',waitResource]
**Preprocessing**

- 
JSON Path: `$.statusByJobs.waitResource`

- 
Discard unchanged with heartbeat: `1h`

|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: jobs 'waitHost'|
Gets the number of jobs in the state - `waitHost`.
|Dependent item|service.jobs.status['{#SERVICE.NAME}','{#SERVICE.JOB}',waitHost]
**Preprocessing**

- 
JSON Path: `$.statusByJobs.waitHost`

- 
Discard unchanged with heartbeat: `1h`

|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: jobs 'waitWorkload'|
Gets the number of jobs in the state - `waitWorkload`.
|Dependent item|service.jobs.status['{#SERVICE.NAME}','{#SERVICE.JOB}',waitWorkload]
**Preprocessing**

- 
JSON Path: `$.statusByJobs.waitWorkload`

- 
Discard unchanged with heartbeat: `1h`

|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: jobs 'completed'|
Gets the number of jobs in the state - `completed`.
|Dependent item|service.jobs.status['{#SERVICE.NAME}','{#SERVICE.JOB}',completed]
**Preprocessing**

- 
JSON Path: `$.statusByJobs.completed`

- 
Discard unchanged with heartbeat: `1h`

|
|Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: jobs 'error'|
Gets the number of jobs in the state - `error`.
|Dependent item|service.jobs.status['{#SERVICE.NAME}','{#SERVICE.JOB}',error]
**Preprocessing**

- 
JSON Path: `$.statusByJobs.error`

- 
Discard unchanged with heartbeat: `1h`

|

### Trigger prototypes for SLA services discovery

|Name|Description|Expression|Severity|Dependencies and additional info|
|----|-----------|----------|--------|--------------------------------|
|Control-M: Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: status [{ITEM.VALUE}]|
The service has encountered an issue.
|`last(/Control-M enterprise manager by HTTP/service.status['{#SERVICE.NAME}','{#SERVICE.JOB}'],#1)=0 or last(/Control-M enterprise manager by HTTP/service.status['{#SERVICE.NAME}','{#SERVICE.JOB}'],#1)=10`|Average|**Manual close**: Yes|
|Control-M: Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: status [{ITEM.VALUE}]|
The service has finished its job late.
|`last(/Control-M enterprise manager by HTTP/service.status['{#SERVICE.NAME}','{#SERVICE.JOB}'],#1)=3`|Warning|**Manual close**: Yes|
|Control-M: Service [{#SERVICE.NAME}, {#SERVICE.JOB}]: jobs in 'error' state|
There are services present which are in the state - `error`.
|`last(/Control-M enterprise manager by HTTP/service.jobs.status['{#SERVICE.NAME}','{#SERVICE.JOB}',error],#1)>0`|Average||

# Control-M server by HTTP

## Overview

This template is designed to get metrics from the Control-M server using the Control-M Automation API with HTTP agent.

This template monitors server statistics, discovers jobs and agents using Low Level Discovery.

To use this template, macros {$API.TOKEN}, {$API.URI.ENDPOINT}, and {$SERVER.NAME} need to be set.


## Requirements

Zabbix version: 7.0 and higher.

## Tested versions

This template has been tested on:
- Control-M 9.21.0

## Configuration

> Zabbix should be configured according to the instructions in the [Templates out of the box](https://www.zabbix.com/documentation/7.0/manual/config/templates_out_of_the_box) section.

## Setup

This template is primarily intended for using in conjunction with the `Control-M enterprise manager by HTTP` template in order to create host prototypes.

It monitors:
* server statistics;
* discovers jobs using Low Level Discovery;
* discovers agents using Low Level Discovery.

However, if you wish to monitor the Control-M server separately with this template, you must set the following macros: **{$API.TOKEN}**, **{$API.URI.ENDPOINT}**, and **{$SERVER.NAME}**. 

To access the `{$API.TOKEN}` macro, use one of the following interfaces:

> [Control-M WEB user interface](https://documents.bmc.com/supportu/controlm-saas/en-US/Documentation/Creating_an_API_Token.htm);

> [Control-M command line interface tool CTM](https://docs.bmc.com/docs/saas-api/authentication-service-941879068.html).

`{$API.URI.ENDPOINT}` - is the Control-M Automation API endpoint for the API requests, including your server IP, or DNS address, the Automation API port and path.

For example, `https://monitored.controlm.instance:8443/automation-api`.

`{$SERVER.NAME}` - is the name of the Control-M server to be monitored.

### Macros used

|Name|Description|Default|
|----|-----------|-------|
|{$SERVER.NAME}|
The name of the Control-M server.
|`<set the server name here>`|
|{$API.URI.ENDPOINT}|
The API endpoint is a URI - for example, `https://monitored.controlm.instance:8443/automation-api`.
|`<set the api uri endpoint here>`|
|{$API.TOKEN}|
A token to use for API connections.
|`<set the token here>`|

### Items

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Get Control-M server stats|
Gets the statistics of the server.
|HTTP agent|controlm.server.stats
**Preprocessing**

- 
JSON Path: `$.[?(@.name == '{$SERVER.NAME}')].first()`

⛔️Custom on fail: Set error to: `Could not get server stats.`

|
|Get jobs|
Gets the status of jobs.
|HTTP agent|controlm.jobs|
|Get agents|
Gets agents for the server.
|HTTP agent|controlm.agents|
|Jobs statistics|
Gets the statistics of jobs.
|Dependent item|controlm.jobs.statistics
**Preprocessing**

- 
JSON Path: `$.['returned', 'total']`

|
|Jobs returned|
Gets the count of returned jobs.
|Dependent item|controlm.jobs.statistics.returned
**Preprocessing**

- 
JSON Path: `$.[0]`

- 
Discard unchanged with heartbeat: `1h`

|
|Jobs total|
Gets the count of total jobs.
|Dependent item|controlm.jobs.statistics.total
**Preprocessing**

- 
JSON Path: `$.[1]`

- 
Discard unchanged with heartbeat: `1h`

|
|Server state|
Gets the metric of the server state.
|Dependent item|server.state
**Preprocessing**

- 
JSON Path: `$.state`

⛔️Custom on fail: Set error to: `Could not get server state.`

- 
JavaScript: `The text is too long. Please see the template.`

- 
Discard unchanged with heartbeat: `1h`

|
|Server message|
Gets the metric of the server message.
|Dependent item|server.message
**Preprocessing**

- 
JSON Path: `$.message`

⛔️Custom on fail: Set error to: `Could not get server message.`

- 
Discard unchanged with heartbeat: `1h`

|
|Server version|
Gets the metric of the server version.
|Dependent item|server.version
**Preprocessing**

- 
JSON Path: `$.version`

⛔️Custom on fail: Set error to: `Could not get server version.`

- 
Discard unchanged with heartbeat: `1h`

|

### Triggers

|Name|Description|Expression|Severity|Dependencies and additional info|
|----|-----------|----------|--------|--------------------------------|
|Control-M: Server is down|
The server is down.
|`last(/Control-M server by HTTP/server.state)=0 or last(/Control-M server by HTTP/server.state)=10`|High||
|Control-M: Server disconnected|
The server is disconnected.
|`last(/Control-M server by HTTP/server.message,#1)="Disconnected"`|High||
|Control-M: Server error|
The server has encountered an error.
|`last(/Control-M server by HTTP/server.message,#1)<>"Connected" and last(/Control-M server by HTTP/server.message,#1)<>"Disconnected" and last(/Control-M server by HTTP/server.message,#1)<>""`|High||
|Control-M: Server version has changed|
The server version has changed. Acknowledge to close the problem manually.
|`last(/Control-M server by HTTP/server.version,#1)<>last(/Control-M server by HTTP/server.version,#2) and length(last(/Control-M server by HTTP/server.version))>0`|Info|**Manual close**: Yes|

### LLD rule Jobs discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Jobs discovery|
Discovers jobs on the server.
|Dependent item|controlm.jobs.discovery
**Preprocessing**

- 
JSON Path: `$.statuses`

⛔️Custom on fail: Set value to: `[]`

- 
Discard unchanged with heartbeat: `1h`

|

### Item prototypes for Jobs discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Job [{#JOB.ID}]: stats|
Gets the statistics of a job.
|Dependent item|job.stats['{#JOB.ID}']
**Preprocessing**

- 
JSON Path: `$.statuses.[?(@.jobId == '{#JOB.ID}')].first()`

⛔️Custom on fail: Discard value

|
|Job [{#JOB.ID}]: status|
Gets the status of a job.
|Dependent item|job.status['{#JOB.ID}']
**Preprocessing**

- 
JSON Path: `$.status`

- 
JavaScript: `The text is too long. Please see the template.`

- 
Discard unchanged with heartbeat: `1h`

|
|Job [{#JOB.ID}]: number of runs|
Gets the number of runs for a job.
|Dependent item|job.numberOfRuns['{#JOB.ID}']
**Preprocessing**

- 
JSON Path: `$.numberOfRuns`

- 
Discard unchanged with heartbeat: `1h`

|
|Job [{#JOB.ID}]: type|
Gets the job type.
|Dependent item|job.type['{#JOB.ID}']
**Preprocessing**

- 
JSON Path: `$.type`

- 
JavaScript: `The text is too long. Please see the template.`

- 
Discard unchanged with heartbeat: `1h`

|
|Job [{#JOB.ID}]: held status|
Gets the held status of a job.
|Dependent item|job.held['{#JOB.ID}']
**Preprocessing**

- 
JSON Path: `$.held`

- 
JavaScript: `The text is too long. Please see the template.`

|

### Trigger prototypes for Jobs discovery

|Name|Description|Expression|Severity|Dependencies and additional info|
|----|-----------|----------|--------|--------------------------------|
|Control-M: Job [{#JOB.ID}]: status [{ITEM.VALUE}]|
The job has encountered an issue.
|`last(/Control-M server by HTTP/job.status['{#JOB.ID}'],#1)=1 or last(/Control-M server by HTTP/job.status['{#JOB.ID}'],#1)=10`|Warning|**Manual close**: Yes|

### LLD rule Agent discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Agent discovery|
Discovers agents on the server.
|Dependent item|controlm.agent.discovery
**Preprocessing**

- 
JSON Path: `$.agents`

⛔️Custom on fail: Set value to: `[]`

- 
Discard unchanged with heartbeat: `1h`

|

### Item prototypes for Agent discovery

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Agent [{#AGENT.NAME}]: stats|
Gets the statistics of an agent.
|Dependent item|agent.stats['{#AGENT.NAME}']
**Preprocessing**

- 
JSON Path: `$.agents.[?(@.nodeid == '{#AGENT.NAME}')].first()`

⛔️Custom on fail: Discard value

|
|Agent [{#AGENT.NAME}]: status|
Gets the status of an agent.
|Dependent item|agent.status['{#AGENT.NAME}']
**Preprocessing**

- 
JSON Path: `$.status`

- 
JavaScript: `The text is too long. Please see the template.`

- 
Discard unchanged with heartbeat: `1h`

|
|Agent [{#AGENT.NAME}]: version|
Gets the version number of an agent.
|Dependent item|agent.version['{#AGENT.NAME}']
**Preprocessing**

- 
JSON Path: `$.version`

⛔️Custom on fail: Set value to: `Unknown`

- 
Discard unchanged with heartbeat: `1h`

|

### Trigger prototypes for Agent discovery

|Name|Description|Expression|Severity|Dependencies and additional info|
|----|-----------|----------|--------|--------------------------------|
|Control-M: Agent [{#AGENT.NAME}]: status [{ITEM.VALUE}]|
The agent has encountered an issue.
|`last(/Control-M server by HTTP/agent.status['{#AGENT.NAME}'],#1)=1 or last(/Control-M server by HTTP/agent.status['{#AGENT.NAME}'],#1)=10`|Average|**Manual close**: Yes|
|Control-M: Agent [{#AGENT.NAME}}: status disabled|
The agent is disabled.
|`last(/Control-M server by HTTP/agent.status['{#AGENT.NAME}'],#1)=2 or last(/Control-M server by HTTP/agent.status['{#AGENT.NAME}'],#1)=3`|Info|**Manual close**: Yes|
|Control-M: Agent [{#AGENT.NAME}]: version has changed|
The agent version has changed. Acknowledge to close the problem manually.
|`last(/Control-M server by HTTP/agent.version['{#AGENT.NAME}'],#1)<>last(/Control-M server by HTTP/agent.version['{#AGENT.NAME}'],#2)`|Info|**Manual close**: Yes|
|Control-M: Agent [{#AGENT.NAME}]: unknown version|
The agent version is unknown.
|`last(/Control-M server by HTTP/agent.version['{#AGENT.NAME}'],#1)="Unknown"`|Warning|**Manual close**: Yes|

## Feedback

Please report any issues with the template at [`https://support.zabbix.com`](https://support.zabbix.com)

You can also provide feedback, discuss the template, or ask for help at [`ZABBIX forums`](https://www.zabbix.com/forum/zabbix-suggestions-and-feedback)

