mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-01-16 23:00:51 +00:00
feat: integrate CaptureSpan decorator into various classes for enhanced telemetry tracking
This commit is contained in:
parent
7c50a09aff
commit
8972cc4d86
18 changed files with 338 additions and 313 deletions
|
|
@ -4,6 +4,7 @@ import Includes from "Common/Types/BaseDatabase/Includes";
|
|||
import LessThan from "Common/Types/BaseDatabase/LessThan";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import { CompareType } from "../../../Types/Database/CompareBase";
|
||||
import CaptureSpan from "../../Utils/Telemetry/CaptureSpan";
|
||||
|
||||
export default class QueryHelper {
|
||||
@CaptureSpan()
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import ProductType from "Common/Types/MeteredPlan/ProductType";
|
|||
import ObjectID from "Common/Types/ObjectID";
|
||||
import Project from "Common/Models/DatabaseModels/Project";
|
||||
import TelemetryUsageBilling from "Common/Models/DatabaseModels/TelemetryUsageBilling";
|
||||
import CaptureSpan from "../../../Utils/Telemetry/CaptureSpan";
|
||||
|
||||
export default class TelemetryMeteredPlan extends ServerMeteredPlan {
|
||||
private _productType!: ProductType;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import Permission, {
|
|||
} from "Common/Types/Permission";
|
||||
import CaptureSpan from "../../../Utils/Telemetry/CaptureSpan";
|
||||
|
||||
|
||||
export default class AccessControlPermission {
|
||||
@CaptureSpan()
|
||||
public static async checkAccessControlBlockPermissionByModel<
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import ObjectID from "Common/Types/ObjectID";
|
|||
import Typeof from "Common/Types/Typeof";
|
||||
import { FindOperator } from "typeorm/find-options/FindOperator";
|
||||
import { CompareType } from "../../../Types/Database/CompareBase";
|
||||
import CaptureSpan from "../../Utils/Telemetry/CaptureSpan";
|
||||
|
||||
export default class QueryUtil {
|
||||
@CaptureSpan()
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import BaseModel, {
|
|||
} from "Common/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
|
||||
import { JSONObject } from "Common/Types/JSON";
|
||||
import Typeof from "Common/Types/Typeof";
|
||||
import CaptureSpan from "../../Utils/Telemetry/CaptureSpan";
|
||||
|
||||
export default class SelectUtil {
|
||||
@CaptureSpan()
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import PositiveNumber from "Common/Types/PositiveNumber";
|
|||
import Text from "Common/Types/Text";
|
||||
import ComponentMetadata, { Port } from "Common/Types/Workflow/Component";
|
||||
import BaseModelComponents from "Common/Types/Workflow/Components/BaseModel";
|
||||
import CaptureSpan from "../../../../Utils/Telemetry/CaptureSpan";
|
||||
|
||||
export default class DeleteManyBaseModel<
|
||||
TBaseModel extends BaseModel,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import ComponentMetadata, { Port } from "Common/Types/Workflow/Component";
|
|||
import ComponentID from "Common/Types/Workflow/ComponentID";
|
||||
import ScheduleComponents from "Common/Types/Workflow/Components/Schedule";
|
||||
import Workflow from "Common/Models/DatabaseModels/Workflow";
|
||||
import CaptureSpan from "../../../Utils/Telemetry/CaptureSpan";
|
||||
|
||||
export default class WebhookTrigger extends TriggerCode {
|
||||
public constructor() {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import JSONFunctions from "Common/Types/JSONFunctions";
|
|||
import AggregateBy, {
|
||||
AggregateUtil,
|
||||
} from "../../Types/AnalyticsDatabase/AggregateBy";
|
||||
import CaptureSpan from "../Telemetry/CaptureSpan";
|
||||
|
||||
export default class StatementGenerator<TBaseModel extends AnalyticsBaseModel> {
|
||||
public model!: TBaseModel;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import BadDataException from "../../Types/Exception/BadDataException";
|
|||
import ScreenSizeType from "../../Types/ScreenSizeType";
|
||||
import BrowserType from "../../Types/BrowserType";
|
||||
import logger from "./Logger";
|
||||
import CaptureSpan from "./Telemetry/CaptureSpan";
|
||||
|
||||
export type Page = PlaywrightPage;
|
||||
export type Browser = PlaywrightBrowser;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import BadDataException from "Common/Types/Exception/BadDataException";
|
||||
import CronParser, { CronExpression } from "cron-parser";
|
||||
import CaptureSpan from "./Telemetry/CaptureSpan";
|
||||
|
||||
export default class CronTab {
|
||||
@CaptureSpan()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { EncryptionSecret } from "../EnvironmentConfig";
|
||||
import CryptoJS from "crypto-js";
|
||||
import CaptureSpan from "./Telemetry/CaptureSpan";
|
||||
|
||||
export default class Encryption {
|
||||
@CaptureSpan()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import UserType from "Common/Types/UserType";
|
|||
import "ejs";
|
||||
import express from "express";
|
||||
import { Server, createServer } from "http";
|
||||
import CaptureSpan from "./Telemetry/CaptureSpan";
|
||||
|
||||
export type RequestHandler = express.RequestHandler;
|
||||
export type NextFunction = express.NextFunction;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import AcmeCertificate from "Common/Models/DatabaseModels/AcmeCertificate";
|
|||
import AcmeChallenge from "Common/Models/DatabaseModels/AcmeChallenge";
|
||||
import acme from "acme-client";
|
||||
import { Challenge } from "acme-client/types/rfc8555";
|
||||
import Telemetry, { Span } from "../Telemetry";
|
||||
import CaptureSpan from "../Telemetry/CaptureSpan";
|
||||
|
||||
export default class GreenlockUtil {
|
||||
@CaptureSpan()
|
||||
|
|
@ -25,145 +25,114 @@ export default class GreenlockUtil {
|
|||
validateCname: (domain: string) => Promise<boolean>;
|
||||
notifyDomainRemoved: (domain: string) => Promise<void>;
|
||||
}): Promise<void> {
|
||||
return await Telemetry.startActiveSpan<Promise<void>>({
|
||||
name: "GreenlockUtil.renewAllCertsWhichAreExpiringSoon",
|
||||
fn: async (span: Span): Promise<void> => {
|
||||
try {
|
||||
logger.debug("Renewing all certificates");
|
||||
|
||||
// get all certificates which are expiring soon
|
||||
|
||||
const certificates: AcmeCertificate[] =
|
||||
await AcmeCertificateService.findBy({
|
||||
query: {
|
||||
expiresAt: QueryHelper.lessThanEqualTo(
|
||||
OneUptimeDate.addRemoveDays(
|
||||
OneUptimeDate.getCurrentDate(),
|
||||
40, // 40 days before expiry
|
||||
),
|
||||
),
|
||||
},
|
||||
limit: LIMIT_MAX,
|
||||
skip: 0,
|
||||
select: {
|
||||
domain: true,
|
||||
},
|
||||
sort: {
|
||||
expiresAt: SortOrder.Ascending,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(
|
||||
`Found ${certificates.length} certificates which are expiring soon`,
|
||||
);
|
||||
|
||||
// order certificate for each domain
|
||||
|
||||
for (const certificate of certificates) {
|
||||
if (!certificate.domain) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
`Renewing certificate for domain: ${certificate.domain}`,
|
||||
);
|
||||
|
||||
try {
|
||||
logger.debug("Renewing all certificates");
|
||||
|
||||
// get all certificates which are expiring soon
|
||||
|
||||
const certificates: AcmeCertificate[] =
|
||||
await AcmeCertificateService.findBy({
|
||||
query: {
|
||||
expiresAt: QueryHelper.lessThanEqualTo(
|
||||
OneUptimeDate.addRemoveDays(
|
||||
OneUptimeDate.getCurrentDate(),
|
||||
40, // 40 days before expiry
|
||||
),
|
||||
),
|
||||
},
|
||||
limit: LIMIT_MAX,
|
||||
skip: 0,
|
||||
select: {
|
||||
domain: true,
|
||||
},
|
||||
sort: {
|
||||
expiresAt: SortOrder.Ascending,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(
|
||||
`Found ${certificates.length} certificates which are expiring soon`,
|
||||
//validate cname
|
||||
const isValidCname: boolean = await data.validateCname(
|
||||
certificate.domain,
|
||||
);
|
||||
|
||||
// order certificate for each domain
|
||||
|
||||
for (const certificate of certificates) {
|
||||
if (!certificate.domain) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isValidCname) {
|
||||
logger.debug(
|
||||
`Renewing certificate for domain: ${certificate.domain}`,
|
||||
`CNAME is not valid for domain: ${certificate.domain}`,
|
||||
);
|
||||
|
||||
try {
|
||||
//validate cname
|
||||
const isValidCname: boolean = await data.validateCname(
|
||||
certificate.domain,
|
||||
);
|
||||
// if cname is not valid then remove the domain
|
||||
await GreenlockUtil.removeDomain(certificate.domain);
|
||||
await data.notifyDomainRemoved(certificate.domain);
|
||||
|
||||
if (!isValidCname) {
|
||||
logger.debug(
|
||||
`CNAME is not valid for domain: ${certificate.domain}`,
|
||||
);
|
||||
logger.error(
|
||||
`Cname is not valid for domain: ${certificate.domain}`,
|
||||
);
|
||||
} else {
|
||||
logger.debug(
|
||||
`CNAME is valid for domain: ${certificate.domain}`,
|
||||
);
|
||||
|
||||
// if cname is not valid then remove the domain
|
||||
await GreenlockUtil.removeDomain(certificate.domain);
|
||||
await data.notifyDomainRemoved(certificate.domain);
|
||||
await GreenlockUtil.orderCert({
|
||||
domain: certificate.domain,
|
||||
validateCname: data.validateCname,
|
||||
});
|
||||
|
||||
logger.error(
|
||||
`Cname is not valid for domain: ${certificate.domain}`,
|
||||
);
|
||||
} else {
|
||||
logger.debug(
|
||||
`CNAME is valid for domain: ${certificate.domain}`,
|
||||
);
|
||||
|
||||
await GreenlockUtil.orderCert({
|
||||
domain: certificate.domain,
|
||||
validateCname: data.validateCname,
|
||||
});
|
||||
|
||||
logger.debug(
|
||||
`Certificate renewed for domain: ${certificate.domain}`,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`Error renewing certificate for domain: ${certificate.domain}`,
|
||||
);
|
||||
logger.error(e);
|
||||
}
|
||||
logger.debug(
|
||||
`Certificate renewed for domain: ${certificate.domain}`,
|
||||
);
|
||||
}
|
||||
|
||||
Telemetry.endSpan(span);
|
||||
} catch (e) {
|
||||
logger.error("Error renewing all certificates");
|
||||
logger.error(
|
||||
`Error renewing certificate for domain: ${certificate.domain}`,
|
||||
);
|
||||
logger.error(e);
|
||||
|
||||
// record exception
|
||||
Telemetry.recordExceptionMarkSpanAsErrorAndEndSpan({
|
||||
span,
|
||||
exception: e,
|
||||
});
|
||||
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error("Error renewing all certificates");
|
||||
logger.error(e);
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@CaptureSpan()
|
||||
public static async removeDomain(domain: string): Promise<void> {
|
||||
return await Telemetry.startActiveSpan<Promise<void>>({
|
||||
name: "GreenlockUtil.orderCert",
|
||||
options: {
|
||||
attributes: {
|
||||
try {
|
||||
// remove certificate for this domain.
|
||||
await AcmeCertificateService.deleteBy({
|
||||
query: {
|
||||
domain: domain,
|
||||
},
|
||||
},
|
||||
fn: async (span: Span): Promise<void> => {
|
||||
try {
|
||||
// remove certificate for this domain.
|
||||
await AcmeCertificateService.deleteBy({
|
||||
query: {
|
||||
domain: domain,
|
||||
},
|
||||
limit: 1,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
Telemetry.endSpan(span);
|
||||
} catch (err) {
|
||||
logger.error(`Error removing domain: ${domain}`);
|
||||
|
||||
Telemetry.recordExceptionMarkSpanAsErrorAndEndSpan({
|
||||
span,
|
||||
exception: err,
|
||||
});
|
||||
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
});
|
||||
limit: 1,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(`Error removing domain: ${domain}`);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
@CaptureSpan()
|
||||
|
|
@ -171,218 +140,201 @@ export default class GreenlockUtil {
|
|||
domain: string;
|
||||
validateCname: (domain: string) => Promise<boolean>;
|
||||
}): Promise<void> {
|
||||
return await Telemetry.startActiveSpan<Promise<void>>({
|
||||
name: "GreenlockUtil.orderCert",
|
||||
options: {
|
||||
attributes: {
|
||||
domain: data.domain,
|
||||
},
|
||||
},
|
||||
fn: async (span: Span): Promise<void> => {
|
||||
try {
|
||||
logger.debug(
|
||||
`GreenlockUtil - Ordering certificate for domain: ${data.domain}`,
|
||||
);
|
||||
try {
|
||||
logger.debug(
|
||||
`GreenlockUtil - Ordering certificate for domain: ${data.domain}`,
|
||||
);
|
||||
|
||||
let { domain } = data;
|
||||
let { domain } = data;
|
||||
|
||||
domain = domain.trim().toLowerCase();
|
||||
domain = domain.trim().toLowerCase();
|
||||
|
||||
const acmeAccountKeyInBase64: string = LetsEncryptAccountKey;
|
||||
const acmeAccountKeyInBase64: string = LetsEncryptAccountKey;
|
||||
|
||||
if (!acmeAccountKeyInBase64) {
|
||||
throw new ServerException(
|
||||
"No lets encrypt account key found in environment variables. Please add one.",
|
||||
if (!acmeAccountKeyInBase64) {
|
||||
throw new ServerException(
|
||||
"No lets encrypt account key found in environment variables. Please add one.",
|
||||
);
|
||||
}
|
||||
|
||||
let acmeAccountKey: string = Buffer.from(
|
||||
acmeAccountKeyInBase64,
|
||||
"base64",
|
||||
).toString();
|
||||
|
||||
acmeAccountKey = Text.replaceAll(acmeAccountKey, "\\n", "\n");
|
||||
|
||||
//validate cname
|
||||
|
||||
logger.debug(`Validating cname for domain: ${domain}`);
|
||||
|
||||
const isValidCname: boolean = await data.validateCname(domain);
|
||||
|
||||
if (!isValidCname) {
|
||||
logger.debug(`CNAME is not valid for domain: ${domain}`);
|
||||
logger.debug(`Removing domain: ${domain}`);
|
||||
|
||||
await GreenlockUtil.removeDomain(domain);
|
||||
logger.error(`Cname is not valid for domain: ${domain}`);
|
||||
throw new BadDataException(
|
||||
"Cname is not valid for domain " + domain,
|
||||
);
|
||||
}
|
||||
|
||||
logger.debug(`Cname is valid for domain: ${domain}`);
|
||||
|
||||
const client: acme.Client = new acme.Client({
|
||||
directoryUrl: acme.directory.letsencrypt.production,
|
||||
accountKey: acmeAccountKey,
|
||||
});
|
||||
|
||||
const [certificateKey, certificateRequest] =
|
||||
await acme.crypto.createCsr({
|
||||
commonName: domain,
|
||||
});
|
||||
|
||||
logger.debug(`Ordering certificate for domain: ${domain}`);
|
||||
|
||||
const certificate: string = await client.auto({
|
||||
csr: certificateRequest,
|
||||
email: LetsEncryptNotificationEmail.toString(),
|
||||
termsOfServiceAgreed: true,
|
||||
challengePriority: ["http-01"], // only http-01 challenge is supported by oneuptime
|
||||
challengeCreateFn: async (
|
||||
authz: acme.Authorization,
|
||||
challenge: Challenge,
|
||||
keyAuthorization: string,
|
||||
) => {
|
||||
// Satisfy challenge here
|
||||
/* http-01 */
|
||||
if (challenge.type === "http-01") {
|
||||
logger.debug(
|
||||
`Creating challenge for domain: ${authz.identifier.value}`,
|
||||
);
|
||||
}
|
||||
|
||||
let acmeAccountKey: string = Buffer.from(
|
||||
acmeAccountKeyInBase64,
|
||||
"base64",
|
||||
).toString();
|
||||
const acmeChallenge: AcmeChallenge = new AcmeChallenge();
|
||||
acmeChallenge.challenge = keyAuthorization;
|
||||
acmeChallenge.token = challenge.token;
|
||||
acmeChallenge.domain = authz.identifier.value;
|
||||
|
||||
acmeAccountKey = Text.replaceAll(acmeAccountKey, "\\n", "\n");
|
||||
|
||||
//validate cname
|
||||
|
||||
logger.debug(`Validating cname for domain: ${domain}`);
|
||||
|
||||
const isValidCname: boolean = await data.validateCname(domain);
|
||||
|
||||
if (!isValidCname) {
|
||||
logger.debug(`CNAME is not valid for domain: ${domain}`);
|
||||
logger.debug(`Removing domain: ${domain}`);
|
||||
|
||||
await GreenlockUtil.removeDomain(domain);
|
||||
logger.error(`Cname is not valid for domain: ${domain}`);
|
||||
throw new BadDataException(
|
||||
"Cname is not valid for domain " + domain,
|
||||
);
|
||||
}
|
||||
|
||||
logger.debug(`Cname is valid for domain: ${domain}`);
|
||||
|
||||
const client: acme.Client = new acme.Client({
|
||||
directoryUrl: acme.directory.letsencrypt.production,
|
||||
accountKey: acmeAccountKey,
|
||||
});
|
||||
|
||||
const [certificateKey, certificateRequest] =
|
||||
await acme.crypto.createCsr({
|
||||
commonName: domain,
|
||||
});
|
||||
|
||||
logger.debug(`Ordering certificate for domain: ${domain}`);
|
||||
|
||||
const certificate: string = await client.auto({
|
||||
csr: certificateRequest,
|
||||
email: LetsEncryptNotificationEmail.toString(),
|
||||
termsOfServiceAgreed: true,
|
||||
challengePriority: ["http-01"], // only http-01 challenge is supported by oneuptime
|
||||
challengeCreateFn: async (
|
||||
authz: acme.Authorization,
|
||||
challenge: Challenge,
|
||||
keyAuthorization: string,
|
||||
) => {
|
||||
// Satisfy challenge here
|
||||
/* http-01 */
|
||||
if (challenge.type === "http-01") {
|
||||
logger.debug(
|
||||
`Creating challenge for domain: ${authz.identifier.value}`,
|
||||
);
|
||||
|
||||
const acmeChallenge: AcmeChallenge = new AcmeChallenge();
|
||||
acmeChallenge.challenge = keyAuthorization;
|
||||
acmeChallenge.token = challenge.token;
|
||||
acmeChallenge.domain = authz.identifier.value;
|
||||
|
||||
await AcmeChallengeService.create({
|
||||
data: acmeChallenge,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(
|
||||
`Challenge created for domain: ${authz.identifier.value}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
challengeRemoveFn: async (
|
||||
authz: acme.Authorization,
|
||||
challenge: Challenge,
|
||||
) => {
|
||||
// Clean up challenge here
|
||||
|
||||
logger.debug(
|
||||
`Removing challenge for domain: ${authz.identifier.value}`,
|
||||
);
|
||||
|
||||
if (challenge.type === "http-01") {
|
||||
await AcmeChallengeService.deleteBy({
|
||||
query: {
|
||||
domain: authz.identifier.value,
|
||||
},
|
||||
limit: 1,
|
||||
skip: 0,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
logger.debug(
|
||||
`Challenge removed for domain: ${authz.identifier.value}`,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Certificate ordered for domain: ${domain}`);
|
||||
|
||||
// get expires at date from certificate
|
||||
const cert: acme.CertificateInfo =
|
||||
acme.crypto.readCertificateInfo(certificate);
|
||||
const issuedAt: Date = cert.notBefore;
|
||||
const expiresAt: Date = cert.notAfter;
|
||||
|
||||
logger.debug(`Certificate expires at: ${expiresAt}`);
|
||||
logger.debug(`Certificate issued at: ${issuedAt}`);
|
||||
|
||||
// check if the certificate is already in the database.
|
||||
const existingCertificate: AcmeCertificate | null =
|
||||
await AcmeCertificateService.findOneBy({
|
||||
query: {
|
||||
domain: domain,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
await AcmeChallengeService.create({
|
||||
data: acmeChallenge,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingCertificate) {
|
||||
logger.debug(`Updating certificate for domain: ${domain}`);
|
||||
logger.debug(
|
||||
`Challenge created for domain: ${authz.identifier.value}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
challengeRemoveFn: async (
|
||||
authz: acme.Authorization,
|
||||
challenge: Challenge,
|
||||
) => {
|
||||
// Clean up challenge here
|
||||
|
||||
// update the certificate
|
||||
await AcmeCertificateService.updateBy({
|
||||
logger.debug(
|
||||
`Removing challenge for domain: ${authz.identifier.value}`,
|
||||
);
|
||||
|
||||
if (challenge.type === "http-01") {
|
||||
await AcmeChallengeService.deleteBy({
|
||||
query: {
|
||||
domain: domain,
|
||||
domain: authz.identifier.value,
|
||||
},
|
||||
limit: 1,
|
||||
skip: 0,
|
||||
data: {
|
||||
certificate: certificate.toString(),
|
||||
certificateKey: certificateKey.toString(),
|
||||
issuedAt: issuedAt,
|
||||
expiresAt: expiresAt,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Certificate updated for domain: ${domain}`);
|
||||
} else {
|
||||
logger.debug(`Creating certificate for domain: ${domain}`);
|
||||
// create the certificate
|
||||
const acmeCertificate: AcmeCertificate = new AcmeCertificate();
|
||||
|
||||
acmeCertificate.domain = domain;
|
||||
acmeCertificate.certificate = certificate.toString();
|
||||
acmeCertificate.certificateKey = certificateKey.toString();
|
||||
acmeCertificate.issuedAt = issuedAt;
|
||||
acmeCertificate.expiresAt = expiresAt;
|
||||
|
||||
await AcmeCertificateService.create({
|
||||
data: acmeCertificate,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Certificate created for domain: ${domain}`);
|
||||
}
|
||||
|
||||
Telemetry.endSpan(span);
|
||||
} catch (e) {
|
||||
logger.error(`Error ordering certificate for domain: ${data.domain}`);
|
||||
|
||||
Telemetry.recordExceptionMarkSpanAsErrorAndEndSpan({
|
||||
span,
|
||||
exception: e,
|
||||
});
|
||||
|
||||
if (e instanceof Exception) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
throw new ServerException(
|
||||
`Unable to order certificate for ${data.domain}. Please contact support at support@oneuptime.com for more information.`,
|
||||
logger.debug(
|
||||
`Challenge removed for domain: ${authz.identifier.value}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Certificate ordered for domain: ${domain}`);
|
||||
|
||||
// get expires at date from certificate
|
||||
const cert: acme.CertificateInfo =
|
||||
acme.crypto.readCertificateInfo(certificate);
|
||||
const issuedAt: Date = cert.notBefore;
|
||||
const expiresAt: Date = cert.notAfter;
|
||||
|
||||
logger.debug(`Certificate expires at: ${expiresAt}`);
|
||||
logger.debug(`Certificate issued at: ${issuedAt}`);
|
||||
|
||||
// check if the certificate is already in the database.
|
||||
const existingCertificate: AcmeCertificate | null =
|
||||
await AcmeCertificateService.findOneBy({
|
||||
query: {
|
||||
domain: domain,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingCertificate) {
|
||||
logger.debug(`Updating certificate for domain: ${domain}`);
|
||||
|
||||
// update the certificate
|
||||
await AcmeCertificateService.updateBy({
|
||||
query: {
|
||||
domain: domain,
|
||||
},
|
||||
limit: 1,
|
||||
skip: 0,
|
||||
data: {
|
||||
certificate: certificate.toString(),
|
||||
certificateKey: certificateKey.toString(),
|
||||
issuedAt: issuedAt,
|
||||
expiresAt: expiresAt,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Certificate updated for domain: ${domain}`);
|
||||
} else {
|
||||
logger.debug(`Creating certificate for domain: ${domain}`);
|
||||
// create the certificate
|
||||
const acmeCertificate: AcmeCertificate = new AcmeCertificate();
|
||||
|
||||
acmeCertificate.domain = domain;
|
||||
acmeCertificate.certificate = certificate.toString();
|
||||
acmeCertificate.certificateKey = certificateKey.toString();
|
||||
acmeCertificate.issuedAt = issuedAt;
|
||||
acmeCertificate.expiresAt = expiresAt;
|
||||
|
||||
await AcmeCertificateService.create({
|
||||
data: acmeCertificate,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug(`Certificate created for domain: ${domain}`);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(`Error ordering certificate for domain: ${data.domain}`);
|
||||
|
||||
if (e instanceof Exception) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
throw new ServerException(
|
||||
`Unable to order certificate for ${data.domain}. Please contact support at support@oneuptime.com for more information.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import CompareCriteria from "./CompareCriteria";
|
||||
import { CheckOn, CriteriaFilter } from "Common/Types/Monitor/CriteriaFilter";
|
||||
import CustomCodeMonitorResponse from "Common/Types/Monitor/CustomCodeMonitor/CustomCodeMonitorResponse";
|
||||
import CaptureSpan from "../../Telemetry/CaptureSpan";
|
||||
|
||||
export default class CustomCodeMonitoringCriteria {
|
||||
@CaptureSpan()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import CompareCriteria from "./CompareCriteria";
|
|||
import { CheckOn, CriteriaFilter } from "Common/Types/Monitor/CriteriaFilter";
|
||||
|
||||
export default class TraceMonitorCriteria {
|
||||
@CaptureSpan()
|
||||
@CaptureSpan()
|
||||
public static async isMonitorInstanceCriteriaFilterMet(input: {
|
||||
dataToProcess: DataToProcess;
|
||||
criteriaFilter: CriteriaFilter;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,17 @@ const MonitorPage: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
|||
return import("../Pages/Monitor/Monitors");
|
||||
});
|
||||
|
||||
const WorkspaceConnectionSlack: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/WorkspaceConnectionSlack");
|
||||
});
|
||||
|
||||
const WorkspaceConnectionTeams: LazyExoticComponent<FunctionComponent<ComponentProps>> =
|
||||
lazy(() => {
|
||||
return import("../Pages/Monitor/WorkspaceConnectionMicrosoftTeams");
|
||||
});
|
||||
|
||||
|
||||
const MonitorViewMetrics: LazyExoticComponent<
|
||||
FunctionComponent<ComponentProps>
|
||||
> = lazy(() => {
|
||||
|
|
@ -176,6 +187,7 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
|||
</Suspense>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_INOPERATIONAL] || ""}
|
||||
element={
|
||||
|
|
@ -188,6 +200,31 @@ const MonitorRoutes: FunctionComponent<ComponentProps> = (
|
|||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkspaceConnectionSlack
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITORS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS] || ""}
|
||||
element={
|
||||
<Suspense fallback={Loader}>
|
||||
<WorkspaceConnectionTeams
|
||||
{...props}
|
||||
pageRoute={RouteMap[PageMap.MONITORS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS] as Route}
|
||||
/>
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
<PageRoute
|
||||
path={MonitorsRoutePath[PageMap.MONITOR_CREATE] || ""}
|
||||
element={
|
||||
|
|
|
|||
|
|
@ -11,6 +11,18 @@ export function getMonitorBreadcrumbs(path: string): Array<Link> | undefined {
|
|||
"Monitors",
|
||||
"Inoperational",
|
||||
]),
|
||||
//slack connection
|
||||
...BuildBreadcrumbLinksByTitles(PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK, [
|
||||
"Project",
|
||||
"Monitors",
|
||||
"Slack",
|
||||
]),
|
||||
// ms teams connection
|
||||
...BuildBreadcrumbLinksByTitles(PageMap.MONITORS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS, [
|
||||
"Project",
|
||||
"Monitors",
|
||||
"Microsoft Teams",
|
||||
]),
|
||||
...BuildBreadcrumbLinksByTitles(PageMap.MONITORS_DISABLED, [
|
||||
"Project",
|
||||
"Monitors",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ export const MonitorsRoutePath: Dictionary<string> = {
|
|||
[PageMap.MONITORS_DISABLED]: "disabled",
|
||||
[PageMap.MONITORS_PROBE_DISCONNECTED]: "probe-disconnected",
|
||||
[PageMap.MONITORS_PROBE_DISABLED]: "probe-disabled",
|
||||
[PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK]: "workspace-connection-slack",
|
||||
[PageMap.MONITORS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS]:
|
||||
"workspace-connection-microsoft-teams",
|
||||
|
||||
[PageMap.MONITOR_VIEW]: `${RouteParams.ModelID}`,
|
||||
[PageMap.MONITOR_VIEW_INTERVAL]: `${RouteParams.ModelID}/interval`,
|
||||
|
|
@ -327,6 +330,18 @@ const RouteMap: Dictionary<Route> = {
|
|||
}`,
|
||||
),
|
||||
|
||||
[PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/monitors/${
|
||||
MonitorsRoutePath[PageMap.MONITORS_WORKSPACE_CONNECTION_SLACK]
|
||||
}`,
|
||||
),
|
||||
|
||||
[PageMap.MONITORS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/monitors/${
|
||||
MonitorsRoutePath[PageMap.MONITORS_WORKSPACE_CONNECTION_MICROSOFT_TEAMS]
|
||||
}`,
|
||||
),
|
||||
|
||||
[PageMap.MONITOR_CREATE]: new Route(
|
||||
`/dashboard/${RouteParams.ProjectID}/monitors/${
|
||||
MonitorsRoutePath[PageMap.MONITOR_CREATE]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue