Merge pull request #851 from Budibase/turn-off-invalidation
remove cf invalidation, adding validation around successful deploys only
This commit is contained in:
commit
a1645db1f2
|
@ -44,6 +44,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
fetchDeployments()
|
||||||
poll = setInterval(fetchDeployments, POLL_INTERVAL)
|
poll = setInterval(fetchDeployments, POLL_INTERVAL)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -55,10 +56,12 @@
|
||||||
<header>
|
<header>
|
||||||
<h4>Deployment History</h4>
|
<h4>Deployment History</h4>
|
||||||
<div class="deploy-div">
|
<div class="deploy-div">
|
||||||
<a target="_blank" href={`https://${appId}.app.budi.live/${appId}`}>
|
{#if deployments.some(deployment => deployment.status === 'SUCCESS')}
|
||||||
View Your Deployed App →
|
<a target="_blank" href={`https://${appId}.app.budi.live/${appId}`}>
|
||||||
</a>
|
View Your Deployed App →
|
||||||
<Button primary on:click={() => modal.show()}>View webhooks</Button>
|
</a>
|
||||||
|
<Button primary on:click={() => modal.show()}>View webhooks</Button>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="deployment-list">
|
<div class="deployment-list">
|
||||||
|
|
|
@ -17,19 +17,16 @@
|
||||||
$: appId = $store.appId
|
$: appId = $store.appId
|
||||||
|
|
||||||
async function deployApp() {
|
async function deployApp() {
|
||||||
loading = true
|
|
||||||
const DEPLOY_URL = `/api/deploy`
|
const DEPLOY_URL = `/api/deploy`
|
||||||
|
|
||||||
try {
|
try {
|
||||||
notifier.info("Starting Deployment..")
|
notifier.info(`Deployment started. Please wait.`)
|
||||||
const response = await api.post(DEPLOY_URL)
|
const response = await api.post(DEPLOY_URL)
|
||||||
const json = await response.json()
|
const json = await response.json()
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error()
|
throw new Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
notifier.info(`Deployment started. Please wait.`)
|
|
||||||
loading = false
|
|
||||||
analytics.captureEvent("Deployed App", {
|
analytics.captureEvent("Deployed App", {
|
||||||
appId,
|
appId,
|
||||||
})
|
})
|
||||||
|
@ -43,7 +40,6 @@
|
||||||
})
|
})
|
||||||
analytics.captureException(err)
|
analytics.captureException(err)
|
||||||
notifier.danger("Deployment unsuccessful. Please try again later.")
|
notifier.danger("Deployment unsuccessful. Please try again later.")
|
||||||
loading = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -51,13 +47,7 @@
|
||||||
<section>
|
<section>
|
||||||
<div>
|
<div>
|
||||||
<h4>It's time to shine!</h4>
|
<h4>It's time to shine!</h4>
|
||||||
<Button secondary medium on:click={deployApp}>
|
<Button secondary medium on:click={deployApp}>Deploy App</Button>
|
||||||
Deploy App
|
|
||||||
{#if loading}
|
|
||||||
<Spacer extraSmall />
|
|
||||||
<Spinner size="10" />
|
|
||||||
{/if}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
src="/_builder/assets/deploy-rocket.jpg"
|
src="/_builder/assets/deploy-rocket.jpg"
|
||||||
|
|
|
@ -12,7 +12,7 @@ JWT_SECRET={{cookieKey1}}
|
||||||
PORT=4001
|
PORT=4001
|
||||||
|
|
||||||
# error level for koa-pino
|
# error level for koa-pino
|
||||||
LOG_LEVEL=error
|
LOG_LEVEL=info
|
||||||
|
|
||||||
DEPLOYMENT_CREDENTIALS_URL="https://dt4mpwwap8.execute-api.eu-west-1.amazonaws.com/prod/"
|
DEPLOYMENT_CREDENTIALS_URL="https://dt4mpwwap8.execute-api.eu-west-1.amazonaws.com/prod/"
|
||||||
DEPLOYMENT_DB_URL="https://couchdb.budi.live:5984"
|
DEPLOYMENT_DB_URL="https://couchdb.budi.live:5984"
|
||||||
|
|
|
@ -2,46 +2,11 @@ const fs = require("fs")
|
||||||
const { join } = require("../../../utilities/centralPath")
|
const { join } = require("../../../utilities/centralPath")
|
||||||
const AWS = require("aws-sdk")
|
const AWS = require("aws-sdk")
|
||||||
const fetch = require("node-fetch")
|
const fetch = require("node-fetch")
|
||||||
const uuid = require("uuid")
|
|
||||||
const sanitize = require("sanitize-s3-objectkey")
|
const sanitize = require("sanitize-s3-objectkey")
|
||||||
const { budibaseAppsDir } = require("../../../utilities/budibaseDir")
|
const { budibaseAppsDir } = require("../../../utilities/budibaseDir")
|
||||||
const PouchDB = require("../../../db")
|
const PouchDB = require("../../../db")
|
||||||
const env = require("../../../environment")
|
const env = require("../../../environment")
|
||||||
|
|
||||||
async function invalidateCDN(cfDistribution, appId) {
|
|
||||||
const cf = new AWS.CloudFront({})
|
|
||||||
const resp = await cf
|
|
||||||
.createInvalidation({
|
|
||||||
DistributionId: cfDistribution,
|
|
||||||
InvalidationBatch: {
|
|
||||||
CallerReference: `${appId}-${uuid.v4()}`,
|
|
||||||
Paths: {
|
|
||||||
Quantity: 1,
|
|
||||||
Items: [`/assets/${appId}/*`],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.promise()
|
|
||||||
return resp.Invalidation.Id
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.isInvalidationComplete = async function(
|
|
||||||
distributionId,
|
|
||||||
invalidationId
|
|
||||||
) {
|
|
||||||
if (distributionId == null || invalidationId == null) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const cf = new AWS.CloudFront({})
|
|
||||||
const resp = await cf
|
|
||||||
.getInvalidation({
|
|
||||||
DistributionId: distributionId,
|
|
||||||
Id: invalidationId,
|
|
||||||
})
|
|
||||||
.promise()
|
|
||||||
return resp.Invalidation.Status === "Completed"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finalises the deployment, updating the quota for the user API key
|
* Finalises the deployment, updating the quota for the user API key
|
||||||
* The verification process returns the levels to update to.
|
* The verification process returns the levels to update to.
|
||||||
|
@ -162,12 +127,7 @@ async function prepareUploadForS3({ s3Key, metadata, s3, file }) {
|
||||||
|
|
||||||
exports.prepareUploadForS3 = prepareUploadForS3
|
exports.prepareUploadForS3 = prepareUploadForS3
|
||||||
|
|
||||||
exports.uploadAppAssets = async function({
|
exports.uploadAppAssets = async function({ appId, bucket, accountId }) {
|
||||||
appId,
|
|
||||||
bucket,
|
|
||||||
cfDistribution,
|
|
||||||
accountId,
|
|
||||||
}) {
|
|
||||||
const s3 = new AWS.S3({
|
const s3 = new AWS.S3({
|
||||||
params: {
|
params: {
|
||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
|
@ -224,8 +184,7 @@ exports.uploadAppAssets = async function({
|
||||||
db.put(fileUploads)
|
db.put(fileUploads)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Promise.all(uploads)
|
return await Promise.all(uploads)
|
||||||
return await invalidateCDN(cfDistribution, appId)
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error uploading budibase app assets to s3", err)
|
console.error("Error uploading budibase app assets to s3", err)
|
||||||
throw err
|
throw err
|
||||||
|
|
|
@ -4,7 +4,6 @@ const {
|
||||||
uploadAppAssets,
|
uploadAppAssets,
|
||||||
verifyDeployment,
|
verifyDeployment,
|
||||||
updateDeploymentQuota,
|
updateDeploymentQuota,
|
||||||
isInvalidationComplete,
|
|
||||||
} = require("./aws")
|
} = require("./aws")
|
||||||
const { DocumentTypes, SEPARATOR, UNICODE_MAX } = require("../../../db/utils")
|
const { DocumentTypes, SEPARATOR, UNICODE_MAX } = require("../../../db/utils")
|
||||||
const newid = require("../../../db/newid")
|
const newid = require("../../../db/newid")
|
||||||
|
@ -20,12 +19,10 @@ const DeploymentStatus = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks that deployments are in a good state, any pending will be updated
|
// checks that deployments are in a good state, any pending will be updated
|
||||||
async function checkAllDeployments(deployments, user) {
|
async function checkAllDeployments(deployments) {
|
||||||
let updated = false
|
let updated = false
|
||||||
function update(deployment, status) {
|
function update(deployment, status) {
|
||||||
deployment.status = status
|
deployment.status = status
|
||||||
delete deployment.invalidationId
|
|
||||||
delete deployment.cfDistribution
|
|
||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,37 +34,6 @@ async function checkAllDeployments(deployments, user) {
|
||||||
) {
|
) {
|
||||||
update(deployment, DeploymentStatus.FAILURE)
|
update(deployment, DeploymentStatus.FAILURE)
|
||||||
}
|
}
|
||||||
// if pending but not past failure point need to update them
|
|
||||||
else if (deployment.status === DeploymentStatus.PENDING) {
|
|
||||||
let complete = false
|
|
||||||
try {
|
|
||||||
complete = await isInvalidationComplete(
|
|
||||||
deployment.cfDistribution,
|
|
||||||
deployment.invalidationId
|
|
||||||
)
|
|
||||||
} catch (err) {
|
|
||||||
// system may have restarted, need to re-verify
|
|
||||||
if (
|
|
||||||
err !== undefined &&
|
|
||||||
err.code === "InvalidClientTokenId" &&
|
|
||||||
deployment.quota
|
|
||||||
) {
|
|
||||||
await verifyDeployment({
|
|
||||||
...user,
|
|
||||||
quota: deployment.quota,
|
|
||||||
})
|
|
||||||
complete = await isInvalidationComplete(
|
|
||||||
deployment.cfDistribution,
|
|
||||||
deployment.invalidationId
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (complete) {
|
|
||||||
update(deployment, DeploymentStatus.SUCCESS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return { updated, deployments }
|
return { updated, deployments }
|
||||||
}
|
}
|
||||||
|
@ -157,7 +123,7 @@ async function deployApp({ appId, deploymentId }) {
|
||||||
|
|
||||||
console.log(`Uploading assets for appID ${appId} assets to s3..`)
|
console.log(`Uploading assets for appID ${appId} assets to s3..`)
|
||||||
|
|
||||||
const invalidationId = await uploadAppAssets({
|
await uploadAppAssets({
|
||||||
appId,
|
appId,
|
||||||
...verification,
|
...verification,
|
||||||
})
|
})
|
||||||
|
@ -174,10 +140,9 @@ async function deployApp({ appId, deploymentId }) {
|
||||||
await storeLocalDeploymentHistory({
|
await storeLocalDeploymentHistory({
|
||||||
_id: deploymentId,
|
_id: deploymentId,
|
||||||
appId,
|
appId,
|
||||||
invalidationId,
|
|
||||||
cfDistribution: verification.cfDistribution,
|
cfDistribution: verification.cfDistribution,
|
||||||
quota: verification.quota,
|
quota: verification.quota,
|
||||||
status: DeploymentStatus.PENDING,
|
status: DeploymentStatus.SUCCESS,
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await storeLocalDeploymentHistory({
|
await storeLocalDeploymentHistory({
|
||||||
|
@ -226,7 +191,7 @@ exports.deployApp = async function(ctx) {
|
||||||
status: DeploymentStatus.PENDING,
|
status: DeploymentStatus.PENDING,
|
||||||
})
|
})
|
||||||
|
|
||||||
await deployApp({
|
deployApp({
|
||||||
...ctx.user,
|
...ctx.user,
|
||||||
deploymentId: deployment._id,
|
deploymentId: deployment._id,
|
||||||
})
|
})
|
||||||
|
|
|
@ -66,6 +66,8 @@ router.use(async (ctx, next) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.get("/health", ctx => (ctx.status = 200))
|
||||||
|
|
||||||
router.use(authRoutes.routes())
|
router.use(authRoutes.routes())
|
||||||
router.use(authRoutes.allowedMethods())
|
router.use(authRoutes.allowedMethods())
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue