mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
feat: Implement DNS monitoring configuration and secret handling
This commit is contained in:
@@ -521,6 +521,19 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "dnsMonitor",
|
||||
type: "MonitorStepDnsMonitor",
|
||||
required: false,
|
||||
description:
|
||||
"Configuration for DNS monitoring. Required for DNS monitor type. Defines query name (domain), record type, optional DNS server, port, timeout, and retry settings. See MonitorStepDnsMonitor.",
|
||||
typeLinks: [
|
||||
{
|
||||
label: "MonitorStepDnsMonitor",
|
||||
path: "monitor-step-dns-monitor",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
values: [],
|
||||
jsonExample: JSON.stringify(
|
||||
@@ -2560,6 +2573,31 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
|
||||
description:
|
||||
"Whether the SNMP device is reachable. Use with 'True' or 'False'. Applies to: SNMP monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNS Response Time (in ms)",
|
||||
description:
|
||||
"The DNS query response time in milliseconds. Use with numeric FilterTypes. Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNS Is Online",
|
||||
description:
|
||||
"Whether the DNS resolution succeeded. Use with 'True' or 'False'. Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNS Record Value",
|
||||
description:
|
||||
"The value of a DNS record returned by the query. Use with string FilterTypes (Contains, EqualTo, etc.). Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNSSEC Is Valid",
|
||||
description:
|
||||
"Whether DNSSEC validation passed (AD flag present). Use with 'True' or 'False'. Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "DNS Record Exists",
|
||||
description:
|
||||
"Whether any DNS records were returned for the query. Use with 'True' or 'False'. Applies to: DNS monitors.",
|
||||
},
|
||||
{
|
||||
value: "JavaScript Expression",
|
||||
description:
|
||||
@@ -3112,6 +3150,94 @@ const dataTypeDetails: Dictionary<DataTypePageData> = {
|
||||
2,
|
||||
),
|
||||
},
|
||||
"monitor-step-dns-monitor": {
|
||||
title: "MonitorStepDnsMonitor",
|
||||
description:
|
||||
"Configuration for a DNS monitor step. Defines the domain to query, record type, optional custom DNS server, and timeout settings. Used as the 'dnsMonitor' property on a MonitorStep when the monitor type is 'DNS'. The criteria filters can then use 'DNS Is Online', 'DNS Response Time (in ms)', 'DNS Record Value', 'DNSSEC Is Valid', and 'DNS Record Exists' as CheckOn values.",
|
||||
isEnum: false,
|
||||
relatedTypes: [
|
||||
{
|
||||
name: "MonitorStep",
|
||||
path: "monitor-step",
|
||||
relationship: "Parent that holds this as dnsMonitor property",
|
||||
},
|
||||
{
|
||||
name: "CheckOn",
|
||||
path: "check-on",
|
||||
relationship: "Use DNS-specific CheckOn values with DNS monitors",
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
name: "queryName",
|
||||
type: "string",
|
||||
required: true,
|
||||
description:
|
||||
"The domain name to query (e.g., 'example.com').",
|
||||
},
|
||||
{
|
||||
name: "recordType",
|
||||
type: "string (enum)",
|
||||
required: true,
|
||||
description:
|
||||
"The DNS record type to query. Possible values: 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'SOA', 'PTR', 'SRV', 'CAA'.",
|
||||
},
|
||||
{
|
||||
name: "hostname",
|
||||
type: "string",
|
||||
required: false,
|
||||
description:
|
||||
"Custom DNS server to use for the query (e.g., '8.8.8.8'). Leave empty to use system default DNS resolver.",
|
||||
},
|
||||
{
|
||||
name: "port",
|
||||
type: "number",
|
||||
required: false,
|
||||
description: "DNS port. Default is 53.",
|
||||
},
|
||||
{
|
||||
name: "timeout",
|
||||
type: "number",
|
||||
required: false,
|
||||
description:
|
||||
"Timeout for DNS queries in milliseconds. Default is 5000 (5 seconds).",
|
||||
},
|
||||
{
|
||||
name: "retries",
|
||||
type: "number",
|
||||
required: false,
|
||||
description: "Number of retries for failed DNS queries. Default is 3.",
|
||||
},
|
||||
],
|
||||
values: [],
|
||||
jsonExample: JSON.stringify(
|
||||
{
|
||||
"// Example 1: Basic A record lookup": {
|
||||
queryName: "example.com",
|
||||
recordType: "A",
|
||||
timeout: 5000,
|
||||
retries: 3,
|
||||
},
|
||||
"// Example 2: MX record with custom DNS server": {
|
||||
queryName: "example.com",
|
||||
recordType: "MX",
|
||||
hostname: "8.8.8.8",
|
||||
port: 53,
|
||||
timeout: 5000,
|
||||
retries: 3,
|
||||
},
|
||||
"// Example 3: TXT record for SPF verification": {
|
||||
queryName: "example.com",
|
||||
recordType: "TXT",
|
||||
hostname: "1.1.1.1",
|
||||
timeout: 5000,
|
||||
retries: 3,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
export default class ServiceHandler {
|
||||
|
||||
@@ -127,6 +127,14 @@ export class Service extends DatabaseService<Model> {
|
||||
monitorDestination = `${monitorDestination}:${port}`;
|
||||
}
|
||||
}
|
||||
|
||||
// For DNS monitors, use the queryName from dnsMonitor config
|
||||
if (monitorType === MonitorType.DNS && firstStep?.data?.dnsMonitor) {
|
||||
monitorDestination = firstStep.data.dnsMonitor.queryName || "";
|
||||
if (firstStep.data.dnsMonitor.hostname) {
|
||||
monitorDestination = `${monitorDestination} @${firstStep.data.dnsMonitor.hostname}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,9 @@ import SyntheticMonitorResponse from "../../../Types/Monitor/SyntheticMonitors/S
|
||||
import SnmpMonitorResponse, {
|
||||
SnmpOidResponse,
|
||||
} from "../../../Types/Monitor/SnmpMonitor/SnmpMonitorResponse";
|
||||
import DnsMonitorResponse, {
|
||||
DnsRecordResponse,
|
||||
} from "../../../Types/Monitor/DnsMonitor/DnsMonitorResponse";
|
||||
import Typeof from "../../../Types/Typeof";
|
||||
import VMUtil from "../VM/VMAPI";
|
||||
import DataToProcess from "./DataToProcess";
|
||||
@@ -240,6 +243,40 @@ export default class MonitorTemplateUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.monitorType === MonitorType.DNS) {
|
||||
const dnsResponse: DnsMonitorResponse | undefined = (
|
||||
data.dataToProcess as ProbeMonitorResponse
|
||||
).dnsResponse;
|
||||
|
||||
storageMap = {
|
||||
isOnline: (data.dataToProcess as ProbeMonitorResponse).isOnline,
|
||||
responseTimeInMs: dnsResponse?.responseTimeInMs,
|
||||
failureCause: dnsResponse?.failureCause,
|
||||
isTimeout: dnsResponse?.isTimeout,
|
||||
isDnssecValid: dnsResponse?.isDnssecValid,
|
||||
} as JSONObject;
|
||||
|
||||
// Add DNS records
|
||||
if (dnsResponse?.records) {
|
||||
storageMap["records"] = dnsResponse.records.map(
|
||||
(record: DnsRecordResponse) => {
|
||||
return {
|
||||
type: record.type,
|
||||
value: record.value,
|
||||
ttl: record.ttl,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// Add record values as a flat array for easier templating
|
||||
storageMap["recordValues"] = dnsResponse.records.map(
|
||||
(record: DnsRecordResponse) => {
|
||||
return record.value;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,8 @@ class MonitorMetricTypeUtil {
|
||||
monitorType === MonitorType.Ping ||
|
||||
monitorType === MonitorType.IP ||
|
||||
monitorType === MonitorType.Port ||
|
||||
monitorType === MonitorType.SNMP
|
||||
monitorType === MonitorType.SNMP ||
|
||||
monitorType === MonitorType.DNS
|
||||
) {
|
||||
return [MonitorMetricType.IsOnline, MonitorMetricType.ResponseTime];
|
||||
}
|
||||
|
||||
@@ -196,6 +196,45 @@ export default class MonitorUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if (monitorType === MonitorType.DNS) {
|
||||
for (const monitorStep of monitorSteps?.data?.monitorStepsInstanceArray ||
|
||||
[]) {
|
||||
// Handle DNS hostname secrets (custom DNS server)
|
||||
if (
|
||||
monitorStep.data?.dnsMonitor?.hostname &&
|
||||
this.hasSecrets(monitorStep.data.dnsMonitor.hostname)
|
||||
) {
|
||||
if (!isSecretsLoaded) {
|
||||
monitorSecrets = await MonitorUtil.loadMonitorSecrets(monitorId);
|
||||
isSecretsLoaded = true;
|
||||
}
|
||||
|
||||
monitorStep.data.dnsMonitor.hostname =
|
||||
(await MonitorUtil.fillSecretsInStringOrJSON({
|
||||
secrets: monitorSecrets,
|
||||
populateSecretsIn: monitorStep.data.dnsMonitor.hostname,
|
||||
})) as string;
|
||||
}
|
||||
|
||||
// Handle DNS query name secrets
|
||||
if (
|
||||
monitorStep.data?.dnsMonitor?.queryName &&
|
||||
this.hasSecrets(monitorStep.data.dnsMonitor.queryName)
|
||||
) {
|
||||
if (!isSecretsLoaded) {
|
||||
monitorSecrets = await MonitorUtil.loadMonitorSecrets(monitorId);
|
||||
isSecretsLoaded = true;
|
||||
}
|
||||
|
||||
monitorStep.data.dnsMonitor.queryName =
|
||||
(await MonitorUtil.fillSecretsInStringOrJSON({
|
||||
secrets: monitorSecrets,
|
||||
populateSecretsIn: monitorStep.data.dnsMonitor.queryName,
|
||||
})) as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return monitorSteps;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user