dashboard/shell/utils/alertmanagerconfig.js

182 lines
4.8 KiB
JavaScript

import jsyaml from 'js-yaml';
import { base64Decode, base64Encode } from '@shell/utils/crypto';
import { MONITORING, SECRET } from '@shell/config/types';
import { get, set } from '@shell/utils/object';
import isEmpty from 'lodash/isEmpty';
import { ROOT_NAME } from '@shell/models/monitoring.coreos.com.route';
/**
* Find secondary schema's related to the primary `monitoring.coreos.com.alertmanagerconfig` schema
*/
export const fetchAlertManagerConfigSpecs = async($store) => {
const schema = $store.getters['cluster/schemaFor'](MONITORING.ALERTMANAGERCONFIG);
if (!schema) {
return;
}
// Make the http request to fetch schema definitions for alertmanagerconfig
await schema.fetchResourceFields();
return {
receiverSchema: schema.schemaDefinitions?.[`${ schema.schemaDefinition.type }.spec.receivers`],
routeSchema: schema.schemaDefinitions?.[`${ schema.schemaDefinition.type }.spec.route`],
};
};
const DEFAULT_SECRET_ID = 'cattle-monitoring-system/alertmanager-rancher-monitoring-alertmanager';
const ALERTMANAGER_ID = 'cattle-monitoring-system/rancher-monitoring-alertmanager';
export const FILENAME = 'alertmanager.yaml';
export async function getSecretId(dispatch) {
const alertManager = await dispatch('cluster/find', { type: MONITORING.ALERTMANAGER, id: ALERTMANAGER_ID }, { root: true });
if (alertManager?.spec?.configSecret) {
return `${ alertManager.namespace }/${ alertManager?.spec?.configSecret }`;
}
return DEFAULT_SECRET_ID;
}
export async function getSecret(dispatch) {
const secretId = await getSecretId(dispatch, false);
try {
return await dispatch('cluster/find', { type: SECRET, id: secretId }, { root: true });
} catch (ex) {
const [namespace, name] = secretId.split('/');
const secret = await dispatch('cluster/create', { type: SECRET }, { root: true });
secret.metadata = {
namespace,
name
};
return secret;
}
}
function extractConfig(secret) {
secret.data = secret.data || {};
const file = secret.data[FILENAME];
const decodedFile = file ? base64Decode(file) : '{}';
const config = jsyaml.load(decodedFile);
config.receivers = config.receivers || [];
config.route = config.route || {};
config.route.routes = config.route.routes || [];
return config;
}
export async function loadConfig(dispatch) {
const secret = await getSecret(dispatch);
return {
config: extractConfig(secret),
secret
};
}
export async function updateConfig(dispatch, path, type, updateFn) {
const { config, secret } = await loadConfig(dispatch);
set(config, path, get(config, path) || []);
setDefaultRouteNames(config.route.routes);
const newValue = updateFn(get(config, path));
set(config, path, newValue);
const routes = config.route.routes;
const rootIndex = routes.findIndex((route) => route.name === ROOT_NAME);
routes.forEach((route) => {
if (route.name) {
delete route.name;
}
});
if (rootIndex >= 0) {
const rootRoute = routes.splice(rootIndex, 1)[0];
rootRoute.routes = routes;
config.route = rootRoute;
}
const newFile = jsyaml.dump(config);
const encodedFile = base64Encode(newFile);
secret.data[FILENAME] = encodedFile;
await secret.save();
}
export async function getAllReceivers(dispatch) {
try {
const { config, secret } = await loadConfig(dispatch);
const receivers = config.receivers || [];
const receiversWithName = receivers.filter((receiver) => receiver.name);
const mapped = receiversWithName.map((receiver) => dispatch('cluster/create', {
id: receiver.name,
spec: receiver,
type: MONITORING.SPOOFED.RECEIVER,
secret
}, { root: true }));
return Promise.all(mapped);
} catch (ex) {
return [];
}
}
export async function getAllRoutes(dispatch) {
try {
const { config, secret } = await loadConfig(dispatch);
config.route = config.route || {};
config.route.name = ROOT_NAME;
const routes = config.route?.routes || [];
setDefaultRouteNames(routes);
routes.push(config.route);
const mapped = routes.map((route) => dispatch('cluster/create', {
id: route.name,
spec: route,
type: MONITORING.SPOOFED.ROUTE,
secret
}, { root: true }));
return Promise.all(mapped);
} catch (ex) {
return [];
}
}
function setDefaultRouteNames(routes) {
routes.forEach((route, i) => {
route.name = route.name || createDefaultRouteName(i);
});
}
export function createDefaultRouteName(index) {
return `route-${ index }`;
}
export function areRoutesSupportedFormat(secret) {
try {
const config = extractConfig(secret);
const routes = config.route?.routes || [];
return !routes.some(isEmpty);
} catch (ex) {
return false;
}
}
export function canCreate(rootGetters) {
return rootGetters['type-map/optionsFor'](SECRET).isCreatable;
}