1
0
Fork 0
mirror of synced 2024-07-03 13:30:46 +12:00

remove cf invalidation, adding validation around successful deploys only

This commit is contained in:
Martin McKeaveney 2020-11-10 17:08:02 +00:00
parent 2adf0560ac
commit f19a20a02d
5 changed files with 17 additions and 98 deletions

View file

@ -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">
{#if deployments.some(deployment => deployment.status === 'SUCCESS')}
<a target="_blank" href={`https://${appId}.app.budi.live/${appId}`}> <a target="_blank" href={`https://${appId}.app.budi.live/${appId}`}>
View Your Deployed App → View Your Deployed App →
</a> </a>
<Button primary on:click={() => modal.show()}>View webhooks</Button> <Button primary on:click={() => modal.show()}>View webhooks</Button>
{/if}
</div> </div>
</header> </header>
<div class="deployment-list"> <div class="deployment-list">

View file

@ -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"

View file

@ -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

View file

@ -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,
}) })

View file

@ -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())