Skip to content

Commit 6f4548b

Browse files
authored
Merge pull request #245 from ministryofjustice/DBA-667
Dba 667
2 parents 4269d28 + ca1454b commit 6f4548b

7 files changed

+271
-318
lines changed

.github/workflows/oracle-db-backup.yml

+115-32
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[
2+
{
3+
"TargetEnvironment":"delius-core-dev",
4+
"TargetHost":"delius_primarydb",
5+
"CronSchedule":"10 14 * * TUE"
6+
},
7+
{
8+
"TargetEnvironment":"delius-core-test",
9+
"TargetHost":"delius_primarydb",
10+
"CronSchedule":"10 16 * * TUE"
11+
}
12+
]

.github/workflows/oracle-db-delete-dbids-not-in-use.yml

+43-244
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: "Oracle: Schedule Delete DBID Backups Not In Use"
2+
on:
3+
push:
4+
branches:
5+
- "DBA-667"
6+
schedule:
7+
- cron: '10 14 * * TUE'
8+
- cron: '10 15 * * TUE'
9+
- cron: '10 16 * * TUE'
10+
jobs:
11+
prepare-run-matrix:
12+
runs-on: ubuntu-latest
13+
outputs:
14+
scheduled_matrix: ${{ steps.filter-validate-schedule.outputs.scheduling_matrix }}
15+
steps:
16+
- name: Checkout Delete DBIDs Backups Schedule
17+
uses: actions/checkout@v4
18+
with:
19+
sparse-checkout-cone-mode: false
20+
sparse-checkout: |
21+
.github/workflows/oracle-db-delete-dbids-not-in-use-schedule.json
22+
path: operations
23+
ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.SourceCodeVersion || 'main' }}
24+
fetch-depth: 0
25+
26+
- name: Filter Validate Schedule
27+
id: filter-validate-schedule
28+
run: |
29+
SCHEDULED_JSON=$(jq '[.[] | select (.CronSchedule=="${{ github.event.schedule }}") | {"TargetEnvironment","TargetHost"}]' operations/.github/workflows/oracle-db-delete-dbids-not-in-use-schedule.json | jq '{include: .}')
30+
echo "scheduling_matrix="$(echo ${SCHEDULED_JSON} | sed 's/ //g') >> $GITHUB_OUTPUT
31+
32+
report-schedule-delete-dbids-not-in-use:
33+
needs: prepare-run-matrix
34+
runs-on: ubuntu-latest
35+
if: ${{ needs.prepare-run-matrix.outputs.scheduled_matrix != '{"include":[]}' }}
36+
steps:
37+
- name: Report Deletion of DBIDs Scheduled to Run
38+
id: report-run
39+
run: |
40+
echo "Running Deletion of Unused DBID Backups for these targets: ${{ needs.prepare-run-matrix.outputs.scheduled_matrix }}"
41+
42+
report-no-scheduled-delete-dbids-not-in-use:
43+
needs: prepare-run-matrix
44+
runs-on: ubuntu-latest
45+
if: ${{ needs.prepare-run-matrix.outputs.scheduled_matrix == '{"include":[]}' }}
46+
steps:
47+
- name: Report Nothing to Do
48+
id: report-no-run
49+
run: |
50+
echo "No targets scheduled for DBID backup deletion."
51+
52+
delete-dbids-not-in-use:
53+
needs: prepare-run-matrix
54+
if: ${{ needs.prepare-run-matrix.outputs.scheduled_matrix != '{"include":[]}' }}
55+
strategy:
56+
matrix: ${{fromJson(needs.prepare-run-matrix.outputs.scheduled_matrix)}}
57+
name: Delete DBID Backups Not In Use
58+
uses:
59+
ministryofjustice/hmpps-delius-operational-automation/.github/workflows/oracle-db-delete-dbids-not-in-use.yml@main
60+
with:
61+
TargetEnvironment: ${{ matrix.TargetEnvironment }}
62+
TargetHost: ${{ matrix.TargetHost }}

playbooks/oracle_backup/check_defunct_backups.yml

-9
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,6 @@
2424

2525
- block:
2626
- include_tasks: fetch_inventory_files.yml
27-
delegate_to: localhost
28-
become: no
29-
30-
# Copy inventory file from Ansible Controller to same directory on the target Host
31-
- name: Copy Inventory File to Target Host for Further Processing
32-
copy:
33-
src: "{{ inventory_file }}"
34-
dest: "{{ inventory_file }}"
35-
owner: oracle
3627

3728
- name: Get Passwords
3829
include_tasks: get_facts.yml

