Skip to content
Draft
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@adobe/aio-lib-core-config": "^5",
"@adobe/aio-lib-core-logging": "^3",
"@adobe/aio-lib-core-networking": "^5",
"@adobe/aio-lib-db": "^0.1.0-beta.4",
"@adobe/aio-lib-env": "^3",
"@adobe/aio-lib-ims": "^7",
"@adobe/aio-lib-runtime": "^7.1.3",
Expand Down
75 changes: 75 additions & 0 deletions src/commands/app/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const {
getFilesCountWithExtension
} = require('../../lib/app-helper')
const rtLib = require('@adobe/aio-lib-runtime')
const dbLib = require('@adobe/aio-lib-db')
const { DB_STATUS } = require('../../lib/defaults')
const LogForwarding = require('../../lib/log-forwarding')
const { sendAppAssetsDeployedAuditLog, sendAppDeployAuditLog } = require('../../lib/audit-logger')
const { setRuntimeApiHostAndAuthHandler, getAccessToken } = require('../../lib/auth-helper')
Expand Down Expand Up @@ -204,6 +206,11 @@ class Deploy extends BuildCommand {
this.error(err)
}

// provision database if configured
if (config.manifest?.full?.database?.['auto-provision'] === true) {
await this.provisionDatabase(config, spinner, flags)
}

if (flags.actions) {
if (config.app.hasBackend) {
let filterEntities
Expand Down Expand Up @@ -300,6 +307,74 @@ class Deploy extends BuildCommand {
}
}

async provisionDatabase (config, spinner, flags) {
const { namespace, auth } = config.ow || {}
if (!(namespace && auth)) {
throw new Error('Database deployment requires OW auth configuration.')
}
const region = config.manifest?.full?.database?.region
const regionMess = region ? `'${region}'` : 'default'

const progress = ({ next = undefined, status = undefined, verboseOnly = false }, statusMethod = spinner.info) => {
if (flags.verbose) {
const method = statusMethod.bind(spinner)
method(status)
spinner.start(next)
} else if (next && !verboseOnly) {
spinner.text = next
}
}

let provRes
try {
spinner.start(`Deploying database in the ${regionMess} region...`)

const db = await dbLib.init({ ow: { namespace, auth }, region })
progress({ next: 'Checking existing database deployment status...', verboseOnly: true })

let prevStatus
let statusRegion
const next = `Submitting database provisioning request in the ${regionMess} region...`
try {
const statusRes = await db.provisionStatus()
prevStatus = statusRes.status.toUpperCase()
statusRegion = statusRes.region
const regionMessage = statusRegion ? ` in region '${statusRegion}'` : ''
progress({ status: chalk.dim(`Existing database provisioning status: ${prevStatus}${regionMessage}`), next })
} catch (err) {
progress({ status: chalk.red(`Database status check failed: ${err.message}`), next }, spinner.warn)
prevStatus = null
}

if (prevStatus === DB_STATUS.PROVISIONED) {
spinner.succeed(chalk.green(`Database is deployed and ready for use in the '${statusRegion}' region`))
return
} else if (prevStatus === DB_STATUS.REQUESTED || prevStatus === DB_STATUS.PROCESSING) {
spinner.succeed(chalk.green(`Database provisioning request has already been submitted in the '${statusRegion}' region and is pending`))
return
}

provRes = await db.provisionRequest()
progress({ status: chalk.dim(`Database provisioning result:\n${JSON.stringify(provRes, null, 2)}`) })
} catch (error) {
spinner.fail(chalk.red('Database deployment failed'))
throw error
}

const resultStatus = provRes?.status?.toUpperCase() || DB_STATUS.UNKNOWN
if (resultStatus === DB_STATUS.PROVISIONED) {
spinner.succeed(chalk.green(`Database is deployed and ready for use in the '${provRes.region}' region`))
} else if (resultStatus === DB_STATUS.REQUESTED || resultStatus === DB_STATUS.PROCESSING) {
spinner.succeed(chalk.green(`Database provisioning request submitted in the '${provRes.region}' region, database deployment is now pending`))
} else if (resultStatus === DB_STATUS.FAILED || resultStatus === DB_STATUS.REJECTED) {
const message = `Database provisioning request failed with status '${resultStatus}'`
spinner.fail(chalk.red(message))
throw new Error(`${message}: ${provRes.message || 'Unknown error'}`)
} else {
spinner.warn(chalk.yellow(`Database provisioning request returned unexpected status '${resultStatus}', an update to the aio cli tool may be necessary.`))
}
}

async publishExtensionPoints (deployConfigs, aioConfig, force) {
const libConsoleCLI = await this.getLibConsoleCLI()

Expand Down
13 changes: 12 additions & 1 deletion src/lib/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,16 @@ module.exports = {
EXTENSIONS_CONFIG_KEY: 'extensions',
// Adding tracking file constants
LAST_BUILT_ACTIONS_FILENAME: 'last-built-actions.json',
LAST_DEPLOYED_ACTIONS_FILENAME: 'last-deployed-actions.json'
LAST_DEPLOYED_ACTIONS_FILENAME: 'last-deployed-actions.json',
// Database constants
DB_STATUS: {
PROVISIONED: 'PROVISIONED',
REQUESTED: 'REQUESTED',
PROCESSING: 'PROCESSING',
FAILED: 'FAILED',
REJECTED: 'REJECTED',
NOT_PROVISIONED: 'NOT_PROVISIONED',
DELETED: 'DELETED',
UNKNOWN: 'UNKNOWN'
}
}
Loading