@sap/cds-mtx
Advanced tools
Comparing version 1.0.5 to 1.0.7
@@ -9,2 +9,6 @@ # Change Log | ||
## [1.0.7] | ||
## [1.0.6] | ||
## [1.0.5] | ||
@@ -11,0 +15,0 @@ |
@@ -22,3 +22,4 @@ const Tenant = require('../../tenant/index'); | ||
const tenantIds = context.data.tenants; | ||
const status = await Tenant.updateBaseModel({}, tenantIds); | ||
const autoUndeploy = context.data.autoUndeploy; | ||
const status = await Tenant.updateBaseModel({}, tenantIds, autoUndeploy); | ||
return status; | ||
@@ -29,6 +30,7 @@ }); | ||
const tenantIds = context.data.tenants; | ||
const autoUndeploy = context.data.autoUndeploy; | ||
const jobExecutor = GlobalConnections.jobExecutor; | ||
const tenantId = context.attr.identityZone; | ||
const jobID = jobExecutor.submit(tenantId, Tenant.updateBaseModel, [tenantIds]); | ||
const jobID = jobExecutor.submit(tenantId, Tenant.updateBaseModel, [tenantIds, autoUndeploy]); | ||
@@ -35,0 +37,0 @@ context._.res.setHeader('Location', '/mtx/v1/model/status/' + jobID); |
@@ -11,20 +11,32 @@ const fs = require('fs-extra'); | ||
static async createTenant(tenant, instanceManager, templateDir, expectedTables = [], instanceManagerOptions = {}) { | ||
static async createTenant(tenant, instanceManager, templateDir, expectedTables = [], instanceManagerOptions = {}, retryOnPriorFailure = false) { | ||
logger.info('Creating tenant: ' + tenant); | ||
let credentials; | ||
let created = false; | ||
let instanceData; | ||
if (await this.tenantExists(tenant, instanceManager)) { | ||
logger.info('Tenant: ' + tenant + ' already exists'); | ||
credentials = await instanceManager.get(tenant); | ||
instanceData = await instanceManager.get(tenant); | ||
// retry if existing instance is faulty | ||
if (instanceData && instanceData.status === 'CREATION_FAILED') { | ||
if (retryOnPriorFailure) { | ||
logger.info('Found tenant is incomplete, creating again'); | ||
logger.debug(`Calling instance manager with tenant id ${tenant} and options ${JSON.stringify(instanceManagerOptions)}`); | ||
await instanceManager.delete(tenant); | ||
instanceData = await instanceManager.create(tenant, instanceManagerOptions); | ||
} | ||
} | ||
} else { | ||
logger.info('Tenant does not exist'); | ||
logger.debug(`Calling instance manager with tenant id ${tenant} and options ${JSON.stringify(instanceManagerOptions)}`); | ||
credentials = await instanceManager.create(tenant, instanceManagerOptions); | ||
created = true; | ||
instanceData = await instanceManager.create(tenant, instanceManagerOptions); | ||
} | ||
const redeploy = await this._redeployNeeded(tenant, credentials.credentials.schema, expectedTables); | ||
if (!instanceData || instanceData.status === 'CREATION_FAILED') { | ||
logger.debug(`Data returned from instance manager: ${instanceData ? JSON.stringify(instanceData) : 'undefined'}`) | ||
throw new Error('Tenant creation failed'); | ||
} | ||
const redeploy = await this._redeployNeeded(tenant, instanceData.credentials.schema, expectedTables); | ||
if(redeploy) { | ||
@@ -40,10 +52,7 @@ logger.debug('Redeployment is needed for tenant: ' + tenant); | ||
await DeployHelper.deployModel(tenant, dbSrcDir, credentials, false); | ||
await DeployHelper.deployModel(tenant, dbSrcDir, instanceData, false); | ||
created = true; | ||
} else { | ||
logger.debug('Redeployment is not needed for tenant: ' + tenant); | ||
} | ||
return { credentials, created }; | ||
} | ||
@@ -77,2 +86,14 @@ | ||
// check field type | ||
const contentType = await client.execute('SELECT DATA_TYPE_NAME FROM TABLE_COLUMNS ' + | ||
'WHERE TABLE_NAME = \'CUSTOM_TENANT_CONTENT\' and COLUMN_NAME = \'CONTENT\' and SCHEMA_NAME = ?', [ schema ]); | ||
logger.debug('Found datatype for custom data content: ' + contentType.DATA_TYPE_NAME); | ||
if (contentType[0] && (contentType[0].DATA_TYPE_NAME !== 'NCLOB')) { | ||
logger.log('Datatype of CUSTOM_TENANT_CONTENT has changed, redeployment will done'); | ||
redeploy = true; | ||
} | ||
await session.release(client); | ||
@@ -79,0 +100,0 @@ |
@@ -29,3 +29,4 @@ const SidecarDataAdaptor = require('./sidecar_data_adaptor'); | ||
this._client = await session.acquire({ attr: { identityZone: tenantMetaID }}); | ||
this._client = await session.acquire({attr: {identityZone: tenantMetaID}}); | ||
this.logger.debug('Session started for: ' + tenantId); | ||
@@ -40,4 +41,7 @@ } | ||
async _createTenant(tenantMetaID, instanceManager, templateDir, tenantMetaTables, instanceManagerOptions, retryOnPriorFailure) { | ||
return CommonHdiAdaptor.createTenant(tenantMetaID, instanceManager, templateDir, tenantMetaTables, instanceManagerOptions, retryOnPriorFailure); | ||
} | ||
async onboardTenant(tenant, tenantMetadata) { | ||
async onboardTenant(tenant, tenantMetadata, retryOnPriorFailure) { | ||
this.logger.info('Onboarding new tenant: ' + tenant); | ||
@@ -49,8 +53,5 @@ | ||
const { created } = await CommonHdiAdaptor.createTenant(tenantMetaID, this._instanceManager, TEMPLATE_DIR, TENANT_META_TABLES, instanceManagerOptions); | ||
return created; | ||
await this._createTenant(tenantMetaID, this._instanceManager, TEMPLATE_DIR, TENANT_META_TABLES, instanceManagerOptions, retryOnPriorFailure); | ||
} | ||
async saveBaseModel(domain) { | ||
@@ -57,0 +58,0 @@ const deleteQuery = 'DELETE FROM TENANT_FILES WHERE TYPE = ? AND DOMAIN = ?'; |
@@ -33,3 +33,3 @@ const Logger = require('../../helper/logger'); | ||
await CommonHDIAdaptor.createTenant(this.globalDataMetaTenant, instanceManager, TEMPLATE_DIR, META_TABLES); | ||
await CommonHDIAdaptor.createTenant(this.globalDataMetaTenant, instanceManager, TEMPLATE_DIR, META_TABLES, {}, true); | ||
} | ||
@@ -72,3 +72,6 @@ | ||
static async onboardTenant(tenant, tenantMetadata) { | ||
static async onboardTenant(tenant, tenantMetadata, retryOnPriorFailure) { | ||
let instanceManagerOptions = hdiHelper.getInstanceManagerOptions(tenantMetadata); | ||
logger.info('Onboarding tenant: ' + tenant); | ||
@@ -78,12 +81,19 @@ const instanceManager = await this._getInstanceManager(); | ||
if(await CommonHDIAdaptor.tenantExists(tenant, instanceManager)) { | ||
const tenantCredentials = await instanceManager.get(tenant); | ||
let instanceData = await instanceManager.get(tenant); | ||
logger.info('Tenant already exists'); | ||
return tenantCredentials; | ||
// retry if existing instance is faulty | ||
if (instanceData && instanceData.status === 'CREATION_FAILED') { | ||
if (retryOnPriorFailure) { | ||
logger.info('Found tenant is incomplete, creating again'); | ||
logger.debug(`Calling instance manager with tenant id ${tenant} and options ${JSON.stringify(instanceManagerOptions)}`); | ||
await instanceManager.delete(tenant); | ||
instanceData = await instanceManager.create(tenant, instanceManagerOptions); | ||
} | ||
} | ||
return instanceData; | ||
} | ||
let instanceManagerOptions = hdiHelper.getInstanceManagerOptions(tenantMetadata); | ||
logger.info('Tenant does not exists, creating'); | ||
logger.debug(`Calling instance manager with tenant id ${tenant} and options ${JSON.stringify(instanceManagerOptions)}`); | ||
return await instanceManager.create(tenant, instanceManagerOptions); | ||
return instanceManager.create(tenant, instanceManagerOptions); | ||
} | ||
@@ -135,4 +145,4 @@ | ||
static async deploy(tenant, dbDir, tenantCredentials, autoUndeploy, undeployWhitelist) { | ||
await DeployHelper.deployModel(tenant, dbDir, tenantCredentials, autoUndeploy, undeployWhitelist); | ||
static async deploy(tenant, dbDir, tenantCredentials, autoUndeploy, undeployWhitelist, logCollector) { | ||
await DeployHelper.deployModel(tenant, dbDir, tenantCredentials, autoUndeploy, undeployWhitelist, logCollector); | ||
} | ||
@@ -139,0 +149,0 @@ |
const cds = require('../cds'); | ||
const Logger = require('./logger'); | ||
const logger = new Logger('BUILD'); | ||
const path = require('path'); | ||
@@ -14,4 +13,7 @@ | ||
static async build(projectPath) { | ||
static async build(projectPath, logCollector) { | ||
const buildLogger = new Logger('BUILD', logCollector); | ||
buildLogger.logLevel = Logger.LOG_LEVEL.debug; | ||
const buildOptions = { | ||
@@ -36,3 +38,3 @@ root: projectPath, | ||
const tasks = await this._getBuildTasks(buildOptions); | ||
const tasks = await this._getBuildTasks(buildOptions, buildLogger); | ||
let buildResult; | ||
@@ -44,5 +46,5 @@ | ||
} | ||
buildResult = await new BuildTaskEngine(logger).processTasks(tasks, buildOptions); | ||
buildResult = await new BuildTaskEngine(buildLogger).processTasks(tasks, buildOptions); | ||
} catch (e) { | ||
this._alignLocation(e, projectPath); | ||
this._alignLocation(e, projectPath, buildLogger); | ||
throw e; | ||
@@ -58,3 +60,3 @@ } | ||
let _csn_node = {}; | ||
let _hdbcds = []; | ||
let _hana = []; | ||
@@ -70,3 +72,3 @@ buildResult.forEach(taskResult => { | ||
_dbDir = taskResult.result.dest; | ||
_hdbcds = taskResult.result.hdbcds; | ||
_hana = taskResult.result.hana || taskResult.result.hdbcds; | ||
} | ||
@@ -86,3 +88,3 @@ if (taskResult.task.for === BUILD_TASK_NODE) { | ||
dbDir: _dbDir, | ||
hdbcds: _hdbcds, | ||
hana: _hana, | ||
csn: _csn, | ||
@@ -97,3 +99,3 @@ edmx: _edmx, | ||
static async _getBuildTasks(buildOptions) { | ||
static async _getBuildTasks(buildOptions, logger) { | ||
@@ -149,3 +151,3 @@ | ||
static _alignLocation(error, projectPath) { | ||
static _alignLocation(error, projectPath, logger) { | ||
if (!error.errors) { | ||
@@ -152,0 +154,0 @@ return; |
@@ -6,3 +6,2 @@ const CONSTANTS = require('../../config/constants'); | ||
const Logger = require('./logger'); | ||
const logger = new Logger('DEPLOY_HELPER'); | ||
@@ -12,3 +11,7 @@ class DeployHelper { | ||
static async deployModel(tenantId, dbDir, instanceCredentials, undeploy = false, undeployWhitelist = []) { | ||
static async deployModel(tenantId, dbDir, instanceCredentials, undeploy = false, undeployWhitelist = [], logCollector = null) { | ||
const logger = new Logger('DEPLOY_HELPER'); | ||
logger.logCollector = logCollector; | ||
if(!dbDir) { | ||
@@ -26,11 +29,11 @@ logger.info('No db dir set - skipping deployment'); | ||
await this._deployModelInternal(dbDir, instanceCredentials, undeploy, undeployWhitelist); | ||
await this._deployModelInternal(dbDir, instanceCredentials, undeploy, undeployWhitelist, logger); | ||
} | ||
static async _deployModelInternal(dbDir, instanceCredentials, undeploy, undeployWhitelist) { | ||
static async _deployModelInternal(dbDir, instanceCredentials, undeploy, undeployWhitelist, logger) { | ||
if(undeploy) { | ||
logger.debug('Writing undeploy.json because undeploy=true'); | ||
await DeployHelper._writeUndeployJson(dbDir, undeployWhitelist); | ||
await DeployHelper._writeUndeployJson(dbDir, undeployWhitelist, logger); | ||
} else { | ||
@@ -44,3 +47,3 @@ logger.debug('Not writing undeploy.json because undeploy=false'); | ||
await this._deployPromise(dbDir, deployerEnv); | ||
await this._deployPromise(dbDir, deployerEnv, logger); | ||
@@ -52,3 +55,3 @@ logger.info('--------------------------------[HDI-DEPLOY-OUTPUT]---------------'); | ||
static async _writeUndeployJson(dbDir, undeployWhitelist) { | ||
static async _writeUndeployJson(dbDir, undeployWhitelist, logger) { | ||
const undeployPath = path.join(dbDir, 'undeploy.json'); | ||
@@ -84,3 +87,3 @@ let undeployWhitelistToWrite = undeployWhitelist; | ||
static _deployPromise(dir, env) { | ||
static _deployPromise(dir, env, logger) { | ||
return new Promise((resolve, reject) => { | ||
@@ -87,0 +90,0 @@ deploy(dir, env, (error, response) => { |
@@ -25,10 +25,12 @@ const InstanceManagerFactory = require('./cf/instance_manager_factory'); | ||
static async _getBasemodelPath() { | ||
const genSdcPath = path.join(process.cwd(), 'gen', 'sdc'); | ||
if(await fs.exists(genSdcPath)) { | ||
return genSdcPath; | ||
} | ||
const validSdcPaths = [ | ||
path.join(process.cwd(), 'gen', 'sdc'), | ||
path.join(process.cwd(), 'sdc'), | ||
path.join(process.cwd(), 'gen', 'src', 'sdc') // needed only for local test scenario | ||
]; | ||
const sdcPath = path.join(process.cwd(), 'sdc'); | ||
if(await fs.exists(sdcPath)) { | ||
return sdcPath; | ||
for (let sdcPath of validSdcPaths) { | ||
if (await fs.exists(sdcPath)) { | ||
return sdcPath; | ||
} | ||
} | ||
@@ -35,0 +37,0 @@ } |
@@ -17,2 +17,6 @@ const SecurityHelper = require('./security_helper'); | ||
static getEtag(timestamps) { | ||
return `"${this._getHash(timestamps)}"`; | ||
} | ||
static _getHash(timestamps) { | ||
if (timestamps) { | ||
@@ -19,0 +23,0 @@ const timestampString = timestamps.join('|'); |
@@ -26,5 +26,6 @@ /* eslint-disable no-console */ | ||
constructor(component) { | ||
constructor(component, collector) { | ||
super(process.stdout, process.stderr); | ||
this._component = component; | ||
this._collector = collector; | ||
let configuredLogLevel = Env.getValueOrDefault('LOG_LEVEL', DEFAULT_LOG_LEVEL); | ||
@@ -68,3 +69,7 @@ if (process.env.DEBUG) { | ||
if (this._logLevel >= severity.value) { | ||
console.log(this._formatMessage(message, severity), ...args); | ||
const formattedMessage = this._formatMessage(message, severity); | ||
console.log(formattedMessage, ...args); | ||
if (this._collector) { | ||
this._collector.log(formattedMessage, ...args); | ||
} | ||
} | ||
@@ -83,3 +88,7 @@ } | ||
} | ||
console.error(this._formatMessage(errorString, LOG_LEVEL.error), ...args); | ||
const formattedMessage = this._formatMessage(errorString, LOG_LEVEL.error); | ||
console.error(formattedMessage, ...args); | ||
if (this._collector) { | ||
this._collector.log(formattedMessage, ...args); | ||
} | ||
} | ||
@@ -94,2 +103,13 @@ | ||
set logCollector(collector) { | ||
this._collector = collector; | ||
} | ||
set logLevel(level) { | ||
this._logLevel = level.value; | ||
} | ||
static get LOG_LEVEL() { | ||
return LOG_LEVEL; | ||
} | ||
} | ||
@@ -96,0 +116,0 @@ |
@@ -9,2 +9,4 @@ const path = require('path'); | ||
const GlobalConnections = require('./helper/global_connections'); | ||
let interval; | ||
@@ -114,2 +116,7 @@ | ||
return model; | ||
}, | ||
shutdown: async () => { | ||
GlobalConnections.jobExecutor.stop(); | ||
clearInterval(interval); | ||
} | ||
@@ -116,0 +123,0 @@ } |
@@ -42,3 +42,7 @@ const Logger = require('../helper/logger'); | ||
stop() { | ||
clearInterval(this._queueInterval); | ||
} | ||
async _runQueue() { | ||
@@ -45,0 +49,0 @@ this._logger.debug('Checking queue'); |
const Logger = require('../helper/logger'); | ||
const LogCollector = require('../helper/log_collector'); | ||
const logger = new Logger('TENANT'); | ||
@@ -28,4 +29,4 @@ const FileSystemHelper = require('../helper/file_system_helper'); | ||
const [tenantCredentials] = await Promise.all([ | ||
GlobalConnections.tenantDataAdaptor.onboardTenant(tenantId, tenantMetadata), | ||
sidecarDataAdaptor.onboardTenant(tenantId, tenantMetadata) | ||
GlobalConnections.tenantDataAdaptor.onboardTenant(tenantId, tenantMetadata, true), | ||
sidecarDataAdaptor.onboardTenant(tenantId, tenantMetadata, true) | ||
]); | ||
@@ -42,2 +43,4 @@ | ||
await sidecarDataAdaptor.destroy(); | ||
await cds.connect(); | ||
} | ||
@@ -184,3 +187,3 @@ | ||
static async updateBaseModel(status, tenantsToUpdate) { | ||
static async updateBaseModel(status, tenantsToUpdate, autoUndeploy) { | ||
@@ -194,3 +197,3 @@ if (!tenantsToUpdate || !Array.isArray(tenantsToUpdate)) { | ||
logger.debug(`Upgrading tenants: ${tenantsToUpdate}`); | ||
logger.debug(`Upgrading tenants: ${tenantsToUpdate} with auto-undeploy=${autoUndeploy}`); | ||
status.tenants = {}; | ||
@@ -210,5 +213,11 @@ | ||
let sidecarDataAdaptorFactory = await GlobalConnections.getSidecarDataAdaptorFactory(); | ||
let logCollector; | ||
if (process.env.MTX_COLLECT_LOGS) { | ||
logCollector = new LogCollector(); | ||
} | ||
try { | ||
// update base model cached by SDAF | ||
@@ -218,3 +227,3 @@ sidecarDataAdaptorFactory.updateBaseModel(); | ||
const sidecarDataAdaptor = sidecarDataAdaptorFactory.createInstance(); | ||
await sidecarDataAdaptor.onboardTenant(tenant); // to be sure | ||
await sidecarDataAdaptor.onboardTenant(tenant); // to be sure, also does a check of the metatenant tables | ||
await sidecarDataAdaptor.begin(tenant); | ||
@@ -227,3 +236,3 @@ | ||
const compileBaseDir = await sidecarDataAdaptor.prepareCompileDir(getDomain(), true); | ||
await Tenant._compileAndDeployModels(sidecarDataAdaptor, compileBaseDir, tenant, tenantCredentials, false); | ||
await Tenant._compileAndDeployModels(sidecarDataAdaptor, compileBaseDir, tenant, tenantCredentials, autoUndeploy, logCollector); | ||
@@ -234,8 +243,7 @@ await sidecarDataAdaptor.destroy(); | ||
status.tenants[tenant] = { status: 'SUCCESS', message: '' }; | ||
status.tenants[tenant] = { status: 'SUCCESS', message: '', buildLogs: logCollector ? logCollector.logs : null }; | ||
logger.debug('Successfully upgraded tenant: ' + tenant); | ||
} catch (error) { | ||
logger.error(error); | ||
status.tenants[tenant] = { status: 'FAILURE', message: error.toString() }; | ||
status.tenants[tenant] = { status: 'FAILURE', message: error.toString(), buildLogs: logCollector ? logCollector.logs : null }; | ||
} | ||
@@ -248,5 +256,5 @@ } | ||
static async _compileAndDeployModels(sidecarDataAdaptor, projectPath, tenantId, tenantCredentials, autoUndeploy = false) { | ||
static async _compileAndDeployModels(sidecarDataAdaptor, projectPath, tenantId, tenantCredentials, autoUndeploy = false, logCollector = null) { | ||
const { dbDir, hdbcds, languages, services, edmx, csn, csn_node } = await BuildHelper.build(projectPath); | ||
const { dbDir, hana, languages, services, edmx, csn, csn_node } = await BuildHelper.build(projectPath, logCollector); | ||
const compiledFiles = new Map([[COMPILED_FILES.CSN_NODE, csn_node], [COMPILED_FILES.CSN, csn], ...edmx]); | ||
@@ -257,5 +265,5 @@ | ||
const undeployWhitelist = await sidecarDataAdaptor.getUndeployWhitelist(getDomain()); | ||
await GlobalConnections.tenantDataAdaptor.deploy(tenantId, dbDir, tenantCredentials, autoUndeploy, undeployWhitelist); | ||
await GlobalConnections.tenantDataAdaptor.deploy(tenantId, dbDir, tenantCredentials, autoUndeploy, undeployWhitelist, logCollector); | ||
await sidecarDataAdaptor.saveCompiledFiles(compiledFiles, getDomain()); | ||
await sidecarDataAdaptor.saveUndeployWhitelist(hdbcds, getDomain(), autoUndeploy); | ||
await sidecarDataAdaptor.saveUndeployWhitelist(hana, getDomain(), autoUndeploy); | ||
} | ||
@@ -288,8 +296,13 @@ | ||
logger.debug('Get model: ' + model + ' for tenant: ' + tenantId); | ||
const sidecarDataAdaptor = (await GlobalConnections.getSidecarDataAdaptorFactory()).createInstance(); | ||
await sidecarDataAdaptor.begin(tenantId); | ||
const loadedModel = await sidecarDataAdaptor.getModel(model, getDomain(), attributes); | ||
await sidecarDataAdaptor.destroy(); | ||
try { | ||
const sidecarDataAdaptor = (await GlobalConnections.getSidecarDataAdaptorFactory()).createInstance(); | ||
await sidecarDataAdaptor.begin(tenantId); | ||
const loadedModel = await sidecarDataAdaptor.getModel(model, getDomain(), attributes); | ||
await sidecarDataAdaptor.destroy(); | ||
return loadedModel; | ||
return loadedModel; | ||
} catch (e) { | ||
logger.error(e); | ||
throw new Error(`Could not get model for tenant ${tenantId}. Tenant might not be onboarded yet.`); | ||
} | ||
} | ||
@@ -296,0 +309,0 @@ |
{ | ||
"name": "@sap/cds-mtx", | ||
"version": "1.0.5", | ||
"version": "1.0.7", | ||
"lockfileVersion": 1, | ||
@@ -5,0 +5,0 @@ "requires": true, |
@@ -1,1 +0,1 @@ | ||
{"bundleDependencies":false,"dependencies":{"fs-extra":"8.1.0"},"deprecated":false,"description":"## https://cap.cloud.sap/ ## https://cap.cloud.sap/docs/guides/extensibility","keywords":["cds","cdx","extension"],"main":"lib/index.js","name":"@sap/cds-mtx","version":"1.0.5","license":"SEE LICENSE IN developer-license-3.1.txt"} | ||
{"bundleDependencies":false,"dependencies":{"fs-extra":"8.1.0"},"deprecated":false,"description":"## https://cap.cloud.sap/ ## https://cap.cloud.sap/docs/guides/extensibility","keywords":["cds","cdx","extension"],"main":"lib/index.js","name":"@sap/cds-mtx","version":"1.0.7","license":"SEE LICENSE IN developer-license-3.1.txt"} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
151055
61
2469
11