UNPKG

mongodb-data-service

Version:
221 lines • 9.52 kB
"use strict"; 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