From 8814e7b8c9ab2d5c8ee68cb6effb8ef7507a245b Mon Sep 17 00:00:00 2001 From: hfroger Date: Wed, 6 Mar 2024 13:42:32 +0000 Subject: [PATCH] chore: backups system through github actions (#69) * chore: add daily tasks for backups and cost structure --- .github/workflows/daily-tasks.yml | 29 +++++++ contrib/jelastic/backup.jps.yml | 92 -------------------- contrib/jelastic/restore.jps.yml | 138 ------------------------------ 3 files changed, 29 insertions(+), 230 deletions(-) create mode 100644 .github/workflows/daily-tasks.yml delete mode 100644 contrib/jelastic/backup.jps.yml delete mode 100644 contrib/jelastic/restore.jps.yml diff --git a/.github/workflows/daily-tasks.yml b/.github/workflows/daily-tasks.yml new file mode 100644 index 0000000..0449ea8 --- /dev/null +++ b/.github/workflows/daily-tasks.yml @@ -0,0 +1,29 @@ +name: Daily tasks for jelastic environment + +on: + workflow_dispatch: + schedule: + - cron: '0 6 * * *' + +jobs: + run-script: + runs-on: ubuntu-latest + container: + image: octree/jelastic-cli + steps: + - name: Run backup scripts on the environments + env: + RESTIC_REPOSITORY: ${{ secrets.RESTIC_REPOSITORY }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + RESTIC_PASSWORD: ${{ secrets.RESTIC_PASSWORD }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + JELASTIC_LOGIN: ${{ secrets.JELASTIC_LOGIN }} + JELASTIC_PASSWORD: ${{ secrets.JELASTIC_PASSWORD }} + JELASTIC_HOSTER: ${{ secrets.JELASTIC_HOSTER }} + HOME: /root + run: | + ~/jelastic/users/authentication/signin --login $JELASTIC_LOGIN --password $JELASTIC_PASSWORD --platformUrl $JELASTIC_HOSTER + export MANIFEST="https://git.octree.ch/decidim/vocacity/system/-/raw/main/contrib/jelastic-manifests/scripts/dailyTasks.yml?ref_type=heads" + export SETTINGS="{\"RESTIC_REPOSITORY\":\"$RESTIC_REPOSITORY\", \"AWS_ACCESS_KEY_ID\":\"$AWS_ACCESS_KEY_ID\", \"AWS_SECRET_ACCESS_KEY\":\"$AWS_SECRET_ACCESS_KEY\", \"RESTIC_PASSWORD\":\"$RESTIC_PASSWORD\", \"AWS_DEFAULT_REGION\":\"$AWS_DEFAULT_REGION\"}" + ~/jelastic/marketplace/jps/install --envName mautic-proxy --jps "$MANIFEST" --settings "$SETTINGS" \ No newline at end of file diff --git a/contrib/jelastic/backup.jps.yml b/contrib/jelastic/backup.jps.yml deleted file mode 100644 index 6af34fa..0000000 --- a/contrib/jelastic/backup.jps.yml +++ /dev/null @@ -1,92 +0,0 @@ -jpsType: update -jpsVersion: '1.7.4' - -name: Scripts/Backup -id: backup-instance -description: - short: Backup a voca instance -categories: - - apps/platforms -ssl: true -ha: false -skipNodeEmails: true - -settings: - fields: - - name: RESTIC_REPOSITORY - type: string - caption: Host+bucket+region for the S3 - - name: AWS_ACCESS_KEY_ID - type: string - caption: Key ID for S3 - - name: AWS_SECRET_ACCESS_KEY - type: string - caption: Secret for S3 - - name: RESTIC_PASSWORD - type: string - caption: Key used for restic encryption - - name: AWS_DEFAULT_REGION - type: string - caption: Default Region - default: 'ch-dk-2' - - name: TAG - type: string - caption: Tag the backup - default: 'daily' -onInstall: - - backupDb - - copyEnvs - - backup - - cleanup - -actions: - backupDb: - - cmd[sqldb]: |- - cd /tmp - mkdir -p "/tmp/dumps" - databases=$(psql --username $POSTGRES_USER postgres -qAt -c "SELECT datname FROM pg_database WHERE NOT datistemplate") - for db in $databases - do - pg_dump --username $POSTGRES_USER -Fp $db > "/tmp/dumps/$db.sql" - done; - - script: | - var result = jelastic.environment.file.getlist("${env.name}", session, "/tmp/dumps", "docker", "sqldb"); - var sentFiles = []; - (result.keywords || []).forEach(function(keyword){ - (keyword.files || []).forEach(function(file) { - if(!file.path || file.isdir) return; - var resultFile = jelastic.environment.file.read("${env.name}", session, file.path, "docker", "sqldb"); - var fileName = "/data" + file.path.replace("/tmp/dumps", ""); - jelastic.environment.file.write("${env.name}", session, fileName, resultFile.body, "docker", "storage"); - sentFiles.push(fileName); - }) - }); - return { "result": sentFiles.length > 0 ? 0 : 1, "message": JSON.stringify(result) }; - - cmd[sqldb]: rm -rf /tmp/dumps - copyEnvs: - - cmd[cp]: - - env > /tmp/.env-cp.bak - - script: | - var result = jelastic.environment.file.read("${env.name}", session, "/tmp/.env-cp.bak", "docker", "cp"); - var fileName = "/data/.env-cp.bak"; - jelastic.environment.file.write("${env.name}", session, fileName, result.body, "docker", "storage"); - return { "result": 0 }; - backup: - - cmd[storage]: - - yum-config-manager --add-repo - https://copr.fedorainfracloud.org/coprs/copart/restic/repo/epel-7/copart-restic-epel-7.repo - - yum install -y jq restic - - export - RESTIC_REPOSITORY="s3:${settings.RESTIC_REPOSITORY}/${env.name}" - - export AWS_ACCESS_KEY_ID="${settings.AWS_ACCESS_KEY_ID}" - - export AWS_SECRET_ACCESS_KEY="${settings.AWS_SECRET_ACCESS_KEY}" - - export RESTIC_PASSWORD="${settings.RESTIC_PASSWORD}" - - export AWS_DEFAULT_REGION="${settings.AWS_DEFAULT_REGION}" - - if ! restic snapshots >/dev/null 2>&1; then restic init; fi - - restic backup --tag "${settings.TAG}" /data - cleanup: - - cmd[storage]: - - rm -f /data/.env-cp.bak /data/*.sql - -success: | - A new backup tagged "${settings.TAG}" has been created for s3:${settings.RESTIC_REPOSITORY}/${env.name} diff --git a/contrib/jelastic/restore.jps.yml b/contrib/jelastic/restore.jps.yml deleted file mode 100644 index cff6ce8..0000000 --- a/contrib/jelastic/restore.jps.yml +++ /dev/null @@ -1,138 +0,0 @@ -# This manifest restore a backup, it can restore backup for -# the current environment, or from another environment. -# Thus, it is used for two things: - -# 1. Restore a backup when we have an issue with an instance -# 2. Setup a template backup to start an instance from a pre-installed configuration. - -# The restore script will: - -# - Take the backup, by the default the last one. -# - Apply the backup in the storage node group -# - Go in the sql node group and dump current state, before restoring the state from the backup. -# - Go back in the storage node, and remove old sql dump. -# - Restart all the containers. - -jpsType: update -jpsVersion: '1.7.4' - -name: Scripts/RestoreBackup -id: voca-jps-restore-backup -description: - short: Restore a backup -categories: - - apps/platforms -ssl: true -ha: false -skipNodeEmails: true -skipEmail: true - -settings: - fields: - - name: SOURCE_ENV_NAME - type: string - caption: Env name of the source backup - - name: SOURCE_PASSWORD - type: string - caption: Password for the source backup - - name: RESTIC_REPOSITORY - type: string - caption: Host+bucket+region for the S3 - - name: AWS_ACCESS_KEY_ID - type: string - caption: Key ID for S3 - - name: AWS_SECRET_ACCESS_KEY - type: string - caption: Secret for S3 - - name: RESTIC_PASSWORD - type: string - caption: Key used for restic encryption - - name: AWS_DEFAULT_REGION - type: string - caption: Default Region - default: 'ch-dk-2' - - name: HEAD_INDEX - type: string - caption: 1 for last, 2 for previous, etc. - default: '1' -onInstall: - - restoreFiles - - restoreDb - - install -actions: - restoreFiles: - - cmd[storage]: - - cd /data - - tar cfz "/tmp/data_dump-$(date +%Y-%m-%d-%H%M%S).tar.gz" -C /data . - - cd / - - rm -rf data/* - - cmd[storage]: - - yum-config-manager --add-repo - https://copr.fedorainfracloud.org/coprs/copart/restic/repo/epel-7/copart-restic-epel-7.repo - - yum install -y jq restic - # Setup own password for environment, and init a snapshot - # collection if does not exists. - - export OWN_REPOSITORY="s3:${settings.RESTIC_REPOSITORY}/${env.name}" - - export OWN_PASSWORD="${settings.RESTIC_PASSWORD}" - - export RESTIC_REPOSITORY="$OWN_REPOSITORY" - - export RESTIC_PASSWORD="$OWN_PASSWORD" - - export AWS_ACCESS_KEY_ID="${settings.AWS_ACCESS_KEY_ID}" - - export AWS_SECRET_ACCESS_KEY="${settings.AWS_SECRET_ACCESS_KEY}" - - export AWS_DEFAULT_REGION="${settings.AWS_DEFAULT_REGION}" - - if ! restic snapshots >/dev/null 2>&1; then restic init; fi - # Restic is initialized, now we can get the backup wanted, - # even the backup is else where. - - export - RESTIC_REPOSITORY="s3:${settings.RESTIC_REPOSITORY}/${settings.SOURCE_ENV_NAME}" - - export RESTIC_PASSWORD="${settings.SOURCE_PASSWORD}" - - export SNAPSHOT_ID=$(restic snapshots --latest ${settings.HEAD_INDEX} - --json | jq -r '.[0].id') - - restic restore $SNAPSHOT_ID --target / - # Add a new instance backup to the collection, with the - # result of the restoration. - - export RESTIC_REPOSITORY="$OWN_REPOSITORY" - - export RESTIC_PASSWORD="$OWN_PASSWORD" - - restic backup --tag "afterRestore" /data - - restoreDb: - # Get the dump.sql file from storage dump and put it in the sql container. - - script: | - var result = jelastic.environment.file.read("${env.name}", session, "/data/decidim.sql", "docker", "storage"); - var fileName = "/tmp/decidim.sql"; - jelastic.environment.file.write("${env.name}", session, fileName, result.body, "docker", "sqldb"); - return { "result": 0 }; - # Dump actual database, then erase it, and import the dump. - - cmd[sqldb]: - - cd /tmp - - pg_dump --username $POSTGRES_USER -Fp $db > "/tmp/pg_dump-$(date - +%Y-%m-%d-%H%M%S).sql" - - psql --username=$POSTGRES_USER postgres -qAt -c "DROP DATABASE IF - EXISTS decidim" - - psql --username=$POSTGRES_USER postgres -qAt -c "CREATE DATABASE - decidim" - - psql --username $POSTGRES_USER decidim < decidim.sql - - rm -rf /tmp/decidim.sql - # Remove from storage any .sql files. - - cmd[storage]: - - cd /data - - tar cfz /tmp/pg_dump-$(date +%Y-%m-%d-%H%M%S).tar.gz -C /data ./*.sql - - rm -f /data/*.sql - - cmd[rpc]: - - cd $ROOT - - NODE_ENV=development npm i - - bundle config set --local with "development" - - bundle config set --local clean false - - bundle update timeout - - rm -rf public/decidim-packs - - NODE_ENV=development bundle exec rails assets:precompile - - chown -R decidim:decidim public - - install: - # Restart to apply change in volumes - - forEach(nodes.cp): - - restartContainer[${@i.id}] - - forEach(nodes.rpc): - - restartContainer[${@i.id}] - - sleep: 1000 -success: | - Latest backup restored from ${settings.SOURCE_ENV_NAME}