From b91bfa21b31f6c7bf46845335409e02274bf1f94 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Tue, 30 Mar 2021 21:49:46 +0200 Subject: [PATCH] v1.0.2 (#8) - Fix restart_policy in Service config. - Tweaked the upgrade process a bit. - Refactor and cosmetic surgery here and there. - Track Service config changes and allow redeploy if it changes. --- README.md | 12 ++-- api/libs/applications/cleanup/index.js | 3 +- api/libs/applications/configuration.js | 24 ++++++- api/libs/applications/deploy/deploy.js | 28 +++------ api/routes/v1/application/deploy/index.js | 4 ++ api/routes/v1/upgrade/index.js | 4 +- install.sh | 61 ++++++++++++------ install/install.js | 2 +- install/{update.js => upgrade.js} | 7 ++- package.json | 3 +- pnpm-lock.yaml | 6 ++ .../Configuration/ActiveTab/General.svelte | 61 +----------------- .../Application/Configuration/Branches.svelte | 2 +- .../Configuration/Repositories.svelte | 2 +- src/pages/_layout.svelte | 21 +++---- src/pages/application/_layout.svelte | 1 + src/store.js | 3 +- upgrade.sh | 62 +++++++++++++++++++ 18 files changed, 181 insertions(+), 125 deletions(-) rename install/{update.js => upgrade.js} (74%) create mode 100644 upgrade.sh diff --git a/README.md b/README.md index 6d9a56b2b..c5cf7b022 100644 --- a/README.md +++ b/README.md @@ -14,15 +14,11 @@ https://andrasbacsai.com/farewell-netlify-and-heroku-after-3-days-of-coding # FAQ -Q: What does Buildpack means? +Q: What is a buildpack? -A: It defines your application's final form. Static means that it will be hosted as a static site in the end. (see next question below 👇) - ---- - -Q: How can I build a static site, like Next.js, Sapper (prerendered), etc ? - -A: Use `static` builder and set your `Build command`. +A: It defines your application's final form. +`Static` means that it will be hosted as a static site. +`NodeJs` means that it will be started as a node application. # Screenshots diff --git a/api/libs/applications/cleanup/index.js b/api/libs/applications/cleanup/index.js index f40c2fbd0..8987eeb5b 100644 --- a/api/libs/applications/cleanup/index.js +++ b/api/libs/applications/cleanup/index.js @@ -1,9 +1,10 @@ const { docker } = require('../../docker') -const { execShellAsync, delay } = require('../../common') +const { execShellAsync } = require('../../common') const Deployment = require('../../../models/Deployment') async function purgeOldThings () { try { + // TODO: Tweak this, because it deletes coolify-base, so the upgrade will be slow await docker.engine.pruneImages() await docker.engine.pruneContainers() } catch (error) { diff --git a/api/libs/applications/configuration.js b/api/libs/applications/configuration.js index 127a2ca36..e4cdfbc4a 100644 --- a/api/libs/applications/configuration.js +++ b/api/libs/applications/configuration.js @@ -1,8 +1,9 @@ const { uniqueNamesGenerator, adjectives, colors, animals } = require('unique-names-generator') const cuid = require('cuid') -const { execShellAsync } = require('../common') const crypto = require('crypto') +const { execShellAsync } = require('../common') + function getUniq () { return uniqueNamesGenerator({ dictionaries: [adjectives, animals, colors], length: 2 }) } @@ -15,6 +16,24 @@ function setDefaultConfiguration (configuration) { const shaBase = JSON.stringify({ repository: configuration.repository }) const sha256 = crypto.createHash('sha256').update(shaBase).digest('hex') + const baseServiceConfiguration = { + replicas: 1, + restart_policy: { + condition: 'any', + max_attempts: 3 + }, + update_config: { + parallelism: 1, + delay: '10s', + order: 'start-first' + }, + rollback_config: { + parallelism: 1, + delay: '10s', + order: 'start-first' + } + } + configuration.build.container.name = sha256.slice(0, 15) configuration.general.nickname = nickname @@ -34,6 +53,9 @@ function setDefaultConfiguration (configuration) { if (!configuration.build.directory) configuration.build.directory = '/' } + configuration.build.container.baseSHA = crypto.createHash('sha256').update(JSON.stringify(baseServiceConfiguration)).digest('hex') + configuration.baseServiceConfiguration = baseServiceConfiguration + return configuration } catch (error) { throw { error, type: 'server' } diff --git a/api/libs/applications/deploy/deploy.js b/api/libs/applications/deploy/deploy.js index 15ebd193f..cd16c0014 100644 --- a/api/libs/applications/deploy/deploy.js +++ b/api/libs/applications/deploy/deploy.js @@ -1,9 +1,9 @@ const yaml = require('js-yaml') +const fs = require('fs').promises const { execShellAsync } = require('../../common') const { docker } = require('../../docker') const { saveAppLog } = require('../../logging') const { deleteSameDeployments } = require('../cleanup') -const fs = require('fs').promises module.exports = async function (configuration, configChanged, imageChanged) { try { @@ -12,6 +12,11 @@ module.exports = async function (configuration, configChanged, imageChanged) { generateEnvs[secret.name] = secret.value } const containerName = configuration.build.container.name + + // Only save SHA256 of it in the configuration label + const baseServiceConfiguration = configuration.baseServiceConfiguration + delete configuration.baseServiceConfiguration + const stack = { version: '3.8', services: { @@ -20,23 +25,7 @@ module.exports = async function (configuration, configChanged, imageChanged) { networks: [`${docker.network}`], environment: generateEnvs, deploy: { - replicas: 1, - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 1, - window: '120s' - }, - update_config: { - parallelism: 1, - delay: '10s', - order: 'start-first' - }, - rollback_config: { - parallelism: 1, - delay: '10s', - order: 'start-first' - }, + ...baseServiceConfiguration, labels: [ 'managedBy=coolify', 'type=application', @@ -71,8 +60,10 @@ module.exports = async function (configuration, configChanged, imageChanged) { } } } + console.log(stack) await saveAppLog('### Publishing.', configuration) await fs.writeFile(`${configuration.general.workdir}/stack.yml`, yaml.dump(stack)) + // TODO: Compare stack.yml with the currently running one to upgrade if something changes, like restart_policy if (configChanged) { // console.log('configuration changed') await execShellAsync( @@ -91,6 +82,7 @@ module.exports = async function (configuration, configChanged, imageChanged) { await saveAppLog('### Published done!', configuration) } catch (error) { + console.log(error) await saveAppLog(`Error occured during deployment: ${error.message}`, configuration) throw { error, type: 'server' } } diff --git a/api/routes/v1/application/deploy/index.js b/api/routes/v1/application/deploy/index.js index dbefa6b8f..1322f3d6c 100644 --- a/api/routes/v1/application/deploy/index.js +++ b/api/routes/v1/application/deploy/index.js @@ -60,6 +60,10 @@ module.exports = async function (fastify) { foundDomain = true } if (running.repository.id === configuration.repository.id && running.repository.branch === configuration.repository.branch) { + // Base service configuration changed + if (!running.build.container.baseSHA || running.build.container.baseSHA !== configuration.build.container.baseSHA) { + configChanged = true + } const state = await execShellAsync(`docker stack ps ${running.build.container.name} --format '{{ json . }}'`) const isError = state.split('\n').filter(n => n).map(s => JSON.parse(s)).filter(n => n.DesiredState !== 'Running') if (isError.length > 0) forceUpdate = true diff --git a/api/routes/v1/upgrade/index.js b/api/routes/v1/upgrade/index.js index 7adfae051..fd86f3b43 100644 --- a/api/routes/v1/upgrade/index.js +++ b/api/routes/v1/upgrade/index.js @@ -3,10 +3,10 @@ const { saveServerLog } = require('../../../libs/logging') module.exports = async function (fastify) { fastify.get('/', async (request, reply) => { - const upgradeP1 = await execShellAsync('bash ./install.sh upgrade-phase-1') + const upgradeP1 = await execShellAsync('bash ./upgrade.sh upgrade-p1') await saveServerLog({ event: upgradeP1, type: 'UPGRADE-P-1' }) reply.code(200).send('I\'m trying, okay?') - const upgradeP2 = await execShellAsync('bash ./install.sh upgrade-phase-2') + const upgradeP2 = await execShellAsync('bash ./upgrade.sh upgrade-p2') await saveServerLog({ event: upgradeP2, type: 'UPGRADE-P-2' }) }) } diff --git a/install.sh b/install.sh index 50cd4fa67..59df1bb81 100644 --- a/install.sh +++ b/install.sh @@ -1,43 +1,68 @@ #!/bin/bash +echo ' +############################## +#### Pulling Git Updates ##### +##############################' GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" git pull -echo "#### Building base image." -docker build -t coolify-base -f install/Dockerfile-base . + if [ $? -ne 0 ]; then - echo '#### Ooops something not okay!' + echo ' +#################################### +#### Ooops something not okay! ##### +####################################' exit 1 fi -echo "#### Checking configuration." +echo ' +############################## +#### Building Base Image ##### +##############################' +docker build --label coolify-reserve=true -t coolify-base -f install/Dockerfile-base . + +if [ $? -ne 0 ]; then + echo ' +#################################### +#### Ooops something not okay! ##### +####################################' + exit 1 +fi + +echo ' +################################## +#### Checking configuration. ##### +##################################' docker run --rm -w /usr/src/app coolify-base node install/install.js --check if [ $? -ne 0 ]; then - echo '#### Missing configuration.' + echo ' +################################## +#### Missing configuration ! ##### +##################################' exit 1 fi case "$1" in "all") - echo "#### Rebuild everything." + echo ' +################################# +#### Rebuilding everything. ##### +#################################' docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify:/data/coolify -u root -w /usr/src/app coolify-base node install/install.js --type all ;; "coolify") - echo "#### Rebuild coolify." + echo ' +############################## +#### Rebuilding Coolify. ##### +##############################' docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify:/data/coolify -u root -w /usr/src/app coolify-base node install/install.js --type coolify ;; "proxy") - echo "#### Rebuild proxy." + echo ' +############################ +#### Rebuilding Proxy. ##### +############################' docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify:/data/coolify -u root -w /usr/src/app coolify-base node install/install.js --type proxy ;; - "upgrade-phase-1") - echo "#### Rebuild coolify from frontend request phase 1." - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify:/data/coolify -u root -w /usr/src/app coolify-base node install/install.js --type upgrade - ;; - "upgrade-phase-2") - echo "#### Rebuild coolify from frontend request phase 2." - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v /data/coolify:/data/coolify -u root -w /usr/src/app coolify-base node install/update.js --type upgrade - ;; - *) - echo "Use 'all' to build & deploy proxy+coolify, 'coolify' to build & deploy only coolify, 'proxy' to build & deploy only proxy." exit 1 ;; esac diff --git a/install/install.js b/install/install.js index 2fd22201f..95dfe477a 100644 --- a/install/install.js +++ b/install/install.js @@ -35,7 +35,7 @@ if (program.check) { } else if (program.type === 'proxy') { shell.exec('docker service rm coollabs-coolify_proxy') } - if (program.type !== 'upgrade') shell.exec('set -a && source .env && set +a && envsubst < install/coolify-template.yml | docker stack deploy -c - coollabs-coolify', { silent: !program.debug, shell: '/bin/bash' }) + shell.exec('set -a && source .env && set +a && envsubst < install/coolify-template.yml | docker stack deploy -c - coollabs-coolify', { silent: !program.debug, shell: '/bin/bash' }) } function checkConfig () { diff --git a/install/update.js b/install/upgrade.js similarity index 74% rename from install/update.js rename to install/upgrade.js index 47beeb026..28e72bd56 100644 --- a/install/update.js +++ b/install/upgrade.js @@ -15,7 +15,12 @@ if (user !== 'root') { console.error(`Please run as root! Current user: ${user}`) process.exit(1) } -if (program.type === 'upgrade') { +if (program.type === 'upgrade-p1') { + shell.exec(`docker network create ${process.env.DOCKER_NETWORK} --driver overlay`, { silent: !program.debug }) + shell.exec('docker build -t coolify -f install/Dockerfile .') +} + +if (program.type === 'upgrade-p2') { shell.exec('docker service rm coollabs-coolify_coolify') shell.exec('set -a && source .env && set +a && envsubst < install/coolify-template.yml | docker stack deploy -c - coollabs-coolify', { silent: !program.debug, shell: '/bin/bash' }) } diff --git a/package.json b/package.json index 0031023cc..925d5e764 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coolify", "description": "An open-source, hassle-free, self-hostable Heroku & Netlify alternative.", - "version": "1.0.1", + "version": "1.0.2", "license": "AGPL-3.0", "scripts": { "lint": "standard", @@ -20,6 +20,7 @@ "@zerodevx/svelte-toast": "^0.1.4", "axios": "^0.21.0", "commander": "^6.2.1", + "compare-versions": "^3.6.0", "cuid": "^2.1.8", "dayjs": "^1.10.4", "deepmerge": "^4.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 87ac153fc..c1565216b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,6 +3,7 @@ dependencies: '@zerodevx/svelte-toast': 0.1.4 axios: 0.21.1 commander: 6.2.1 + compare-versions: 3.6.0 cuid: 2.1.8 dayjs: 1.10.4 deepmerge: 4.2.2 @@ -1188,6 +1189,10 @@ packages: dev: true resolution: integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + /compare-versions/3.6.0: + dev: false + resolution: + integrity: sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== /concat-map/0.0.1: resolution: integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= @@ -6749,6 +6754,7 @@ specifiers: '@zerodevx/svelte-toast': ^0.1.4 axios: ^0.21.0 commander: ^6.2.1 + compare-versions: ^3.6.0 cuid: ^2.1.8 dayjs: ^1.10.4 deepmerge: ^4.2.2 diff --git a/src/components/Application/Configuration/ActiveTab/General.svelte b/src/components/Application/Configuration/ActiveTab/General.svelte index d48584fad..e0bcbcadf 100644 --- a/src/components/Application/Configuration/ActiveTab/General.svelte +++ b/src/components/Application/Configuration/ActiveTab/General.svelte @@ -8,8 +8,8 @@ >
{/if} -
\ No newline at end of file diff --git a/src/components/Application/Configuration/Branches.svelte b/src/components/Application/Configuration/Branches.svelte index c111e215c..a10a0c083 100644 --- a/src/components/Application/Configuration/Branches.svelte +++ b/src/components/Application/Configuration/Branches.svelte @@ -17,7 +17,7 @@ diff --git a/src/components/Application/Configuration/Repositories.svelte b/src/components/Application/Configuration/Repositories.svelte index c69685e71..c62bfc445 100644 --- a/src/components/Application/Configuration/Repositories.svelte +++ b/src/components/Application/Configuration/Repositories.svelte @@ -23,7 +23,7 @@ > {#each repositories as repo} -