@flowfuse/flowfuse
Version:
An open source low-code development platform
165 lines (147 loc) • 5.14 kB
JavaScript
const extractNameRegex =
/(?:(?<name>.*) - )?Deploy Snapshot - \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/
const extractDescriptionRegex =
/Snapshot created for pipeline deployment from .* to .* as part of pipeline .*/
async function setSnapShotAsTarget (app, snapshot, instance, user) {
await snapshot.reload()
await instance.updateSetting('deviceSettings', {
targetSnapshot: snapshot.id
})
// Update the targetSnapshot of the devices assigned to this project
await app.db.models.Device.update(
{ targetSnapshotId: snapshot.id },
{
where: {
ProjectId: instance.id
}
}
)
await app.auditLog.Project.project.snapshot.deviceTargetSet(
user,
null,
instance,
snapshot
)
if (app.comms) {
app.comms.devices.sendCommandToProjectDevices(
(await instance.getTeam()).hashid,
instance.id,
'update',
{
snapshot: snapshot.hashid
}
)
}
}
/**
* Generate a name for a restore snapshot
* Optionally using the name of the source snapshot, stripping out the deploy timing info
* @param {*} sourceSnapshot
* @returns string
*/
module.exports.generateDeploySnapshotName = (sourceSnapshot = null) => {
const nameParts = [
'Deploy Snapshot',
new Date().toLocaleString('sv-SE') // YYYY-MM-DD HH:MM:SS
]
if (sourceSnapshot?.name) {
const extractedGroups = sourceSnapshot.name.match(extractNameRegex)
const existingName = extractedGroups?.groups.name ?? (extractedGroups?.length > 0 ? '' : sourceSnapshot.name)
if (existingName) {
nameParts.unshift(existingName)
}
}
return nameParts.join(' - ')
}
module.exports.generateDeploySnapshotDescription = (
sourceStage,
targetStage,
pipeline,
sourceSnapshot = null
) => {
let description = `Snapshot created for pipeline deployment from ${sourceStage.name} to ${targetStage.name} as part of pipeline ${pipeline.name}`
if (sourceSnapshot) {
const existingDescription = sourceSnapshot.description
.replace(extractDescriptionRegex, '')
.trim()
if (existingDescription) {
description = `${existingDescription}\n\n${description}`
}
}
return description
}
module.exports.createSnapshot = async (app, instance, user, snapshotProps) => {
const fullInstanceObject = await app.db.models.Project.byId(instance.id)
if (snapshotProps.flows && typeof snapshotProps.flows === 'object' && Array.isArray(snapshotProps.flows.flows)) {
// ProjectSnapshot.createSnapshot function in `controllers/ProjectSnapshot.js`
// expects the flows and credentials to be separate properties
const credentials = snapshotProps.flows.credentials
const flows = snapshotProps.flows.flows
snapshotProps.credentials = credentials
snapshotProps.flows = flows
}
const snapShot = await app.db.controllers.ProjectSnapshot.createSnapshot(
fullInstanceObject, // expects Project.byId for all extra props
user,
snapshotProps
)
snapShot.User = user
await app.auditLog.Project.project.snapshot.created(
user,
null,
instance,
snapShot
)
if (snapshotProps.setAsTarget) {
await setSnapShotAsTarget(app, snapShot, instance, user)
}
return snapShot
}
module.exports.copySnapshot = async (
app,
snapshot,
toInstance,
{
importSnapshot,
setAsTarget,
targetSnapshotProperties
} = {
importSnapshot: true,
setAsTarget: false,
targetSnapshotProperties: null
}
) => {
const { settings, flows, name, description, credentialSecret } = snapshot.toJSON()
const snapshotToCopyProps = { settings, flows, name, description }
let targetInstanceSecret = await toInstance.getCredentialSecret()
if (!targetInstanceSecret) {
targetInstanceSecret = app.db.models.Project.generateCredentialSecret()
await toInstance.updateSetting('credentialSecret', targetInstanceSecret)
}
// Decrypt and re-encrypt credentials
if (snapshotToCopyProps.flows.credentials) {
snapshotToCopyProps.flows.credentials = await app.db.controllers.Project.reEncryptCredentials(
snapshotToCopyProps.flows.credentials,
credentialSecret,
targetInstanceSecret
)
}
const newSnapshot = await app.db.models.ProjectSnapshot.create({
...snapshotToCopyProps,
...targetSnapshotProperties,
credentialSecret: targetInstanceSecret,
ProjectId: toInstance.id,
UserId: snapshot.UserId
})
if (importSnapshot) {
await app.db.controllers.Project.importProjectSnapshot(
toInstance,
newSnapshot,
{ mergeEnvVars: true, mergeEditorSettings: true }
)
}
if (setAsTarget) {
await setSnapShotAsTarget(app, newSnapshot, toInstance, snapshot.User)
}
return newSnapshot
}