mongodb-data-service
Version:
MongoDB Data Service
221 lines • 9.52 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getInstance = getInstance;
exports.checkIsCSFLEConnection = checkIsCSFLEConnection;
exports.configuredKMSProviders = configuredKMSProviders;
exports.getPrivilegesByDatabaseAndCollection = getPrivilegesByDatabaseAndCollection;
exports.getDatabasesByRoles = getDatabasesByRoles;
exports.isNotAuthorized = isNotAuthorized;
exports.isNotSupportedPipelineStage = isNotSupportedPipelineStage;
exports.adaptBuildInfo = adaptBuildInfo;
exports.adaptDatabaseInfo = adaptDatabaseInfo;
exports.adaptCollectionInfo = adaptCollectionInfo;
const mongodb_build_info_1 = require("mongodb-build-info");
const mongodb_ns_1 = __importDefault(require("mongodb-ns"));
const run_command_1 = require("./run-command");
const logger_1 = require("./logger");
async function getInstance(client, uri) {
const adminDb = client.db('admin');
const [connectionStatus, hostInfoResult, buildInfoResult, getParameterResult, atlasVersionResult, isLocalAtlas,] = await Promise.all([
(0, run_command_1.runCommand)(adminDb, { connectionStatus: 1, showPrivileges: true }, { enableUtf8Validation: false }).catch(ignoreNotAuthorized(null)),
(0, run_command_1.runCommand)(adminDb, { hostInfo: 1 }, { enableUtf8Validation: false }).catch(ignoreNotAuthorized({})),
// This command should always pass, if it throws, somethings is really off.
// This is why it's the only one where we are not ignoring any types of
// errors
(0, run_command_1.runCommand)(adminDb, { buildInfo: 1 }, { enableUtf8Validation: false }),
// This command is only here to get data for the logs and telemetry, if it
// failed (e.g., not authorised or not supported) we should just ignore the
// failure
(0, run_command_1.runCommand)(adminDb, {
getParameter: 1,
featureCompatibilityVersion: 1,
}, { enableUtf8Validation: false }).catch(() => null),
(0, run_command_1.runCommand)(adminDb, { atlasVersion: 1 }, { enableUtf8Validation: false }).catch(() => {
return { atlasVersion: '', gitVersion: '' };
}),
(0, mongodb_build_info_1.isLocalAtlas)(async (db, collection, query) => {
return await client.db(db).collection(collection).countDocuments(query);
}),
]);
const isAtlas = !!atlasVersionResult.atlasVersion || (0, mongodb_build_info_1.isAtlas)(uri);
return {
auth: adaptAuthInfo(connectionStatus),
build: adaptBuildInfo(buildInfoResult),
host: adaptHostInfo(hostInfoResult),
genuineMongoDB: buildGenuineMongoDBInfo(uri),
dataLake: buildDataLakeInfo(buildInfoResult),
featureCompatibilityVersion: getParameterResult?.featureCompatibilityVersion.version ?? null,
isAtlas,
// If a user is connected to Cloud Atlas, its possible they can have
// admin.atlascli with data that mongo-build-info uses to check for
// local atlas. So we set isLocalAtlas to false in such cases.
isLocalAtlas: isAtlas ? false : isLocalAtlas,
};
}
function checkIsCSFLEConnection(client) {
return configuredKMSProviders(client.options?.autoEncryption).length > 0;
}
function configuredKMSProviders(autoEncryption) {
const kmsProviders = autoEncryption?.kmsProviders ?? {};
return Object.entries(kmsProviders)
.filter(([, kmsOptions]) => Object.values(kmsOptions ?? {}).filter(Boolean).length > 0)
.map(([kmsProviderName]) => kmsProviderName);
}
function buildGenuineMongoDBInfo(uri) {
const { isGenuine, serverName } = (0, mongodb_build_info_1.getGenuineMongoDB)(uri);
return {
isGenuine,
dbType: serverName,
};
}
function buildDataLakeInfo(buildInfo) {
const { isDataLake, dlVersion } = (0, mongodb_build_info_1.getDataLake)(buildInfo);
return {
isDataLake,
version: dlVersion,
};
}
function adaptAuthInfo(connectionStatus) {
if (connectionStatus === null) {
return { user: null, roles: [], privileges: [] };
}
const { authenticatedUsers, authenticatedUserRoles, authenticatedUserPrivileges, } = connectionStatus.authInfo;
return {
user: authenticatedUsers[0] ?? null,
roles: authenticatedUserRoles,
privileges: authenticatedUserPrivileges,
};
}
function getPrivilegesByDatabaseAndCollection(authenticatedUserPrivileges = null, requiredActions = null) {
const privileges = authenticatedUserPrivileges ?? [];
const filteredPrivileges = requiredActions && requiredActions.length > 0
? privileges.filter(({ actions }) => {
return requiredActions.every((action) => actions.includes(action));
})
: privileges;
const result = {};
for (const { resource, actions } of filteredPrivileges) {
// Documented resources include roles for dbs/colls, cluster, or in rare cases
// anyResource, additionally there seem to be undocumented ones like
// system_buckets and who knows what else. To make sure we are only cover
// cases that we can meaningfully handle here, roles for the
// databases/collections, we are skipping all roles where these are
// undefined
//
// See: https://docs.mongodb.com/manual/reference/resource-document/#std-label-resource-document
if (typeof resource.db !== 'undefined' &&
typeof resource.collection !== 'undefined') {
const { db, collection } = resource;
if (result[db]) {
Object.assign(result[db], { [collection]: actions });
}
else {
result[db] = { [collection]: actions };
}
}
}
return result;
}
// Return a list of the databases which have a role matching one of the roles.
function getDatabasesByRoles(authenticatedUserRoles = null, possibleRoles = null) {
const roles = authenticatedUserRoles ?? [];
const results = new Set();
const filteredRoles = possibleRoles && possibleRoles.length > 0
? roles.filter(({ role }) => {
return possibleRoles.includes(role);
})
: roles;
for (const { db } of filteredRoles) {
results.add(db);
}
return [...results];
}
function isNotAuthorized(err) {
if (!err) {
return false;
}
const msg = err.message || JSON.stringify(err);
return new RegExp('not (authorized|allowed)').test(msg);
}
function isNotSupportedPipelineStage(err) {
if (!err) {
return false;
}
const msg = err.message || JSON.stringify(err);
return msg.match(/Unrecognized pipeline stage name/);
}
function ignoreNotAuthorized(fallback) {
return (err) => {
if (isNotAuthorized(err)) {
(0, logger_1.debug)('ignoring not authorized error and returning fallback value:', {
err,
fallback,
});
return Promise.resolve(fallback);
}
return Promise.reject(err);
};
}
function adaptHostInfo(rawHostInfo) {
return {
os: rawHostInfo.os?.name,
os_family: rawHostInfo.os?.type
? rawHostInfo.os.type.toLowerCase()
: undefined,
kernel_version: rawHostInfo.os?.version,
kernel_version_string: rawHostInfo.extra?.versionString,
arch: rawHostInfo.system?.cpuArch,
memory_bits: (rawHostInfo.system?.memSizeMB ?? 0) * 1024 * 1024,
cpu_cores: rawHostInfo.system?.numCores,
cpu_frequency: parseInt(rawHostInfo.extra?.cpuFrequencyMHz || '0', 10) * 1_000_000,
};
}
function adaptBuildInfo(rawBuildInfo) {
return {
version: rawBuildInfo.version ?? '',
// Cover both cases of detecting enterprise module, see SERVER-18099.
isEnterprise: (0, mongodb_build_info_1.isEnterprise)(rawBuildInfo),
};
}
function adaptDatabaseInfo(databaseStats) {
return {
collection_count: databaseStats.collections ?? 0,
document_count: databaseStats.objects ?? 0,
index_count: databaseStats.indexes ?? 0,
storage_size: databaseStats.storageSize ?? 0,
data_size: databaseStats.dataSize ?? 0,
index_size: databaseStats.indexSize ?? 0,
};
}
function adaptCollectionInfo({ db, name, info, options, type, }) {
const ns = (0, mongodb_ns_1.default)(`${db}.${name}`);
const { collection, database, system, oplog, command, special, specialish, normal, } = ns;
const { readOnly } = info ?? {};
const { collation, viewOn, pipeline, validator, validationAction, validationLevel, clusteredIndex, encryptedFields, } = options ?? {};
const hasValidation = Boolean(validator || validationAction || validationLevel);
return {
_id: ns.toString(),
name: collection,
database,
system,
oplog,
command,
special,
specialish,
normal,
type: type ?? 'collection',
readonly: readOnly ?? false,
collation: collation ?? null,
view_on: viewOn ?? null,
pipeline: pipeline ?? null,
clustered: clusteredIndex ? true : false,
fle2: encryptedFields ? true : false,
validation: hasValidation
? { validator, validationAction, validationLevel }
: null,
};
}
//# sourceMappingURL=instance-detail-helper.js.map
;