playbooks/oracle_backup/delete_dbids_not_in_use.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
- name: Delete DBIDs Not Longer in Use
2-
hosts: '{{ rman_target | default("localhost", true) }}'
2+
hosts: "{{ rman_target }}"
33
gather_facts: yes
44
become: yes
55
become_user: oracle

playbooks/oracle_backup/rman_backup.sh

+38-32
Original file line numberDiff line numberDiff line change
@@ -88,17 +88,18 @@ function generate_jwt()
8888
{
8989
# Get a JSON Web Token to authenicate against the HMPPS Bot.
9090
# The HMPPS bot can provide exchange this for a GitHub Token for action GitHub workflows.
91-
9291
BOT_APP_ID=$(aws ssm get-parameter --name "/github/hmpps_bot_app_id" --query "Parameter.Value" --with-decryption --output text)
9392
BOT_PRIVATE_KEY=$(aws ssm get-parameter --name "/github/hmpps_bot_priv_key" --query "Parameter.Value" --with-decryption --output text)
9493

95-
# Define expiry time for JWT
94+
# Define expiry time for JWT - we will be using it immediately so just use a 10 minute expiry time.
9695
NOW=$(date +%s)
97-
INITIAL=$((${NOW} - 60)) # Issues 60 seconds in the past
96+
INITIAL=$((${NOW} - 60)) # Issues 60 seconds in the past (avoid time jitter problem)
9897
EXPIRY=$((${NOW} + 600)) # Expires 10 minutes in the future
9998

99+
# This function is used to apply Base64 encoding for the token to allow it to be passed on.
100100
b64enc() { openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n'; }
101101

102+
# The JWT requires a Header, Payload and Signature as defined here.
102103
HEADER_JSON='{
103104
"typ":"JWT",
104105
"alg":"RS256"
@@ -111,7 +112,7 @@ PAYLOAD_JSON='{
111112
"exp":'"${EXPIRY}"',
112113
"iss":'"${BOT_APP_ID}"'
113114
}'
114-
# Payload encode
115+
# Payload encode in Base64
115116
PAYLOAD=$( echo -n "${PAYLOAD_JSON}" | b64enc )
116117

117118
# Signature
@@ -138,23 +139,33 @@ printf '%s\n' "$GITHUB_TOKEN"
138139

139140
function github_repository_dispatch()
140141
{
142+
# Because this script is intended to run asynchronously and may be called by a GitHub Workflow, we use
143+
# GitHub Repository Dispatch events to call back to the Workflow to allow it to continue. This is a
144+
# workaround to avoid two issues:
145+
# (1) Timeout of GitHub actions lasting over 6 hours.
146+
# (2) Billing costs associated with the GitHub hosted runner actively waiting whilst the backup runs.
147+
#
148+
# We supply 2 parameters to this function:
149+
# EVENT_TYPE is a user-defined event to pass to the GitHub repository. The backup worflow is triggered
150+
# for either oracle-db-backup-sucess or oracle-db-backup-failure events. These are the only 2 which
151+
# should be used.
152+
# JSON_PAYLOAD is the JSON originally passed to the script using the -j switch. This allows the
153+
# workflow to continue where it left off because this JSON contains the name of the environment, host
154+
# and period of the backup, along with any associated parameters.
141155
EVENT_TYPE=$1
142156
JSON_PAYLOAD=$2
143157
GITHUB_TOKEN_VALUE=$(get_github_token | jq -r '.token')
158+
# We set the Phase in the JSON payload corresponding to whether the backup has succeeded or failed.
159+
# This is informational only - it is GitHub event type (oracle-db-backup-success/failure) which
160+
# determines what the workflow does next.
144161
if [[ "$EVENT_TYPE" == "oracle-db-backup-success" ]]; then
145162
JSON_PAYLOAD=$(echo $JSON_PAYLOAD | jq -r '.Phase = "Backup Succeeded"')
146163
else
147164
JSON_PAYLOAD=$(echo $JSON_PAYLOAD | jq -r '.Phase = "Backup Failed"')
148165
fi
149-
info "Running Repository Dispatch:${EVENT_TYPE}:${JSON_PAYLOAD}:${GITHUB_TOKEN_VALUE}"
150166
JSON_DATA="{\"event_type\": \"${EVENT_TYPE}\",\"client_payload\":${JSON_PAYLOAD}}"
151-
info "JD1: $JSON_DATA"
152-
JSON_DATA=$(echo $JSON_DATA | jq @json)
153-
info "JD2: $JSON_DATA"
154-
cat <<EOCURL | tee -a /tmp/eocurl.txt
155-
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: token ${GITHUB_TOKEN_VALUE}" --data ${JSON_DATA} ${REPOSITORY_DISPATCH}
156-
EOCURL
157-
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: token ${GITHUB_TOKEN_VALUE}" --data ${JSON_DATA} ${REPOSITORY_DISPATCH}
167+
info "Posting repository dispatch event"
168+
curl -X POST -H "Accept: application/vnd.github+json" -H "Authorization: token ${GITHUB_TOKEN_VALUE}" --data-raw "${JSON_DATA}" ${REPOSITORY_DISPATCH}
158169
RC=$?
159170
if [[ $RC -ne 0 ]]; then
160171
# We cannot use the error function for dispatch failures as it contains its own dispatch call
@@ -184,17 +195,14 @@ update_ssm_parameter () {
184195
MESSAGE=$2
185196
info "Updating SSM Parameter ${SSM_PARAMETER} Message to ${MESSAGE}"
186197
SSM_VALUE=$(aws ssm get-parameter --name "${SSM_PARAMETER}" --query "Parameter.Value" --output text)
187-
info "I: $NEW_SSM_VALUE"
188198
NEW_SSM_VALUE=$(echo ${SSM_VALUE} | jq -r --arg MESSAGE "$MESSAGE" '.Message=$MESSAGE')
189-
info "B: $NEW_SSM_VALUE"
190199
if [[ "$STATUS" == "Success" ]]; then
191200
NEW_SSM_VALUE=$(echo ${NEW_SSM_VALUE} | jq -r '.Phase = "Backup Succeeded"')
192201
elif [[ "$STATUS" == "Running" ]]; then
193202
NEW_SSM_VALUE=$(echo ${NEW_SSM_VALUE} | jq -r '.Phase = "Backup In Progress"')
194203
else
195204
NEW_SSM_VALUE=$(echo ${NEW_SSM_VALUE} | jq -r '.Phase = "Backup Failed"')
196205
fi
197-
info "A: $NEW_SSM_VALUE"
198206
aws ssm put-parameter --name "${SSM_PARAMETER}" --type String --overwrite --value "${NEW_SSM_VALUE}" 1>&2
199207
}
200208

@@ -739,6 +747,21 @@ info "Trace File = $TRACE_FILE"
739747
info "Archivelog Range = $ARCHIVELOGS"
740748
info "Specific Datafiles = $DATAFILES"
741749

750+
if [[ ! -z "$REPOSITORY_DISPATCH" ]]; then
751+
REPOSITORY_DISPATCH="https://api.github.com/repos/${REPOSITORY_DISPATCH}/dispatches"
752+
info "GitHub Actions Repository Dispatch Events will be sent to : $REPOSITORY_DISPATCH"
753+
fi
754+
755+
if [[ ! -z "$JSON_INPUTS" ]]; then
756+
# The JSON Inputs are used to record the parameters originally passed to GitHub
757+
# actions to start the backup job. These are only used for actioning a repository
758+
# dispatch event to indicate the end of the backup job run. They do NOT
759+
# override the command line options passed to the script.
760+
JSON_INPUTS=$(echo $JSON_INPUTS | base64 --decode )
761+
elif [[ ! -z "$REPOSITORY_DISPATCH" ]]; then
762+
error "JSON inputs must be supplied using the -j option if Repository Dispatch Events are requested."
763+
fi
764+
742765
validate user
743766
info "Execute $THISUSER bash profile"
744767
. $HOME/.bash_profile
@@ -784,23 +807,6 @@ if [[ ! -z "$SSM_PARAMETER" ]]; then
784807
update_ssm_parameter "Running" "Running: $0 $*"
785808
fi
786809

787-
if [[ ! -z "$REPOSITORY_DISPATCH" ]]; then
788-
REPOSITORY_DISPATCH="https://api.github.com/repos/${REPOSITORY_DISPATCH}/dispatches"
789-
info "GitHub Actions Repository Dispatch Events will be sent to : $REPOSITORY_DISPATCH"
790-
fi
791-
792-
if [[ ! -z "$JSON_INPUTS" ]]; then
793-
# The JSON Inputs are used to record the parameters originally passed to GitHub
794-
# actions to start the backup job. These are only used for actioning a repository
795-
# dispatch event to indicate the end of the backup job run. They do NOT
796-
# override the command line options passed to the script.
797-
JSON_INPUTS=$(echo $JSON_INPUTS | base64 --decode )
798-
info "Original JSON Inputs to GitHub Action: $JSON_INPUTS"
799-
elif [[ ! -z "$REPOSITORY_DISPATCH" ]]; then
800-
error "JSON inputs must be supplied using the -j option if Repository Dispatch Events are requested."
801-
fi
802-
803-
touch $RMANCMDFILE
804810
info "Create rman tags and format"
805811
create_tag_format
806812
info "Generating rman command file"

0 commit comments

Comments
 (0)